Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Complete app's logic #1

Merged
merged 23 commits into from
Oct 16, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
e655dd3
Create basic components with state and its handlers, configure eslint
Fafruch Oct 8, 2017
35a48c4
Add bootstrap dependency and basic functionality
Fafruch Oct 8, 2017
f00dcb0
End component has now conditional render
Fafruch Oct 9, 2017
fe61973
Add comments in endAfter form
Fafruch Oct 9, 2017
4980a5f
Remove unnecessary <form> tags from End
Fafruch Oct 9, 2017
342043e
Generating ending rrule works, add rrule.js & moment.js dependencies
Fafruch Oct 10, 2017
dae53d1
Add html representation in Repeat
Fafruch Oct 10, 2017
cb3f538
Repeat component and its children is finished (despite CSS), add lodash
Fafruch Oct 11, 2017
5998bfa
Converting to rrule works for all options, small fixes in components
Fafruch Oct 11, 2017
6cc8f31
Split End component
Fafruch Oct 11, 2017
5741ac1
Fix mapping in RepeatWeekly
Fafruch Oct 11, 2017
8eef2b4
Rebuilt app's state and its handleChange
Fafruch Oct 14, 2017
d3401ea
Make computeRRule handle new data
Fafruch Oct 14, 2017
f2f5205
Change app's structure and on/onThe state's structure
Fafruch Oct 14, 2017
7b2b5cb
Split computeRRule function's logic
Fafruch Oct 14, 2017
346c577
Remove unnecessary spreads from editedEvent objects
Fafruch Oct 14, 2017
a71aecd
Add react-copy-to-clipboard dependency
Fafruch Oct 14, 2017
5f68ea9
Change 'frequency' name to 'interval' to match RRule's name
Fafruch Oct 14, 2017
e72dc8a
Fix after review
Fafruch Oct 15, 2017
a1bc1a9
Fix after review continued
Fafruch Oct 15, 2017
b38f036
Fix handleChange and simplify rrule yearly / bymonth
Fafruch Oct 15, 2017
44925fa
Remove App.css, update package.json
Fafruch Oct 16, 2017
5fb221d
Remove obsolete divs in App
Fafruch Oct 16, 2017
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .eslintrc
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"parser": "babel-eslint",
"extends": [
"standard",
"standard-react",
Expand All @@ -8,6 +9,8 @@
"react"
],
"rules": {
"react/jsx-filename-extension": [1, { "extensions": [".js", ".jsx"] }]
"react/jsx-filename-extension": [1, { "extensions": [".js", ".jsx"] }],
"no-trailing-spaces": ["error", { "skipBlankLines": true }],
"max-len": [2, 120, 2]
}
}
15 changes: 13 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,12 +1,23 @@
{
"name": "react-rrule-generator",
"version": "0.1.0",
"private": true,
"author": "Filip Duczyminski <fduczyminski@gmail.com>",
"repository": {
"type": "git",
"url": "git+https://github.com/Fafruch/react-rrule-generator.git"
},
"license": "MIT",
"dependencies": {
"bootstrap": "^4.0.0-beta",
"lodash": "^4.17.4",
"moment": "^2.18.1",
"prop-types": "^15.6.0",
"react": "^16.0.0",
"react-copy-to-clipboard": "^5.0.1",
"react-datetime": "^2.10.3",
"react-dom": "^16.0.0",
"react-scripts": "1.0.14"
"react-scripts": "1.0.14",
"rrule": "^2.2.0"
},
"devDependencies": {
"eslint": "^4.8.0",
Expand Down
15 changes: 4 additions & 11 deletions src/App.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,8 @@
import React from 'react';
import './styles/App.css';

const App = () => (
<div className="App">
<header className="App-header">
<h1 className="App-title">Rrule generator</h1>
</header>
<p className="App-intro">
To get started, edit <code>src/App.js</code> and save to reload.
</p>
</div>
);
import './styles/index.css';
import AppContainer from './components/AppContainer';

const App = () => <AppContainer />;

export default App;
102 changes: 102 additions & 0 deletions src/components/AppContainer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import React, { Component } from 'react';
import { cloneDeep, set } from 'lodash';
import moment from 'moment';

import Repeat from './Repeat/index';
import End from './End/index';
import RRule from './RRule/index';
import computeRRule from '../utils/computeRRule';
import { DATE_TIME_FORMAT } from '../constants/index';

class AppContainer extends Component {
state = {
data: {
repeat: {
frequency: 'Yearly',
yearly: {
mode: 'on',
on: {
month: 'Jan',
day: 1,
},
onThe: {
month: 'Jan',
day: 'Monday',
which: 'First',
},
},
monthly: {
mode: 'on',
interval: 1,
on: {
day: 1,
},
onThe: {
day: 'Monday',
which: 'First',
},
},
weekly: {
interval: 1,
days: {
mon: false,
tue: false,
wed: false,
thu: false,
fri: false,
sat: false,
sun: false,
},
},
daily: {
interval: 1,
},
hourly: {
interval: 1,
},
},
end: {
mode: 'Never',
after: 1,
onDate: moment().format(DATE_TIME_FORMAT),
},
},
isCopied: false,
};

handleChange = ({ target }) => {
this.setState((currentState) => {
const newData = cloneDeep(currentState.data);
set(newData, target.name, target.value);
return { data: newData, isCopied: false };
});
}

handleCopy = () => this.setState({ isCopied: true });

render() {
return (
<div className="container m-5">

<Repeat
repeat={this.state.data.repeat}
handleChange={this.handleChange}
/>

<End
end={this.state.data.end}
handleChange={this.handleChange}
/>

<RRule
rrule={computeRRule(this.state.data)}
isCopied={this.state.isCopied}
handleCopy={this.handleCopy}
/>

</div>
);
}
}

export default AppContainer;
25 changes: 25 additions & 0 deletions src/components/End/After.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import React from 'react';
import PropTypes from 'prop-types';
import numericalFieldHandler from '../../utils/numericalFieldHandler';

const EndAfter = ({
after,
handleChange,
}) => (
<div>
<input
name="end.after"
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about using type="number"?
This changes the way this input is rendering, but then you do not need to check isNaN (however still need to transform string to number)

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

type="number" adds its own "up/down" button to incrementing and decrementing value. I didn't ever like it so I avoided it there

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok 👍

className="form-control"
value={after}
onChange={numericalFieldHandler(handleChange)}
/>
executions.
</div>
);

EndAfter.propTypes = {
after: PropTypes.number.isRequired,
handleChange: PropTypes.func.isRequired,
};

export default EndAfter;
33 changes: 33 additions & 0 deletions src/components/End/OnDate.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import React from 'react';
import PropTypes from 'prop-types';
import moment from 'moment';
import DateTime from 'react-datetime';

import { DATE_TIME_FORMAT } from '../../constants/index';

const EndOnDate = ({
onDate,
handleChange,
}) => (
<DateTime
inputProps={{ name: 'end.onDate' }}
value={onDate}
dateFormat={DATE_TIME_FORMAT}
timeFormat={false}
viewMode="days"
closeOnSelect
closeOnTab
required
onChange={(inputDate) => {
const editedEvent = { target: { value: moment(inputDate).format(DATE_TIME_FORMAT), name: 'end.onDate' } };
handleChange(editedEvent);
}}
/>
);

EndOnDate.propTypes = {
onDate: PropTypes.string.isRequired,
handleChange: PropTypes.func.isRequired,
};

export default EndOnDate;
42 changes: 42 additions & 0 deletions src/components/End/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import React from 'react';
import PropTypes from 'prop-types';
import EndAfter from './After';
import EndOnDate from './OnDate';

const End = ({
end: {
mode,
after,
onDate,
},
handleChange,
}) => (
<div>
<h2>End</h2>
<select
name="end.mode"
className="form-control"
value={mode}
onChange={event => handleChange(event)}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

obsolete fat arrow function
onChange={handleChange}

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point

>
<option value="Never">Never</option>
<option value="After">After</option>
<option value="On date">On date</option>
</select>

{mode === 'After' && <EndAfter after={after} handleChange={handleChange} />}
{mode === 'On date' && <EndOnDate onDate={onDate} handleChange={handleChange} />}

</div>
);

End.propTypes = {
end: PropTypes.shape({
mode: PropTypes.string.isRequired,
after: PropTypes.number.isRequired,
onDate: PropTypes.string.isRequired,
}).isRequired,
handleChange: PropTypes.func.isRequired,
};

export default End;
30 changes: 30 additions & 0 deletions src/components/RRule/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import React from 'react';
import PropTypes from 'prop-types';
import CopyToClipboard from 'react-copy-to-clipboard';

const RRule = ({ rrule, isCopied, handleCopy }) => (
<div>
<div className="m-5">
Your RRule is: <code>{rrule}</code>
</div>
<CopyToClipboard
text={rrule}
onCopy={handleCopy}
>
<button
className={isCopied ? 'btn btn-secondary' : 'btn btn-primary'}
onClick={handleCopy}
>
{isCopied ? 'Copied' : 'Copy'}
</button>
</CopyToClipboard>
</div>
);

RRule.propTypes = {
rrule: PropTypes.string.isRequired,
isCopied: PropTypes.bool.isRequired,
handleCopy: PropTypes.func.isRequired,
};

export default RRule;
30 changes: 30 additions & 0 deletions src/components/Repeat/Daily/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import React from 'react';
import PropTypes from 'prop-types';
import numericalFieldHandler from '../../../utils/numericalFieldHandler';

const RepeatDaily = ({
daily: {
interval,
},
handleChange,
}) => (
<div>
every
<input
name="repeat.daily.interval"
className="form-control"
value={interval}
onChange={numericalFieldHandler(handleChange)}
/>
day(s)

</div>
);
RepeatDaily.propTypes = {
daily: PropTypes.shape({
interval: PropTypes.number.isRequired,
}).isRequired,
handleChange: PropTypes.func.isRequired,
};

export default RepeatDaily;
30 changes: 30 additions & 0 deletions src/components/Repeat/Hourly/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import React from 'react';
import PropTypes from 'prop-types';
import numericalFieldHandler from '../../../utils/numericalFieldHandler';

const RepeatHourly = ({
hourly: {
interval,
},
handleChange,
}) => (
<div>
every
<input
name="repeat.hourly.interval"
className="form-control"
value={interval}
onChange={numericalFieldHandler(handleChange)}
/>
day(s)

</div>
);
RepeatHourly.propTypes = {
hourly: PropTypes.shape({
interval: PropTypes.number.isRequired,
}).isRequired,
handleChange: PropTypes.func.isRequired,
};

export default RepeatHourly;
Loading