From 2ef2124dc32edb8df3cce003f46bc323b05978b2 Mon Sep 17 00:00:00 2001 From: Panchenko Svetlana Date: Sun, 10 Dec 2017 02:24:12 +0400 Subject: [PATCH 01/11] Home task 1: --- Configure firebase(auth+db) --- Adding user to db --- Show errors and loaders in forms --- admin-panel/package.json | 3 +- admin-panel/src/App.js | 2 +- admin-panel/src/components/routes/Admin.js | 17 ---- .../src/components/routes/admin/index.js | 41 ++++++++++ .../src/components/routes/auth/index.js | 28 ++++++- admin-panel/src/components/user/UserForm.js | 46 +++++++++++ admin-panel/src/config.js | 6 +- admin-panel/src/ducks/auth.js | 11 +++ admin-panel/src/ducks/user.js | 75 ++++++++++++++++++ admin-panel/src/redux/reducer.js | 4 +- admin-panel/src/static/preloader-xs.png | Bin 0 -> 1246 bytes admin-panel/yarn.lock | 57 ++++++++++++- 12 files changed, 264 insertions(+), 26 deletions(-) delete mode 100644 admin-panel/src/components/routes/Admin.js create mode 100644 admin-panel/src/components/routes/admin/index.js create mode 100644 admin-panel/src/components/user/UserForm.js create mode 100644 admin-panel/src/ducks/user.js create mode 100644 admin-panel/src/static/preloader-xs.png diff --git a/admin-panel/package.json b/admin-panel/package.json index 5fbeba9..bb1cbe5 100644 --- a/admin-panel/package.json +++ b/admin-panel/package.json @@ -18,7 +18,8 @@ "redux-form": "^7.2.0", "redux-logger": "^3.0.6", "redux-thunk": "^2.2.0", - "reselect": "^3.0.1" + "reselect": "^3.0.1", + "styled-components": "^2.2.4" }, "scripts": { "start": "react-scripts start", diff --git a/admin-panel/src/App.js b/admin-panel/src/App.js index fd110f7..b02dd0a 100644 --- a/admin-panel/src/App.js +++ b/admin-panel/src/App.js @@ -1,7 +1,7 @@ import React, { Component } from 'react' import {Route} from 'react-router-dom' import Auth from './components/routes/auth' -import Admin from './components/routes/Admin' +import Admin from './components/routes/admin/' import ProtectedRoute from './components/common/ProtectedRoute' class App extends Component { diff --git a/admin-panel/src/components/routes/Admin.js b/admin-panel/src/components/routes/Admin.js deleted file mode 100644 index 952248e..0000000 --- a/admin-panel/src/components/routes/Admin.js +++ /dev/null @@ -1,17 +0,0 @@ -import React, { Component } from 'react' - -class Admin extends Component { - static propTypes = { - - }; - - render() { - return ( -
-

Admin Page

-
- ) - } -} - -export default Admin \ No newline at end of file diff --git a/admin-panel/src/components/routes/admin/index.js b/admin-panel/src/components/routes/admin/index.js new file mode 100644 index 0000000..eb188ea --- /dev/null +++ b/admin-panel/src/components/routes/admin/index.js @@ -0,0 +1,41 @@ +import React, { Component } from 'react' +import {Route, NavLink} from 'react-router-dom' +import {connect} from 'react-redux' + +import UserForm from './../../user/UserForm' +import {addUser,userErrorSelector,userLoaderSelector} from '../../../ducks/user' + +class Admin extends Component { + static propTypes = { + + }; + + render() { + const {loading, error} = this.props; + return ( +
+

Admin Page

+ + } /> + {error !== null && +

{error}

+ } + {/*loading && + + */} + {loading && +
Loading...
+ } +
+ ) + } + + addUser = ({ firstName,lastName, email }) => this.props.addUser(firstName, lastName, email) +} + +export default connect(state => ({ + error: userErrorSelector(state), + loading: userLoaderSelector(state) +}), { addUser})(Admin) \ No newline at end of file diff --git a/admin-panel/src/components/routes/auth/index.js b/admin-panel/src/components/routes/auth/index.js index 91c9bab..d5b6163 100644 --- a/admin-panel/src/components/routes/auth/index.js +++ b/admin-panel/src/components/routes/auth/index.js @@ -1,9 +1,20 @@ import React, { Component } from 'react' import {Route, NavLink} from 'react-router-dom' import {connect} from 'react-redux' -import {signIn, signUp} from '../../../ducks/auth' + +//import styled from 'styled-components'; + +import {signIn, signUp, userErrorSelector, userLoaderSelector} from '../../../ducks/auth' import SignInForm from '../../auth/SignInForm' import SignUpForm from '../../auth/SignUpForm' +//import spinner from '../../../static/preloader-xs.png'; + +//const LoaderIcon = styled.div` +// width: 166px; +// height: 166px; +// background: url(spinner); +// animation: rotate 2s linear infinite; +//`; class Auth extends Component { static propTypes = { @@ -11,6 +22,7 @@ class Auth extends Component { }; render() { + const {loading, error} = this.props; return (

Auth page

@@ -20,6 +32,15 @@ class Auth extends Component { } /> } /> + {error !== null && +

{error}

+ } + {/*loading && + + */} + {loading && +
Loading...
+ }
) } @@ -29,4 +50,7 @@ class Auth extends Component { } -export default connect(null, { signIn, signUp })(Auth) \ No newline at end of file +export default connect(state => ({ + error: userErrorSelector(state), + loading: userLoaderSelector(state) +}), { signIn, signUp })(Auth) \ No newline at end of file diff --git a/admin-panel/src/components/user/UserForm.js b/admin-panel/src/components/user/UserForm.js new file mode 100644 index 0000000..36541c8 --- /dev/null +++ b/admin-panel/src/components/user/UserForm.js @@ -0,0 +1,46 @@ +import React, { Component } from 'react' +import {reduxForm, Field} from 'redux-form' +import validator from 'email-validator' + +import ErrorField from '../common/ErrorField' + +class UserForm extends Component { + static propTypes = { + + }; + + render() { + const {mode} = this.props; + return ( +
+

{mode === 'add' ? 'Add user' : 'Edit User' }

+
+
+ First name: +
+
+ Last name: +
+
+ email: +
+ +
+ +
+ ) + } +} +const validate = ({ email }) => { + const errors = {} + + if (!email) errors.email = 'email is a required field' + if (email && !validator.validate(email)) errors.email = 'incorrect email format' + + return errors +} + +export default reduxForm({ + form: 'user', + validate +})(UserForm) \ No newline at end of file diff --git a/admin-panel/src/config.js b/admin-panel/src/config.js index 65bba00..a429471 100644 --- a/admin-panel/src/config.js +++ b/admin-panel/src/config.js @@ -1,14 +1,14 @@ import firebase from 'firebase' -export const appName = 'advreact-04-12' +export const appName = 'advreact-04-12-vesna' const config = { - apiKey: "AIzaSyCmDWlgYIhtEr1pWjgKYds3iXKWBl9wbjE", + apiKey: "AIzaSyAkBB770P-MOKox9k6DjFRKi9J-bIoMnJs", authDomain: `${appName}.firebaseapp.com`, databaseURL: `https://${appName}.firebaseio.com`, projectId: appName, storageBucket: "", - messagingSenderId: "95255462276" + messagingSenderId: "786443944884" } firebase.initializeApp(config) \ No newline at end of file diff --git a/admin-panel/src/ducks/auth.js b/admin-panel/src/ducks/auth.js index f031871..b4475e0 100644 --- a/admin-panel/src/ducks/auth.js +++ b/admin-panel/src/ducks/auth.js @@ -10,6 +10,7 @@ const prefix = `${appName}/${moduleName}` export const SIGN_IN_START = `${prefix}/SIGN_IN_START` export const SIGN_IN_SUCCESS = `${prefix}/SIGN_IN_SUCCESS` +export const SIGN_IN_FAIL = `${prefix}/SIGN_IN_FAIL` export const SIGN_UP_START = `${prefix}/SIGN_UP_START` export const SIGN_UP_SUCCESS = `${prefix}/SIGN_UP_SUCCESS` @@ -35,6 +36,10 @@ export default function reducer(state = new ReducerRecord(), action) { return state .set('loading', false) .set('user', payload.user) + case SIGN_IN_FAIL: + return state + .set('loading', false) + .set('error', payload.error.message) default: return state } @@ -45,6 +50,8 @@ export default function reducer(state = new ReducerRecord(), action) { * */ export const userSelector = state => state[moduleName].user +export const userLoaderSelector = state => state[moduleName].loading +export const userErrorSelector = state => state[moduleName].error /** * Action Creators @@ -61,6 +68,10 @@ export function signIn(email, password) { type: SIGN_IN_SUCCESS, payload: { user } })) + .catch(error => dispatch({ + type: SIGN_IN_FAIL, + payload: { error } + })) } } diff --git a/admin-panel/src/ducks/user.js b/admin-panel/src/ducks/user.js new file mode 100644 index 0000000..675a121 --- /dev/null +++ b/admin-panel/src/ducks/user.js @@ -0,0 +1,75 @@ +import {appName} from '../config' +import {Record} from 'immutable' +import firebase from 'firebase' + +/** + * Constants + * */ +export const moduleName = 'user' +const prefix = `${appName}/${moduleName}` + +export const ADD_USER_START = `${prefix}/ADD_USER_START` +export const ADD_USER_SUCCESS = `${prefix}/ADD_USER_SUCCESS` +export const ADD_USER_FAIL = `${prefix}/ADD_USER_FAIL` + +/** + * Reducer + * */ +export const ReducerRecord = Record({ + //users: null, + loading: false, + error: null +}) + +export default function reducer(state = new ReducerRecord(), action) { + const {type, payload} = action + + switch (type) { + case ADD_USER_START: + return state.set('loading', true) + + case ADD_USER_SUCCESS: + return state + .set('loading', false) + + case ADD_USER_FAIL: + return state + .set('loading', false) + .set('error', payload.error.message) + + default: + return state + } +} + +/** + * Selectors + * */ + +//export const userListSelector = state => state[moduleName].users +export const userLoaderSelector = state => state[moduleName].loading +export const userErrorSelector = state => state[moduleName].error + +/** + * Action Creators + * */ + +export function addUser(firstName, lastName, email) { + return (dispatch) => { + dispatch({ + type: ADD_USER_START + }) + + const db = firebase.database(); + const users = db.ref().child('users'); + + users.push({firstName, lastName, email}) + .then(answer => dispatch({ + type: ADD_USER_SUCCESS + })) + .catch(error => dispatch({ + type: ADD_USER_FAIL, + payload: { error } + })) + } +} diff --git a/admin-panel/src/redux/reducer.js b/admin-panel/src/redux/reducer.js index 34143fe..551e9a1 100644 --- a/admin-panel/src/redux/reducer.js +++ b/admin-panel/src/redux/reducer.js @@ -2,8 +2,10 @@ import {combineReducers} from 'redux' import {routerReducer as router} from 'react-router-redux' import {reducer as form} from 'redux-form' import authReducer, {moduleName as authModule} from '../ducks/auth' +import userReducer, {moduleName as userModule} from '../ducks/user' export default combineReducers({ router, form, - [authModule]: authReducer + [authModule]: authReducer, + [userModule]: userReducer }) \ No newline at end of file diff --git a/admin-panel/src/static/preloader-xs.png b/admin-panel/src/static/preloader-xs.png new file mode 100644 index 0000000000000000000000000000000000000000..5f3c4f7aeac6ac351b60061be0271384c05b5b39 GIT binary patch literal 1246 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`k|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*9U+m^Cs(B1$5BeXNr6bM+EIYV;~{3xK*A7;Nk-3KEmEQ%e+* zQqwc@Y?a>c-mj#PnPRIHZt82`Ti~3Uk?B!Ylp0*+7m{3+ootz+WN)WnQ(*-(AUCxn zQK2F?C$HG5!d3}vt`(3C64qBz04piUwpD^SD#ABF!8yMuRl!uxOgGuU%v{0TQqR!T z+}y-mN5ROz&{W^RSl`${*T~q)#K6kLNC66zfVLH-q*(>IxIyg#@@$ndN=gc>^!3Zj z%k|2Q_413-^$jg8E%gnI^o@*kfhu&1EAvVcD|GXUm0>2hq!uR^WfqiV=I1GZOiWD5 zFD$Tv3bSNU;+l1ennz|zM-B0$V)JVzP|XC=H|jx7ncO3BHWAB;NpiyW)Z+ZoqGVvir744~DzI`cN=+=uFAB-e&w+(vKt_H^esM;Afr7I$IMft0d=ry1 z^FV@{U|qhxR-SpqC5d^-sh%#jN= zAx`t4dQ)(_#R#WfeV}9XLD7p8-7q0w8Uiuli5JL$C;!wuV45!iCho%*Zy7T%F#349 zIEGZ*nlss7+a*w<{k{DE)I(lesSmkNJo5_knzHu%f(?m5`x=iO3)}QTaLU;jdB?z0 zNjn{wFo&VgeCNDe?KhYb5J=(DNEzIYKpDUA>%y<)H8yFx4hz=bI?F% z(}Md#H=KpDkA~%hmvZQuuNSXd8g+G*-9srQ_0+qEy$pFy*9ou)x!Ab){mQyAP2KkP z_xeMHQxl$rA9$WF_+o>)N=5SfyOJzcKjyIT8>I^L9N5j`8gWixMyobwU&7&C2DvNu zhCjUWm|^`}ZNA{Puh+{SG`)$vb85B$pL$w;c$W`r literal 0 HcmV?d00001 diff --git a/admin-panel/yarn.lock b/admin-panel/yarn.lock index c9c597c..ac968f5 100644 --- a/admin-panel/yarn.lock +++ b/admin-panel/yarn.lock @@ -1232,6 +1232,13 @@ buffer@^4.3.0: ieee754 "^1.1.4" isarray "^1.0.0" +buffer@^5.0.3: + version "5.0.8" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.0.8.tgz#84daa52e7cf2fa8ce4195bc5cf0f7809e0930b24" + dependencies: + base64-js "^1.0.2" + ieee754 "^1.1.4" + builtin-modules@^1.0.0, builtin-modules@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" @@ -1679,6 +1686,10 @@ crypto-browserify@^3.11.0: randombytes "^2.0.0" randomfill "^1.0.3" +css-color-keywords@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/css-color-keywords/-/css-color-keywords-1.0.0.tgz#fea2616dc676b2962686b3af8dbdbe180b244e05" + css-color-names@0.0.4: version "0.0.4" resolved "https://registry.yarnpkg.com/css-color-names/-/css-color-names-0.0.4.tgz#808adc2e79cf84738069b646cb20ec27beb629e0" @@ -1719,6 +1730,14 @@ css-selector-tokenizer@^0.7.0: fastparse "^1.1.1" regexpu-core "^1.0.0" +css-to-react-native@^2.0.3: + version "2.0.4" + resolved "https://registry.yarnpkg.com/css-to-react-native/-/css-to-react-native-2.0.4.tgz#cf4cc407558b3474d4ba8be1a2cd3b6ce713101b" + dependencies: + css-color-keywords "^1.0.0" + fbjs "^0.8.5" + postcss-value-parser "^3.3.0" + css-what@2.1: version "2.1.0" resolved "https://registry.yarnpkg.com/css-what/-/css-what-2.1.0.tgz#9467d032c38cfaefb9f2d79501253062f87fa1bd" @@ -2555,7 +2574,7 @@ fb-watchman@^2.0.0: dependencies: bser "^2.0.0" -fbjs@^0.8.16: +fbjs@^0.8.16, fbjs@^0.8.5, fbjs@^0.8.9: version "0.8.16" resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.16.tgz#5e67432f550dc41b572bf55847b8aca64e5337db" dependencies: @@ -3057,6 +3076,10 @@ hoek@4.x.x: version "4.2.0" resolved "https://registry.yarnpkg.com/hoek/-/hoek-4.2.0.tgz#72d9d0754f7fe25ca2d01ad8f8f9a9449a89526d" +hoist-non-react-statics@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-1.2.0.tgz#aa448cf0986d55cc40773b17174b7dd066cb7cfb" + hoist-non-react-statics@^2.2.1, hoist-non-react-statics@^2.3.0, hoist-non-react-statics@^2.3.1: version "2.3.1" resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-2.3.1.tgz#343db84c6018c650778898240135a1420ee22ce0" @@ -3384,6 +3407,10 @@ is-fullwidth-code-point@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" +is-function@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-function/-/is-function-1.0.1.tgz#12cfb98b65b57dd3d193a3121f5f6e2f437602b5" + is-glob@^2.0.0, is-glob@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863" @@ -3436,6 +3463,12 @@ is-plain-obj@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e" +is-plain-object@^2.0.1: + version "2.0.4" + resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" + dependencies: + isobject "^3.0.1" + is-posix-bracket@^0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4" @@ -3520,6 +3553,10 @@ isobject@^2.0.0: dependencies: isarray "1.0.0" +isobject@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" + isomorphic-fetch@^2.1.1: version "2.2.1" resolved "https://registry.yarnpkg.com/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz#611ae1acf14f5e81f729507472819fe9733558a9" @@ -6140,6 +6177,24 @@ style-loader@0.19.0: loader-utils "^1.0.2" schema-utils "^0.3.0" +styled-components@^2.2.4: + version "2.2.4" + resolved "https://registry.yarnpkg.com/styled-components/-/styled-components-2.2.4.tgz#dd87fd3dafd359e7a0d570aec1bd07d691c0b5a2" + dependencies: + buffer "^5.0.3" + css-to-react-native "^2.0.3" + fbjs "^0.8.9" + hoist-non-react-statics "^1.2.0" + is-function "^1.0.1" + is-plain-object "^2.0.1" + prop-types "^15.5.4" + stylis "^3.4.0" + supports-color "^3.2.3" + +stylis@^3.4.0: + version "3.4.5" + resolved "https://registry.yarnpkg.com/stylis/-/stylis-3.4.5.tgz#d7b9595fc18e7b9c8775eca8270a9a1d3e59806e" + supports-color@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" From 0be404e032f6133196e4e114318e6bf7b7a0d967 Mon Sep 17 00:00:00 2001 From: Panchenko Svetlana Date: Wed, 13 Dec 2017 02:41:25 +0400 Subject: [PATCH 02/11] HT2.1 Merge branch 'master' of https://github.com/romabelka/advreact_04_12 # Conflicts: # admin-panel/src/App.js # admin-panel/src/ducks/auth.js # admin-panel/src/redux/reducer.js --- admin-panel/src/config.js | 1 + admin-panel/src/ducks/auth.test.js | 191 +++++++++++++++++++++++++++++ 2 files changed, 192 insertions(+) create mode 100644 admin-panel/src/ducks/auth.test.js diff --git a/admin-panel/src/config.js b/admin-panel/src/config.js index a429471..8bb4843 100644 --- a/admin-panel/src/config.js +++ b/admin-panel/src/config.js @@ -3,6 +3,7 @@ import firebase from 'firebase' export const appName = 'advreact-04-12-vesna' const config = { + appName: appName, apiKey: "AIzaSyAkBB770P-MOKox9k6DjFRKi9J-bIoMnJs", authDomain: `${appName}.firebaseapp.com`, databaseURL: `https://${appName}.firebaseio.com`, diff --git a/admin-panel/src/ducks/auth.test.js b/admin-panel/src/ducks/auth.test.js new file mode 100644 index 0000000..c89ddb7 --- /dev/null +++ b/admin-panel/src/ducks/auth.test.js @@ -0,0 +1,191 @@ +import {call, put, take} from 'redux-saga/effects' +import { + signInSaga, + SIGN_IN_REQUEST, + SIGN_IN_START, + SIGN_IN_SUCCESS, + SIGN_IN_ERROR, + + signUpSaga, + SIGN_UP_REQUEST, + SIGN_UP_START, + SIGN_UP_SUCCESS, + SIGN_UP_ERROR +} from './auth'; +import firebase from 'firebase' + +describe('auth saga', () => { + + /** + * Sign in tests + */ + + it('should sign in person', () => { + const user = { + password: '123456', + email: 'ivanovasvetlana1991@gmail.com' + } + + const action = { + type: SIGN_IN_REQUEST, + payload: { user } + } + + const generator = signInSaga(action) + + expect(generator.next().value).toEqual(put({ + type: SIGN_IN_START + })) + + const auth = firebase.auth() + + expect(JSON.stringify(generator.next().value)).toEqual(JSON.stringify( + call( + [auth, auth.createUserWithEmailAndPassword], + action.payload.email, + action.payload.password + ) + ) + ) + + expect(generator.next(user).value).toEqual( + put({ + type: SIGN_IN_SUCCESS, + payload: { user } + }) + ) + + expect(generator.next().done).toBe(true) + + }); + + it('should be error in sign in request', () => { + const user = { + password: '1236', + email: 'ivanovasvetlana1991@gmail.com' + } + + const action = { + type: SIGN_IN_REQUEST, + payload: { user } + } + + const generator = signInSaga(action) + + expect(generator.next().value).toEqual(put({ + type: SIGN_IN_START + })) + + const auth = firebase.auth() + + expect(JSON.stringify(generator.next().value)).toEqual(JSON.stringify( + call( + [auth, auth.createUserWithEmailAndPassword], + action.payload.email, + action.payload.password + ) + ) + ) + + const error = new Error('something went wrong') + + expect(generator.throw(error).value).toEqual( + put({ + type: SIGN_IN_ERROR, + payload: { error } + }) + ) + + expect(generator.next().done).toBe(true) + + }); + + /** + * Sign up tests + */ + + it('should sign up person', () => { + const user = { + password: '123456', + email: 'ivanovasvetlana1991@gmail.com' + } + + const action = { + type: SIGN_UP_REQUEST, + payload: { user } + } + + const generator = signUpSaga() + + expect(generator.next().value).toEqual(take(SIGN_UP_REQUEST)) + + expect(generator.next(action).value).toEqual(put({ + type: SIGN_UP_START + })) + + const auth = firebase.auth() + + expect(JSON.stringify(generator.next().value)).toEqual(JSON.stringify( + call( + [auth, auth.createUserWithEmailAndPassword], + action.payload.email, + action.payload.password + ) + ) + ) + + expect(generator.next(user).value).toEqual( + put({ + type: SIGN_UP_SUCCESS, + payload: { user } + }) + ) + + expect(generator.next().value).toEqual(take(SIGN_UP_REQUEST)) + + }); + + it('should throw error in sign up ', () => { + const user = { + password: '123456', + email: 'ivanovasvetlana1991@gmail.com' + } + + const action = { + type: SIGN_UP_REQUEST, + payload: { user } + } + + const generator = signUpSaga() + + expect(generator.next().value).toEqual(take(SIGN_UP_REQUEST)) + + expect(generator.next(action).value).toEqual(put({ + type: SIGN_UP_START + })) + + const auth = firebase.auth() + + expect(JSON.stringify(generator.next().value)).toEqual(JSON.stringify( + call( + [auth, auth.createUserWithEmailAndPassword], + action.payload.email, + action.payload.password + ) + ) + ) + + const error = new Error('something went wrong') + + expect(generator.throw(error).value).toEqual( + put({ + type: SIGN_UP_ERROR, + payload: { error } + }) + ) + + expect(generator.next().value).toEqual(take(SIGN_UP_REQUEST)) + + }); + +}); \ No newline at end of file From f92c6456359b62d78a87190addd5a6ad53833e91 Mon Sep 17 00:00:00 2001 From: Panchenko Svetlana Date: Wed, 13 Dec 2017 03:02:44 +0400 Subject: [PATCH 03/11] HT2.2 --- admin-panel/src/components/App.js | 20 ++++----- admin-panel/src/components/routes/Admin.js | 17 ++++++++ .../src/components/routes/admin/index.js | 41 ------------------- .../src/components/routes/auth/index.js | 6 +-- admin-panel/src/ducks/people.js | 20 ++++++--- 5 files changed, 45 insertions(+), 59 deletions(-) create mode 100644 admin-panel/src/components/routes/Admin.js delete mode 100644 admin-panel/src/components/routes/admin/index.js diff --git a/admin-panel/src/components/App.js b/admin-panel/src/components/App.js index 6abd045..c21919d 100644 --- a/admin-panel/src/components/App.js +++ b/admin-panel/src/components/App.js @@ -12,16 +12,16 @@ class App extends Component { render() { return ( -
-

Hello world

-
    -
  • admin
  • -
  • people
  • -
- - - -
+
+

Hello world

+
    +
  • admin
  • +
  • people
  • +
+ + + +
) } } diff --git a/admin-panel/src/components/routes/Admin.js b/admin-panel/src/components/routes/Admin.js new file mode 100644 index 0000000..b82921e --- /dev/null +++ b/admin-panel/src/components/routes/Admin.js @@ -0,0 +1,17 @@ +import React, { Component } from 'react' + +class Admin extends Component { + static propTypes = { + + }; + + render() { + return ( +
+

Admin Page

+
+ ) + } +} + +export default Admin \ No newline at end of file diff --git a/admin-panel/src/components/routes/admin/index.js b/admin-panel/src/components/routes/admin/index.js deleted file mode 100644 index eb188ea..0000000 --- a/admin-panel/src/components/routes/admin/index.js +++ /dev/null @@ -1,41 +0,0 @@ -import React, { Component } from 'react' -import {Route, NavLink} from 'react-router-dom' -import {connect} from 'react-redux' - -import UserForm from './../../user/UserForm' -import {addUser,userErrorSelector,userLoaderSelector} from '../../../ducks/user' - -class Admin extends Component { - static propTypes = { - - }; - - render() { - const {loading, error} = this.props; - return ( -
-

Admin Page

-
    -
  • Add User
  • -
- } /> - {error !== null && -

{error}

- } - {/*loading && - - */} - {loading && -
Loading...
- } -
- ) - } - - addUser = ({ firstName,lastName, email }) => this.props.addUser(firstName, lastName, email) -} - -export default connect(state => ({ - error: userErrorSelector(state), - loading: userLoaderSelector(state) -}), { addUser})(Admin) \ No newline at end of file diff --git a/admin-panel/src/components/routes/auth/index.js b/admin-panel/src/components/routes/auth/index.js index d5b6163..6c2b285 100644 --- a/admin-panel/src/components/routes/auth/index.js +++ b/admin-panel/src/components/routes/auth/index.js @@ -4,7 +4,7 @@ import {connect} from 'react-redux' //import styled from 'styled-components'; -import {signIn, signUp, userErrorSelector, userLoaderSelector} from '../../../ducks/auth' +import {signIn, signUp, errorSelector, loadingSelector} from '../../../ducks/auth' import SignInForm from '../../auth/SignInForm' import SignUpForm from '../../auth/SignUpForm' //import spinner from '../../../static/preloader-xs.png'; @@ -51,6 +51,6 @@ class Auth extends Component { } export default connect(state => ({ - error: userErrorSelector(state), - loading: userLoaderSelector(state) + error: errorSelector(state), + loading: loadingSelector(state) }), { signIn, signUp })(Auth) \ No newline at end of file diff --git a/admin-panel/src/ducks/people.js b/admin-panel/src/ducks/people.js index 52bce70..979e4e8 100644 --- a/admin-panel/src/ducks/people.js +++ b/admin-panel/src/ducks/people.js @@ -1,6 +1,7 @@ import {appName} from '../config' import {Record, List} from 'immutable' import {put, call, all, takeEvery} from 'redux-saga/effects' +import {reset} from 'redux-form'; import {generateId} from './utils' /** @@ -10,6 +11,7 @@ export const moduleName = 'people' const prefix = `${appName}/${moduleName}` export const ADD_PERSON = `${prefix}/ADD_PERSON` export const ADD_PERSON_SUCCESS = `${prefix}/ADD_PERSON_SUCCESS` +export const ADD_PERSON_ERROR = `${prefix}/ADD_PERSON_ERROR` /** * Reducer @@ -59,12 +61,20 @@ export function addPerson(person) { export const addPersonSaga = function * (action) { const { person } = action.payload - const id = yield call(generateId) + try { + const id = yield call(generateId) - yield put({ - type: ADD_PERSON_SUCCESS, - payload: {id, ...person} - }) + yield put({ + type: ADD_PERSON_SUCCESS, + payload: { id, ...person } + }) + yield put(reset('person')) + }catch(error){ + yield put({ + type: ADD_PERSON_ERROR, + payload: { error } + }) + } } export const saga = function * () { From 90c7511c42ef35a39648d47d501a32bcb6b6a4ea Mon Sep 17 00:00:00 2001 From: Panchenko Svetlana Date: Wed, 13 Dec 2017 03:19:42 +0400 Subject: [PATCH 04/11] HT2.3 --- admin-panel/src/components/people/PeopleList.js | 14 ++++++++++++++ admin-panel/src/components/routes/PersonPage.js | 11 ++++++++--- admin-panel/src/ducks/people.js | 5 ++++- 3 files changed, 26 insertions(+), 4 deletions(-) create mode 100644 admin-panel/src/components/people/PeopleList.js diff --git a/admin-panel/src/components/people/PeopleList.js b/admin-panel/src/components/people/PeopleList.js new file mode 100644 index 0000000..1b5be06 --- /dev/null +++ b/admin-panel/src/components/people/PeopleList.js @@ -0,0 +1,14 @@ +import React, { Component } from 'react' + +export default ({list}) => +
+

People

+
+
Id. Email Имя Фамилия
+ {list.map((p, idx) => ( +
+ {idx}. {p.email} {p.firstName} {p.lastName} +
+ ))} +
+
diff --git a/admin-panel/src/components/routes/PersonPage.js b/admin-panel/src/components/routes/PersonPage.js index fd69263..06ad883 100644 --- a/admin-panel/src/components/routes/PersonPage.js +++ b/admin-panel/src/components/routes/PersonPage.js @@ -1,7 +1,8 @@ import React, { Component } from 'react' import {connect} from 'react-redux' -import {addPerson} from '../../ducks/people' +import {addPerson, peopleSelector} from '../../ducks/people' import NewPersonForm from '../people/NewPersonForm' +import PeopleList from '../people/PeopleList'; class PersonPage extends Component { static propTypes = { @@ -9,13 +10,17 @@ class PersonPage extends Component { }; render() { + const {addPerson, peopleList} = this.props; return (

Add new person

- + +
) } } -export default connect(null, {addPerson})(PersonPage) \ No newline at end of file +export default connect(state => ({ + peopleList: peopleSelector(state) +}), {addPerson})(PersonPage) \ No newline at end of file diff --git a/admin-panel/src/ducks/people.js b/admin-panel/src/ducks/people.js index 979e4e8..f695587 100644 --- a/admin-panel/src/ducks/people.js +++ b/admin-panel/src/ducks/people.js @@ -1,6 +1,7 @@ import {appName} from '../config' import {Record, List} from 'immutable' import {put, call, all, takeEvery} from 'redux-saga/effects' +import {createSelector} from 'reselect' import {reset} from 'redux-form'; import {generateId} from './utils' @@ -32,7 +33,7 @@ export default function reducer(state = new ReducerState(), action) { switch (type) { case ADD_PERSON_SUCCESS: - return state.update('entities', entities => entities.push(new PersonRecord(payload.person))) + return state.update('entities', entities => entities.push(new PersonRecord(payload))) default: return state @@ -42,6 +43,8 @@ export default function reducer(state = new ReducerState(), action) { /** * Selectors * */ +export const stateSelector = state => state[moduleName] +export const peopleSelector = createSelector(stateSelector, state => state.entities.toJS()) /** * Action Creators From 4547c39b5b6851e246866ec20f273893e0456194 Mon Sep 17 00:00:00 2001 From: Panchenko Svetlana Date: Wed, 13 Dec 2017 05:30:02 +0400 Subject: [PATCH 05/11] HT2.4 --- admin-panel/src/components/App.js | 3 + .../src/components/people/PeopleList.js | 2 +- .../src/components/routes/EventsPage.js | 55 ++++++++ .../src/components/routes/auth/index.js | 13 -- admin-panel/src/ducks/event.js | 130 ++++++++++++++++++ admin-panel/src/ducks/people.js | 2 +- admin-panel/src/mocks/index.js | 7 + admin-panel/src/redux/reducer.js | 4 +- admin-panel/src/redux/saga.js | 4 +- admin-panel/src/static/preloader-xs.png | Bin 1246 -> 0 bytes 10 files changed, 203 insertions(+), 17 deletions(-) create mode 100644 admin-panel/src/components/routes/EventsPage.js create mode 100644 admin-panel/src/ducks/event.js delete mode 100644 admin-panel/src/static/preloader-xs.png diff --git a/admin-panel/src/components/App.js b/admin-panel/src/components/App.js index c21919d..75c33d6 100644 --- a/admin-panel/src/components/App.js +++ b/admin-panel/src/components/App.js @@ -4,6 +4,7 @@ import AuthPage from './routes/auth' import AdminPage from './routes/Admin' import ProtectedRoute from './common/ProtectedRoute' import PersonPage from './routes/PersonPage' +import EventsPage from './routes/EventsPage'; class App extends Component { static propTypes = { @@ -17,9 +18,11 @@ class App extends Component {
  • admin
  • people
  • +
  • events
+ ) diff --git a/admin-panel/src/components/people/PeopleList.js b/admin-panel/src/components/people/PeopleList.js index 1b5be06..0a1a4a6 100644 --- a/admin-panel/src/components/people/PeopleList.js +++ b/admin-panel/src/components/people/PeopleList.js @@ -1,4 +1,4 @@ -import React, { Component } from 'react' +import React from 'react' export default ({list}) =>
diff --git a/admin-panel/src/components/routes/EventsPage.js b/admin-panel/src/components/routes/EventsPage.js new file mode 100644 index 0000000..fb461b0 --- /dev/null +++ b/admin-panel/src/components/routes/EventsPage.js @@ -0,0 +1,55 @@ +import React, { Component } from 'react' +import {connect} from 'react-redux' +import {saveEventsToDb, eventsSelector, loaderSelector} from '../../ducks/event' + + +class EventsPage extends Component { + static propTypes = { + + }; + + render() { + const {saveEventsToDb,eventList, loading } = this.props; + return ( +
+

Events Page

+ + +

Events List

+ + + + + + + + + + + + + + {!loading && eventList.map(value => + value.map((prop,key) => + + + + + + + + + ) + )} + {loading && } + +
monthsubmissionDeadlinetitleurlwhenwhere
{prop.month}{prop.submissionDeadline}{prop.title}{prop.url}{prop.when}{prop.where}

Loading...

+
+ ) + } +} + +export default connect(state => ({ + eventList: eventsSelector(state), + loading:loaderSelector(state) +}), {saveEventsToDb})(EventsPage) \ No newline at end of file diff --git a/admin-panel/src/components/routes/auth/index.js b/admin-panel/src/components/routes/auth/index.js index 6c2b285..9114b86 100644 --- a/admin-panel/src/components/routes/auth/index.js +++ b/admin-panel/src/components/routes/auth/index.js @@ -2,19 +2,9 @@ import React, { Component } from 'react' import {Route, NavLink} from 'react-router-dom' import {connect} from 'react-redux' -//import styled from 'styled-components'; - import {signIn, signUp, errorSelector, loadingSelector} from '../../../ducks/auth' import SignInForm from '../../auth/SignInForm' import SignUpForm from '../../auth/SignUpForm' -//import spinner from '../../../static/preloader-xs.png'; - -//const LoaderIcon = styled.div` -// width: 166px; -// height: 166px; -// background: url(spinner); -// animation: rotate 2s linear infinite; -//`; class Auth extends Component { static propTypes = { @@ -35,9 +25,6 @@ class Auth extends Component { {error !== null &&

{error}

} - {/*loading && - - */} {loading &&
Loading...
} diff --git a/admin-panel/src/ducks/event.js b/admin-panel/src/ducks/event.js new file mode 100644 index 0000000..933bbf5 --- /dev/null +++ b/admin-panel/src/ducks/event.js @@ -0,0 +1,130 @@ +import {appName} from '../config' +import {Record, Map,List} from 'immutable' +import {put, call, all, takeEvery} from 'redux-saga/effects' +import {createSelector} from 'reselect' + +import {saveEventsToFB, getEventsFromFB} from '../mocks/index'; + +/** + * Constants + * */ + +export const moduleName = 'event' +const prefix = `${appName}/${moduleName}` + +export const ADD_EVENTS_REQUEST = `${prefix}/ADD_EVENTS_REQUEST` +export const ADD_EVENTS_START = `${prefix}/ADD_EVENTS_START` +export const ADD_EVENTS_SUCCESS = `${prefix}/ADD_EVENTS_SUCCESS` +export const ADD_EVENTS_ERROR = `${prefix}/ADD_EVENTS_ERROR` + +export const GET_EVENTS_REQUEST = `${prefix}/GET_EVENTS_REQUEST` +export const GET_EVENTS_START = `${prefix}/GET_EVENTS_START` +export const GET_EVENTS_SUCCESS = `${prefix}/GET_EVENTS_SUCCESS` +export const GET_EVENTS_ERROR = `${prefix}/GET_EVENTS_ERROR` + +/** + * Reducer + * */ +const ReducerState = Record({ + entities: new List([]), + loading: false, + error: null +}) + + +export default function reducer(state = new ReducerState(), action) { + const {type, payload} = action + + switch (type) { + case ADD_EVENTS_START: + return state + .set('error', null) + .set('loading', true) + + case GET_EVENTS_SUCCESS: + return state + .update('entities', entities => entities.push(Object.values(payload.events))) + .set('loading', false) + + case ADD_EVENTS_ERROR: + case GET_EVENTS_ERROR: + return state + .set('loading', false) + .set('error', payload.error.message) + default: + return state + } +} + +/** + * Selectors + * */ +export const stateSelector = state => state[moduleName] +export const eventsSelector = createSelector(stateSelector, state => state.entities) +export const loaderSelector = createSelector(stateSelector, state => state.loading) + +/** + * Action Creators + * */ + +export function saveEventsToDb() { + return { + type: ADD_EVENTS_REQUEST + } +} + +/** + * Sagas + */ + +export const saveEventsSaga = function * (action) { + try { + yield put({ + type: ADD_EVENTS_START + }) + let events = yield call(getEventsFromFB); + + if(events === null){ + events = yield call(saveEventsToFB) + } + + yield put({ + type: ADD_EVENTS_SUCCESS, + payload: { events } + }) + }catch(error){ + yield put({ + type: ADD_EVENTS_ERROR, + payload: { error } + }) + } +} + +export const fetchEventsSaga = function * (action){ + try{ + yield put({ + type: GET_EVENTS_START + }) + const events = yield call(getEventsFromFB) + + yield put({ + type: GET_EVENTS_SUCCESS, + payload: { events } + }) + + } + catch(error){ + yield put({ + type: GET_EVENTS_ERROR, + payload: { error } + }) + } +} + + +export const saga = function * () { + yield all([ + takeEvery(ADD_EVENTS_REQUEST, saveEventsSaga), + takeEvery(ADD_EVENTS_SUCCESS,fetchEventsSaga) + ]) +} \ No newline at end of file diff --git a/admin-panel/src/ducks/people.js b/admin-panel/src/ducks/people.js index f695587..e7063cb 100644 --- a/admin-panel/src/ducks/people.js +++ b/admin-panel/src/ducks/people.js @@ -44,7 +44,7 @@ export default function reducer(state = new ReducerState(), action) { * Selectors * */ export const stateSelector = state => state[moduleName] -export const peopleSelector = createSelector(stateSelector, state => state.entities.toJS()) +export const peopleSelector = createSelector(stateSelector, state => state.entities) /** * Action Creators diff --git a/admin-panel/src/mocks/index.js b/admin-panel/src/mocks/index.js index d1a851f..57c2d98 100644 --- a/admin-panel/src/mocks/index.js +++ b/admin-panel/src/mocks/index.js @@ -6,4 +6,11 @@ export function saveEventsToFB() { conferences.forEach(conference => eventsRef.push(conference)) } +export function getEventsFromFB() { + const db = firebase.database() + const eventsRef = db.ref(`/events`) + return eventsRef.once('value').then(result => result.val() + ); +} + window.saveEventsToFB = saveEventsToFB \ No newline at end of file diff --git a/admin-panel/src/redux/reducer.js b/admin-panel/src/redux/reducer.js index cc6e0aa..0eb750b 100644 --- a/admin-panel/src/redux/reducer.js +++ b/admin-panel/src/redux/reducer.js @@ -3,9 +3,11 @@ import {routerReducer as router} from 'react-router-redux' import {reducer as form} from 'redux-form' import authReducer, {moduleName as authModule} from '../ducks/auth' import peopleReducer, {moduleName as peopleModule} from '../ducks/people' +import eventReducer, {moduleName as eventModule} from '../ducks/event' export default combineReducers({ router, form, [authModule]: authReducer, - [peopleModule]: peopleReducer + [peopleModule]: peopleReducer, + [eventModule]: eventReducer }) \ No newline at end of file diff --git a/admin-panel/src/redux/saga.js b/admin-panel/src/redux/saga.js index 4a6c841..c431ce8 100644 --- a/admin-panel/src/redux/saga.js +++ b/admin-panel/src/redux/saga.js @@ -1,10 +1,12 @@ import {all} from 'redux-saga/effects' import {saga as peopleSaga} from '../ducks/people' import {saga as authSaga} from '../ducks/auth' +import {saga as eventSaga} from '../ducks/event' export default function * rootSaga() { yield all([ peopleSaga(), - authSaga() + authSaga(), + eventSaga() ]) } \ No newline at end of file diff --git a/admin-panel/src/static/preloader-xs.png b/admin-panel/src/static/preloader-xs.png deleted file mode 100644 index 5f3c4f7aeac6ac351b60061be0271384c05b5b39..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1246 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`k|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*9U+m^Cs(B1$5BeXNr6bM+EIYV;~{3xK*A7;Nk-3KEmEQ%e+* zQqwc@Y?a>c-mj#PnPRIHZt82`Ti~3Uk?B!Ylp0*+7m{3+ootz+WN)WnQ(*-(AUCxn zQK2F?C$HG5!d3}vt`(3C64qBz04piUwpD^SD#ABF!8yMuRl!uxOgGuU%v{0TQqR!T z+}y-mN5ROz&{W^RSl`${*T~q)#K6kLNC66zfVLH-q*(>IxIyg#@@$ndN=gc>^!3Zj z%k|2Q_413-^$jg8E%gnI^o@*kfhu&1EAvVcD|GXUm0>2hq!uR^WfqiV=I1GZOiWD5 zFD$Tv3bSNU;+l1ennz|zM-B0$V)JVzP|XC=H|jx7ncO3BHWAB;NpiyW)Z+ZoqGVvir744~DzI`cN=+=uFAB-e&w+(vKt_H^esM;Afr7I$IMft0d=ry1 z^FV@{U|qhxR-SpqC5d^-sh%#jN= zAx`t4dQ)(_#R#WfeV}9XLD7p8-7q0w8Uiuli5JL$C;!wuV45!iCho%*Zy7T%F#349 zIEGZ*nlss7+a*w<{k{DE)I(lesSmkNJo5_knzHu%f(?m5`x=iO3)}QTaLU;jdB?z0 zNjn{wFo&VgeCNDe?KhYb5J=(DNEzIYKpDUA>%y<)H8yFx4hz=bI?F% z(}Md#H=KpDkA~%hmvZQuuNSXd8g+G*-9srQ_0+qEy$pFy*9ou)x!Ab){mQyAP2KkP z_xeMHQxl$rA9$WF_+o>)N=5SfyOJzcKjyIT8>I^L9N5j`8gWixMyobwU&7&C2DvNu zhCjUWm|^`}ZNA{Puh+{SG`)$vb85B$pL$w;c$W`r From 34dacfe8346a02d6c66d3e2ce3dc721e935b38f9 Mon Sep 17 00:00:00 2001 From: Panchenko Svetlana Date: Wed, 13 Dec 2017 05:39:36 +0400 Subject: [PATCH 06/11] HT2.4 --- admin-panel/src/components/App.js | 39 ++++++--------- admin-panel/src/components/routes/Admin.js | 21 ++------- .../src/components/routes/EventsPage.js | 47 +++++++------------ .../src/components/routes/PersonPage.js | 24 ++++------ admin-panel/src/ducks/event.js | 2 +- 5 files changed, 47 insertions(+), 86 deletions(-) diff --git a/admin-panel/src/components/App.js b/admin-panel/src/components/App.js index 75c33d6..d8cc8a3 100644 --- a/admin-panel/src/components/App.js +++ b/admin-panel/src/components/App.js @@ -1,4 +1,4 @@ -import React, { Component } from 'react' +import React from 'react' import {Route, NavLink} from 'react-router-dom' import AuthPage from './routes/auth' import AdminPage from './routes/Admin' @@ -6,27 +6,18 @@ import ProtectedRoute from './common/ProtectedRoute' import PersonPage from './routes/PersonPage' import EventsPage from './routes/EventsPage'; -class App extends Component { - static propTypes = { +const App = () => +
+

Hello world

+
    +
  • admin
  • +
  • people
  • +
  • events
  • +
+ + + + +
- }; - - render() { - return ( -
-

Hello world

-
    -
  • admin
  • -
  • people
  • -
  • events
  • -
- - - - -
- ) - } -} - -export default App \ No newline at end of file +export default App; \ No newline at end of file diff --git a/admin-panel/src/components/routes/Admin.js b/admin-panel/src/components/routes/Admin.js index b82921e..91dbb03 100644 --- a/admin-panel/src/components/routes/Admin.js +++ b/admin-panel/src/components/routes/Admin.js @@ -1,17 +1,6 @@ -import React, { Component } from 'react' +import React from 'react' -class Admin extends Component { - static propTypes = { - - }; - - render() { - return ( -
-

Admin Page

-
- ) - } -} - -export default Admin \ No newline at end of file +export default () => +
+

Admin Page

+
\ No newline at end of file diff --git a/admin-panel/src/components/routes/EventsPage.js b/admin-panel/src/components/routes/EventsPage.js index fb461b0..80e4a3b 100644 --- a/admin-panel/src/components/routes/EventsPage.js +++ b/admin-panel/src/components/routes/EventsPage.js @@ -1,33 +1,25 @@ -import React, { Component } from 'react' +import React from 'react' import {connect} from 'react-redux' import {saveEventsToDb, eventsSelector, loaderSelector} from '../../ducks/event' +const EventsPage = ({saveEventsToDb,eventList, loading }) => +
+

Events Page

+ -class EventsPage extends Component { - static propTypes = { - - }; - - render() { - const {saveEventsToDb,eventList, loading } = this.props; - return ( -
-

Events Page

- - -

Events List

- - - - - - - - - - - - +

Events List

+
monthsubmissionDeadlinetitleurlwhenwhere
+ + + + + + + + + + + {!loading && eventList.map(value => value.map((prop,key) => @@ -45,9 +37,6 @@ class EventsPage extends Component {
monthsubmissionDeadlinetitleurlwhenwhere
- ) - } -} export default connect(state => ({ eventList: eventsSelector(state), diff --git a/admin-panel/src/components/routes/PersonPage.js b/admin-panel/src/components/routes/PersonPage.js index 06ad883..a1708ae 100644 --- a/admin-panel/src/components/routes/PersonPage.js +++ b/admin-panel/src/components/routes/PersonPage.js @@ -1,25 +1,17 @@ -import React, { Component } from 'react' +import React from 'react' import {connect} from 'react-redux' import {addPerson, peopleSelector} from '../../ducks/people' import NewPersonForm from '../people/NewPersonForm' import PeopleList from '../people/PeopleList'; -class PersonPage extends Component { - static propTypes = { +const PersonPage = + ({addPerson, peopleList}) => +
+

Add new person

+ + +
- }; - - render() { - const {addPerson, peopleList} = this.props; - return ( -
-

Add new person

- - -
- ) - } -} export default connect(state => ({ peopleList: peopleSelector(state) diff --git a/admin-panel/src/ducks/event.js b/admin-panel/src/ducks/event.js index 933bbf5..e3e69d7 100644 --- a/admin-panel/src/ducks/event.js +++ b/admin-panel/src/ducks/event.js @@ -1,5 +1,5 @@ import {appName} from '../config' -import {Record, Map,List} from 'immutable' +import {Record, List} from 'immutable' import {put, call, all, takeEvery} from 'redux-saga/effects' import {createSelector} from 'reselect' From c7d562b7e28982860429e65c939f5d6b52de57fa Mon Sep 17 00:00:00 2001 From: Panchenko Svetlana Date: Wed, 20 Dec 2017 04:32:30 +0400 Subject: [PATCH 07/11] =?UTF-8?q?##HT4.2=20=D0=A1=D0=B4=D0=B0=D0=BB=D0=B0?= =?UTF-8?q?=D1=82=D1=8C=20=D0=BA=D0=BE=D1=80=D0=B7=D0=B8=D0=BD=D1=83,=20?= =?UTF-8?q?=D1=83=D0=B4=D0=B0=D0=BB=D1=8F=D1=82=D1=8C=20event=20=D0=BF?= =?UTF-8?q?=D0=B5=D1=80=D0=B5=D1=82=D0=B0=D1=81=D0=BA=D0=B8=D0=B2=D0=B0?= =?UTF-8?q?=D1=8F=20=D0=B5=D0=B3=D0=BE=20=D0=B2=20=D0=BA=D0=BE=D1=80=D0=B7?= =?UTF-8?q?=D0=B8=D0=BD=D1=83=20=D0=B8=D0=B7=20=D1=82=D0=B0=D0=B1=D0=BB?= =?UTF-8?q?=D0=B8=D1=86=D1=8B.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- admin-panel/src/components/events/Bucket.js | 41 ++++++ .../src/components/events/EventDragPreview.js | 21 +++ .../src/components/events/EventsTable.js | 7 +- .../src/components/events/EventsTableRow.js | 96 +++++++++++++ .../components/events/VirtualizedLazyTable.js | 8 ++ admin-panel/src/components/routes/Admin.js | 2 + admin-panel/src/ducks/event.js | 130 ------------------ admin-panel/src/ducks/events.js | 13 ++ 8 files changed, 183 insertions(+), 135 deletions(-) create mode 100644 admin-panel/src/components/events/Bucket.js create mode 100644 admin-panel/src/components/events/EventDragPreview.js create mode 100644 admin-panel/src/components/events/EventsTableRow.js delete mode 100644 admin-panel/src/ducks/event.js diff --git a/admin-panel/src/components/events/Bucket.js b/admin-panel/src/components/events/Bucket.js new file mode 100644 index 0000000..da63b9a --- /dev/null +++ b/admin-panel/src/components/events/Bucket.js @@ -0,0 +1,41 @@ +import React, { Component } from 'react' +import {connect} from 'react-redux' +import {DropTarget} from 'react-dnd' +import {removeEvent} from '../../ducks/events' + +class Bucket extends Component { + + render() { + const {connectDropTarget, canDrop, hovered} = this.props + + const dndStyle = { + border: `2px solid ${canDrop + ? hovered + ? 'green' + : 'red' + : 'black'}`, + width:'100px', + height:'100px' + } + + return connectDropTarget( +
+

Bucket:

+
+
+ ) + } +} +const spec = { + drop(props, monitor) { + props.removeEvent(monitor.getItem().id) + } +} + +const collect = (connect, monitor) => ({ + connectDropTarget: connect.dropTarget(), + canDrop: monitor.canDrop(), + hovered: monitor.isOver() +}) + +export default connect(null, {removeEvent})(DropTarget(['event'], spec, collect)(Bucket)) diff --git a/admin-panel/src/components/events/EventDragPreview.js b/admin-panel/src/components/events/EventDragPreview.js new file mode 100644 index 0000000..8892c1b --- /dev/null +++ b/admin-panel/src/components/events/EventDragPreview.js @@ -0,0 +1,21 @@ +import React, { Component } from 'react' +import {connect} from 'react-redux' +import {eventSelector} from '../../ducks/events' + +class EventDragPreview extends Component { + static propTypes = { + + }; + + render() { + return ( +
+

{this.props.event.title}

+
+ ) + } +} + +export default connect((state, ownProps) => ({ + event: eventSelector(state, ownProps) +}))(EventDragPreview) \ No newline at end of file diff --git a/admin-panel/src/components/events/EventsTable.js b/admin-panel/src/components/events/EventsTable.js index 432e7a1..047f643 100644 --- a/admin-panel/src/components/events/EventsTable.js +++ b/admin-panel/src/components/events/EventsTable.js @@ -2,6 +2,7 @@ import React, { Component } from 'react' import {connect} from 'react-redux' import {fetchAllEvents, selectEvent, eventListSelector, loadedSelector, loadingSelector} from '../../ducks/events' import Loader from '../common/Loader' +import EventsTableRow from './EventsTableRow' export class EventsTable extends Component { static propTypes = { @@ -26,11 +27,7 @@ export class EventsTable extends Component { getRows = () => this.props.events.map(this.getRow) getRow = (event) => ( - this.props.selectEvent(event.uid)}> - {event.title} - {event.when} - {event.where} - + ) } diff --git a/admin-panel/src/components/events/EventsTableRow.js b/admin-panel/src/components/events/EventsTableRow.js new file mode 100644 index 0000000..5c56a9a --- /dev/null +++ b/admin-panel/src/components/events/EventsTableRow.js @@ -0,0 +1,96 @@ +import React, { Component } from 'react' +import {DragSource} from 'react-dnd' +import {getEmptyImage} from 'react-dnd-html5-backend' +import EventDragPreview from './EventDragPreview' + +class EventsTableRow extends Component { + + componentDidMount() { + this.props.connectDragPreview(getEmptyImage()) + } + + render() { + + + const { className, + columns, + index, + key, + onRowClick, + onRowDoubleClick, + onRowMouseOut, + onRowMouseOver, + onRowRightClick, + rowData, + style, + + isDragging, + connectDragSource + } = this.props; + + const dragStyles = { + opacity: isDragging ? 0.2 : 1 + } + + const a11yProps = {}; + + if ( + onRowClick || + onRowDoubleClick || + onRowMouseOut || + onRowMouseOver || + onRowRightClick + ) { + a11yProps['aria-label'] = 'row'; + a11yProps.tabIndex = 0; + + if (onRowClick) { + a11yProps.onClick = event => onRowClick({ event, index, rowData }); + } + if (onRowDoubleClick) { + a11yProps.onDoubleClick = event => + onRowDoubleClick({ event, index, rowData }); + } + if (onRowMouseOut) { + a11yProps.onMouseOut = event => onRowMouseOut({ event, index, rowData }); + } + if (onRowMouseOver) { + a11yProps.onMouseOver = event => onRowMouseOver({ event, index, rowData }); + } + if (onRowRightClick) { + a11yProps.onContextMenu = event => + onRowRightClick({ event, index, rowData }); + } + } + + return ( + connectDragSource(
+ {columns} +
+ ) + ); + + } +} +const spec = { + beginDrag(props) { + return { + id: props.rowData.uid, + DragPreview: EventDragPreview + } + } +} + +const collect = (connect, monitor) => ({ + connectDragSource: connect.dragSource(), + connectDragPreview: connect.dragPreview(), + isDragging: monitor.isDragging() +}) + +export default DragSource('event', spec, collect)(EventsTableRow) \ No newline at end of file diff --git a/admin-panel/src/components/events/VirtualizedLazyTable.js b/admin-panel/src/components/events/VirtualizedLazyTable.js index 2fc24f2..f6bac71 100644 --- a/admin-panel/src/components/events/VirtualizedLazyTable.js +++ b/admin-panel/src/components/events/VirtualizedLazyTable.js @@ -4,6 +4,13 @@ import {moduleName, fetchLazy, selectEvent, eventListSelector} from '../../ducks import {Table, Column, InfiniteLoader} from 'react-virtualized' import 'react-virtualized/styles.css' +import EventTableRow from './EventsTableRow' + + +function rowRenderer (props) { + return +} + export class EventLazyTable extends Component { static propTypes = { @@ -33,6 +40,7 @@ export class EventLazyTable extends Component { height={300} onRowClick={this.handleRowClick} onRowsRendered={onRowsRendered} + rowRenderer={rowRenderer} rowClassName="test__event_table_row" > Admin Page +
) diff --git a/admin-panel/src/ducks/event.js b/admin-panel/src/ducks/event.js deleted file mode 100644 index e3e69d7..0000000 --- a/admin-panel/src/ducks/event.js +++ /dev/null @@ -1,130 +0,0 @@ -import {appName} from '../config' -import {Record, List} from 'immutable' -import {put, call, all, takeEvery} from 'redux-saga/effects' -import {createSelector} from 'reselect' - -import {saveEventsToFB, getEventsFromFB} from '../mocks/index'; - -/** - * Constants - * */ - -export const moduleName = 'event' -const prefix = `${appName}/${moduleName}` - -export const ADD_EVENTS_REQUEST = `${prefix}/ADD_EVENTS_REQUEST` -export const ADD_EVENTS_START = `${prefix}/ADD_EVENTS_START` -export const ADD_EVENTS_SUCCESS = `${prefix}/ADD_EVENTS_SUCCESS` -export const ADD_EVENTS_ERROR = `${prefix}/ADD_EVENTS_ERROR` - -export const GET_EVENTS_REQUEST = `${prefix}/GET_EVENTS_REQUEST` -export const GET_EVENTS_START = `${prefix}/GET_EVENTS_START` -export const GET_EVENTS_SUCCESS = `${prefix}/GET_EVENTS_SUCCESS` -export const GET_EVENTS_ERROR = `${prefix}/GET_EVENTS_ERROR` - -/** - * Reducer - * */ -const ReducerState = Record({ - entities: new List([]), - loading: false, - error: null -}) - - -export default function reducer(state = new ReducerState(), action) { - const {type, payload} = action - - switch (type) { - case ADD_EVENTS_START: - return state - .set('error', null) - .set('loading', true) - - case GET_EVENTS_SUCCESS: - return state - .update('entities', entities => entities.push(Object.values(payload.events))) - .set('loading', false) - - case ADD_EVENTS_ERROR: - case GET_EVENTS_ERROR: - return state - .set('loading', false) - .set('error', payload.error.message) - default: - return state - } -} - -/** - * Selectors - * */ -export const stateSelector = state => state[moduleName] -export const eventsSelector = createSelector(stateSelector, state => state.entities) -export const loaderSelector = createSelector(stateSelector, state => state.loading) - -/** - * Action Creators - * */ - -export function saveEventsToDb() { - return { - type: ADD_EVENTS_REQUEST - } -} - -/** - * Sagas - */ - -export const saveEventsSaga = function * (action) { - try { - yield put({ - type: ADD_EVENTS_START - }) - let events = yield call(getEventsFromFB); - - if(events === null){ - events = yield call(saveEventsToFB) - } - - yield put({ - type: ADD_EVENTS_SUCCESS, - payload: { events } - }) - }catch(error){ - yield put({ - type: ADD_EVENTS_ERROR, - payload: { error } - }) - } -} - -export const fetchEventsSaga = function * (action){ - try{ - yield put({ - type: GET_EVENTS_START - }) - const events = yield call(getEventsFromFB) - - yield put({ - type: GET_EVENTS_SUCCESS, - payload: { events } - }) - - } - catch(error){ - yield put({ - type: GET_EVENTS_ERROR, - payload: { error } - }) - } -} - - -export const saga = function * () { - yield all([ - takeEvery(ADD_EVENTS_REQUEST, saveEventsSaga), - takeEvery(ADD_EVENTS_SUCCESS,fetchEventsSaga) - ]) -} \ No newline at end of file diff --git a/admin-panel/src/ducks/events.js b/admin-panel/src/ducks/events.js index db0acb6..06465c1 100644 --- a/admin-panel/src/ducks/events.js +++ b/admin-panel/src/ducks/events.js @@ -22,6 +22,8 @@ export const FETCH_LAZY_SUCCESS = `${prefix}/FETCH_LAZY_SUCCESS` export const SELECT = `${prefix}/SELECT` export const ADD_PERSON_TO_EVENT = `${prefix}/ADD_PERSON_TO_EVENT` +export const REMOVE = `${prefix}/REMOVE` + /** * Reducer * */ @@ -67,6 +69,9 @@ export default function reducer(state = new ReducerRecord(), action) { ? selected.remove(payload.uid) : selected.add(payload.uid) ) + case REMOVE: + return state.update('entities', entities => entities.delete(payload.eventId)) + default: return state @@ -86,6 +91,8 @@ export const selectionSelector = createSelector(stateSelector, state => state.se export const selectedEvents = createSelector(eventListSelector, selectionSelector, (events, selected) => events.filter(event => selected.has(event.uid)) ) +export const idSelector = (_, props) => props.id +export const eventSelector = createSelector(entitiesSelector, idSelector, (entities, id) => entities.get(id) !== undefined?entities.get(id):EventRecord) /** * Action Creators @@ -117,6 +124,12 @@ export function addPersonToEvent(personId, eventId) { } } +export function removeEvent(eventId){ + return { + type: REMOVE, + payload:{eventId} + } +} /** * Sagas * */ From 4c741b41c4ab595f437f2513a13bdd1db97814d5 Mon Sep 17 00:00:00 2001 From: Panchenko Svetlana Date: Wed, 20 Dec 2017 04:37:30 +0400 Subject: [PATCH 08/11] =?UTF-8?q?##HT4.2=20=D0=A1=D0=B4=D0=B0=D0=BB=D0=B0?= =?UTF-8?q?=D1=82=D1=8C=20=D0=BA=D0=BE=D1=80=D0=B7=D0=B8=D0=BD=D1=83,=20?= =?UTF-8?q?=D1=83=D0=B4=D0=B0=D0=BB=D1=8F=D1=82=D1=8C=20event=20=D0=BF?= =?UTF-8?q?=D0=B5=D1=80=D0=B5=D1=82=D0=B0=D1=81=D0=BA=D0=B8=D0=B2=D0=B0?= =?UTF-8?q?=D1=8F=20=D0=B5=D0=B3=D0=BE=20=D0=B2=20=D0=BA=D0=BE=D1=80=D0=B7?= =?UTF-8?q?=D0=B8=D0=BD=D1=83=20=D0=B8=D0=B7=20=D1=82=D0=B0=D0=B1=D0=BB?= =?UTF-8?q?=D0=B8=D1=86=D1=8B.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- admin-panel/src/components/user/UserForm.js | 46 ------------- admin-panel/src/ducks/user.js | 75 --------------------- 2 files changed, 121 deletions(-) delete mode 100644 admin-panel/src/components/user/UserForm.js delete mode 100644 admin-panel/src/ducks/user.js diff --git a/admin-panel/src/components/user/UserForm.js b/admin-panel/src/components/user/UserForm.js deleted file mode 100644 index 36541c8..0000000 --- a/admin-panel/src/components/user/UserForm.js +++ /dev/null @@ -1,46 +0,0 @@ -import React, { Component } from 'react' -import {reduxForm, Field} from 'redux-form' -import validator from 'email-validator' - -import ErrorField from '../common/ErrorField' - -class UserForm extends Component { - static propTypes = { - - }; - - render() { - const {mode} = this.props; - return ( -
-

{mode === 'add' ? 'Add user' : 'Edit User' }

-
-
- First name: -
-
- Last name: -
-
- email: -
- -
- -
- ) - } -} -const validate = ({ email }) => { - const errors = {} - - if (!email) errors.email = 'email is a required field' - if (email && !validator.validate(email)) errors.email = 'incorrect email format' - - return errors -} - -export default reduxForm({ - form: 'user', - validate -})(UserForm) \ No newline at end of file diff --git a/admin-panel/src/ducks/user.js b/admin-panel/src/ducks/user.js deleted file mode 100644 index 675a121..0000000 --- a/admin-panel/src/ducks/user.js +++ /dev/null @@ -1,75 +0,0 @@ -import {appName} from '../config' -import {Record} from 'immutable' -import firebase from 'firebase' - -/** - * Constants - * */ -export const moduleName = 'user' -const prefix = `${appName}/${moduleName}` - -export const ADD_USER_START = `${prefix}/ADD_USER_START` -export const ADD_USER_SUCCESS = `${prefix}/ADD_USER_SUCCESS` -export const ADD_USER_FAIL = `${prefix}/ADD_USER_FAIL` - -/** - * Reducer - * */ -export const ReducerRecord = Record({ - //users: null, - loading: false, - error: null -}) - -export default function reducer(state = new ReducerRecord(), action) { - const {type, payload} = action - - switch (type) { - case ADD_USER_START: - return state.set('loading', true) - - case ADD_USER_SUCCESS: - return state - .set('loading', false) - - case ADD_USER_FAIL: - return state - .set('loading', false) - .set('error', payload.error.message) - - default: - return state - } -} - -/** - * Selectors - * */ - -//export const userListSelector = state => state[moduleName].users -export const userLoaderSelector = state => state[moduleName].loading -export const userErrorSelector = state => state[moduleName].error - -/** - * Action Creators - * */ - -export function addUser(firstName, lastName, email) { - return (dispatch) => { - dispatch({ - type: ADD_USER_START - }) - - const db = firebase.database(); - const users = db.ref().child('users'); - - users.push({firstName, lastName, email}) - .then(answer => dispatch({ - type: ADD_USER_SUCCESS - })) - .catch(error => dispatch({ - type: ADD_USER_FAIL, - payload: { error } - })) - } -} From e01ef0011d4d179495fb181c20eac19a132f145d Mon Sep 17 00:00:00 2001 From: Panchenko Svetlana Date: Wed, 20 Dec 2017 04:38:36 +0400 Subject: [PATCH 09/11] =?UTF-8?q?##HT4.2=20=D0=A1=D0=B4=D0=B0=D0=BB=D0=B0?= =?UTF-8?q?=D1=82=D1=8C=20=D0=BA=D0=BE=D1=80=D0=B7=D0=B8=D0=BD=D1=83,=20?= =?UTF-8?q?=D1=83=D0=B4=D0=B0=D0=BB=D1=8F=D1=82=D1=8C=20event=20=D0=BF?= =?UTF-8?q?=D0=B5=D1=80=D0=B5=D1=82=D0=B0=D1=81=D0=BA=D0=B8=D0=B2=D0=B0?= =?UTF-8?q?=D1=8F=20=D0=B5=D0=B3=D0=BE=20=D0=B2=20=D0=BA=D0=BE=D1=80=D0=B7?= =?UTF-8?q?=D0=B8=D0=BD=D1=83=20=D0=B8=D0=B7=20=D1=82=D0=B0=D0=B1=D0=BB?= =?UTF-8?q?=D0=B8=D1=86=D1=8B.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- admin-panel/src/App.js | 23 ----------------------- 1 file changed, 23 deletions(-) delete mode 100644 admin-panel/src/App.js diff --git a/admin-panel/src/App.js b/admin-panel/src/App.js deleted file mode 100644 index fd110f7..0000000 --- a/admin-panel/src/App.js +++ /dev/null @@ -1,23 +0,0 @@ -import React, { Component } from 'react' -import {Route} from 'react-router-dom' -import Auth from './components/routes/auth' -import Admin from './components/routes/Admin' -import ProtectedRoute from './components/common/ProtectedRoute' - -class App extends Component { - static propTypes = { - - }; - - render() { - return ( -
-

Hello world

- - -
- ) - } -} - -export default App \ No newline at end of file From e9436e6768c0e3acb33994934e678ff48862449f Mon Sep 17 00:00:00 2001 From: Panchenko Svetlana Date: Wed, 20 Dec 2017 04:39:21 +0400 Subject: [PATCH 10/11] =?UTF-8?q?##HT4.2=20=D0=A1=D0=B4=D0=B0=D0=BB=D0=B0?= =?UTF-8?q?=D1=82=D1=8C=20=D0=BA=D0=BE=D1=80=D0=B7=D0=B8=D0=BD=D1=83,=20?= =?UTF-8?q?=D1=83=D0=B4=D0=B0=D0=BB=D1=8F=D1=82=D1=8C=20event=20=D0=BF?= =?UTF-8?q?=D0=B5=D1=80=D0=B5=D1=82=D0=B0=D1=81=D0=BA=D0=B8=D0=B2=D0=B0?= =?UTF-8?q?=D1=8F=20=D0=B5=D0=B3=D0=BE=20=D0=B2=20=D0=BA=D0=BE=D1=80=D0=B7?= =?UTF-8?q?=D0=B8=D0=BD=D1=83=20=D0=B8=D0=B7=20=D1=82=D0=B0=D0=B1=D0=BB?= =?UTF-8?q?=D0=B8=D1=86=D1=8B.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- admin-panel/src/components/events/EventsTable.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/admin-panel/src/components/events/EventsTable.js b/admin-panel/src/components/events/EventsTable.js index 047f643..432e7a1 100644 --- a/admin-panel/src/components/events/EventsTable.js +++ b/admin-panel/src/components/events/EventsTable.js @@ -2,7 +2,6 @@ import React, { Component } from 'react' import {connect} from 'react-redux' import {fetchAllEvents, selectEvent, eventListSelector, loadedSelector, loadingSelector} from '../../ducks/events' import Loader from '../common/Loader' -import EventsTableRow from './EventsTableRow' export class EventsTable extends Component { static propTypes = { @@ -27,7 +26,11 @@ export class EventsTable extends Component { getRows = () => this.props.events.map(this.getRow) getRow = (event) => ( - + this.props.selectEvent(event.uid)}> + {event.title} + {event.when} + {event.where} + ) } From dc420a0b8cec51bf1ddf6ba67592c3084e234076 Mon Sep 17 00:00:00 2001 From: SvetlanaVesna Date: Wed, 20 Dec 2017 04:42:26 +0400 Subject: [PATCH 11/11] Update Bucket.js --- admin-panel/src/components/events/Bucket.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/admin-panel/src/components/events/Bucket.js b/admin-panel/src/components/events/Bucket.js index da63b9a..5bb83df 100644 --- a/admin-panel/src/components/events/Bucket.js +++ b/admin-panel/src/components/events/Bucket.js @@ -21,7 +21,7 @@ class Bucket extends Component { return connectDropTarget(

Bucket:

-
+
) }