diff --git a/README.md b/README.md old mode 100644 new mode 100755 diff --git a/package.json b/package.json old mode 100644 new mode 100755 diff --git a/public/favicon.ico b/public/favicon.ico old mode 100644 new mode 100755 diff --git a/public/index.html b/public/index.html old mode 100644 new mode 100755 diff --git a/public/manifest.json b/public/manifest.json old mode 100644 new mode 100755 diff --git a/src/App.js b/src/App.js old mode 100644 new mode 100755 diff --git a/src/components/Root.js b/src/components/Root.js old mode 100644 new mode 100755 index 47ad271..7fa11e4 --- a/src/components/Root.js +++ b/src/components/Root.js @@ -2,7 +2,7 @@ import React, { Component } from 'react' import {Route} from 'react-router-dom' import AdminPage from './routes/AdminPage' import AuthPage from './routes/AuthPage' -import PersonPage from './routes/PersonPage' +import People from './people/People' import ProtectedRoute from './common/ProtectedRoute' class Root extends Component { @@ -14,8 +14,8 @@ class Root extends Component { return (
- +
) } diff --git a/src/components/auth/SignInForm.js b/src/components/auth/SignInForm.js old mode 100644 new mode 100755 diff --git a/src/components/auth/SignUpForm.js b/src/components/auth/SignUpForm.js old mode 100644 new mode 100755 diff --git a/src/components/common/ErrorField.js b/src/components/common/ErrorField.js old mode 100644 new mode 100755 diff --git a/src/components/common/Loader.js b/src/components/common/Loader.js old mode 100644 new mode 100755 diff --git a/src/components/common/ProtectedRoute.js b/src/components/common/ProtectedRoute.js old mode 100644 new mode 100755 diff --git a/src/components/common/UnAuthorized.js b/src/components/common/UnAuthorized.js old mode 100644 new mode 100755 diff --git a/src/components/people/NewPersonForm.js b/src/components/people/NewPersonForm.js deleted file mode 100644 index 2bfed0b..0000000 --- a/src/components/people/NewPersonForm.js +++ /dev/null @@ -1,40 +0,0 @@ -import React, { Component } from 'react' -import {reduxForm, Field} from 'redux-form' -import validateEmail from 'email-validator' -import ErrorField from '../common/ErrorField' - -class NewPersonForm extends Component { - static propTypes = { - - }; - - render() { - return ( -
-
- - - -
- -
- -
- ) - } -} - -function validate({firstName, email}) { - const errors = {} - if (!firstName) errors.firstName = 'first name is required' - - if (!email) errors.email = 'email is required' - else if (!validateEmail.validate(email)) errors.email = 'email is invalid' - - return errors -} - -export default reduxForm({ - form: 'person', - validate -})(NewPersonForm) \ No newline at end of file diff --git a/src/components/people/People.js b/src/components/people/People.js new file mode 100644 index 0000000..a6e0aa2 --- /dev/null +++ b/src/components/people/People.js @@ -0,0 +1,42 @@ +import React, { Component, PropTypes } from 'react' +import {NavLink} from 'react-router-dom' +import {connect} from 'react-redux' +import Loader from '../common/Loader' +import {addPerson, moduleName} from '../../ducks/people' +import PeopleTable from './PeopleTable' +import PeopleForm from './PeopleForm' + + +class PeoplePage extends Component { + handleAddPerson = ({firstName, lastName, email}) => this.props.addPerson(firstName, lastName, email) + + static propTypes = { + peopleList: PropTypes.array.isRequired + } + + render() { + const {loading, peopleList} = this.props + + const table = (peopleList.length > 0) ? : null + + return ( +
+

Add people + Log out +

+ {table} + + {loading && } +
+ ) + } +} + + +export default connect(state => ({ + loading: state[moduleName].loading, + peopleList: state[moduleName].peopleList.toJS() +}), {addPerson})(PeoplePage) \ No newline at end of file diff --git a/src/components/people/PeopleForm.js b/src/components/people/PeopleForm.js new file mode 100644 index 0000000..8fac9a6 --- /dev/null +++ b/src/components/people/PeopleForm.js @@ -0,0 +1,51 @@ +import React from 'react' +import {reduxForm, Field} from 'redux-form' +import emailValidator from 'email-validator' +import ErrorField from '../common/ErrorField' + +let people + +const PeopleForm = ({handleSubmit, peopleList}) => { + + people = peopleList + + return ( +
+
+ + + +
+ +
+ +
+ ) +} + + +const validate = ({firstName, lastName, email}) => { + const errors = {} + + if (!firstName) errors.firstName = 'First name is required' + + if (!lastName) errors.lastName = 'Last name is required' + + if (!email) errors.email = 'Email is required' + else if (!emailValidator.validate(email)) errors.email = 'Invalid email' + else if (checkRepeatEmail(email)) errors.email = 'User with this email already exists' + + return errors +} + +const checkRepeatEmail = (email) => { + let result = false + people.map((el) => { if (el.email === email) result = true }) + return result +} + + +export default reduxForm({ + form: 'people', + validate +})(PeopleForm) \ No newline at end of file diff --git a/src/components/people/PeopleTable.js b/src/components/people/PeopleTable.js new file mode 100644 index 0000000..6193698 --- /dev/null +++ b/src/components/people/PeopleTable.js @@ -0,0 +1,36 @@ +import React, { PropTypes } from 'react' + +const PeopleTable = ({peopleList}) => +
+ + + + + + + + + + { peopleList.map((el, index) => ) } + +
First NameLast NameE-mail
+
+ + +const PeopleTableRow = ({person: {firstName, lastName, email}}) => + + {firstName} + {lastName} + {email} + + + +PeopleTableRow.propTypes = { + person: PropTypes.shape({ + firstName: PropTypes.string.isRequired, + lastName: PropTypes.string.isRequired, + email: PropTypes.string.isRequired + }).isRequired +} + +export default PeopleTable diff --git a/src/components/routes/AdminPage.js b/src/components/routes/AdminPage.js old mode 100644 new mode 100755 diff --git a/src/components/routes/AuthPage.js b/src/components/routes/AuthPage.js old mode 100644 new mode 100755 diff --git a/src/components/routes/PersonPage.js b/src/components/routes/PersonPage.js deleted file mode 100644 index fd69263..0000000 --- a/src/components/routes/PersonPage.js +++ /dev/null @@ -1,21 +0,0 @@ -import React, { Component } from 'react' -import {connect} from 'react-redux' -import {addPerson} from '../../ducks/people' -import NewPersonForm from '../people/NewPersonForm' - -class PersonPage extends Component { - static propTypes = { - - }; - - render() { - return ( -
-

Add new person

- -
- ) - } -} - -export default connect(null, {addPerson})(PersonPage) \ No newline at end of file diff --git a/src/config.js b/src/config.js old mode 100644 new mode 100755 diff --git a/src/ducks/auth.js b/src/ducks/auth.js old mode 100644 new mode 100755 diff --git a/src/ducks/people.js b/src/ducks/people.js index 87a5548..ca2163f 100644 --- a/src/ducks/people.js +++ b/src/ducks/people.js @@ -1,41 +1,61 @@ import {appName} from '../config' -import {Record, List} from 'immutable' +import {List, Record} from 'immutable' +import {reset} from 'redux-form' -const ReducerState = Record({ - entities: new List([]) +const PeopleListRecord = Record({ + peopleList: List(), + error: null, + loading: false }) const PersonRecord = Record({ - id: null, - firstName: null, - lastName: null, - email: null + id: null, + firstName: null, + lastName: null, + email: null }) export const moduleName = 'people' -const prefix = `${appName}/${moduleName}` -export const ADD_PERSON = `${prefix}/ADD_PERSON` - - -export default function reducer(state = new ReducerState(), action) { - const {type, payload} = action - - switch (type) { - case ADD_PERSON: - return state.update('entities', entities => entities.push(new PersonRecord(payload.person))) - - default: - return state - } +export const ADD_PERSON_REQUEST = `${appName}/${moduleName}/ADD_PERSON_REQUEST` +export const ADD_PERSON_SUCCESS = `${appName}/${moduleName}/ADD_PERSON_SUCCESS` +export const ADD_PERSON_ERROR = `${appName}/${moduleName}/ADD_PERSON_ERROR` + + +export default function reducer(state = new PeopleListRecord(), action) { + const {type, payload, error} = action + + switch (type) { + case ADD_PERSON_REQUEST: + return state.set('loading', true) + + case ADD_PERSON_SUCCESS: + return state + .set('loading', false) + .set('error', null) + .setIn(['peopleList', state.get('peopleList').size], new PersonRecord({ + id: state.get('peopleList').size, + firstName: payload.firstName, + lastName: payload.lastName, + email: payload.email + })) + + case ADD_PERSON_ERROR: + return state + .set('loading', false) + .set('error', error) + + default: + return state + } } -export function addPerson(person) { - return (dispatch) => { - dispatch({ - type: ADD_PERSON, - payload: { - person: {id: Date.now(), ...person} - } - }) - } -} \ No newline at end of file +export function addPerson(firstName, lastName, email) { + return (dispatch) => { + dispatch({ + type: ADD_PERSON_SUCCESS, + payload: {firstName, lastName, email} + }) + // Dispatching this to reset redux-form + dispatch(reset('people')) + } +} diff --git a/src/history.js b/src/history.js old mode 100644 new mode 100755 diff --git a/src/index.css b/src/index.css old mode 100644 new mode 100755 diff --git a/src/index.js b/src/index.js old mode 100644 new mode 100755 diff --git a/src/redux/index.js b/src/redux/index.js old mode 100644 new mode 100755 index b45bb34..72be007 --- a/src/redux/index.js +++ b/src/redux/index.js @@ -1,4 +1,4 @@ -import {createStore, applyMiddleware} from 'redux' +import {createStore, applyMiddleware, compose} from 'redux' import reducer from './reducer' import logger from 'redux-logger' import thunk from 'redux-thunk' @@ -7,7 +7,12 @@ import history from '../history' const enhancer = applyMiddleware(routerMiddleware(history), thunk, logger) -const store = createStore(reducer, enhancer) +const store = createStore(reducer, compose( + enhancer, + window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__() + ) +) + window.store = store export default store diff --git a/src/redux/reducer.js b/src/redux/reducer.js old mode 100644 new mode 100755 diff --git a/src/registerServiceWorker.js b/src/registerServiceWorker.js old mode 100644 new mode 100755 diff --git a/yarn.lock b/yarn.lock old mode 100644 new mode 100755