From c0110d5769d3006d5952b8f4e5e0a9bb1e2d2308 Mon Sep 17 00:00:00 2001 From: Max Date: Sat, 7 Jul 2018 16:33:24 +0300 Subject: [PATCH 01/10] set up firebase --- admin/src/config.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/admin/src/config.js b/admin/src/config.js index baf47b0..9110480 100644 --- a/admin/src/config.js +++ b/admin/src/config.js @@ -4,12 +4,12 @@ import 'firebase/auth' export const appName = 'adv-react-25-06' const config = { - apiKey: 'AIzaSyDzqwnZ_39QyqhxYZVPjVH8eBww7DUBmVc', - authDomain: `${appName}.firebaseapp.com`, - databaseURL: `https://${appName}.firebaseio.com`, - projectId: appName, + apiKey: 'AIzaSyD25TAZjq0-smHue8ViLsxv3nWBHm3Pjug', + authDomain: 'advreact-bed03.firebaseapp.com', + databaseURL: 'https://advreact-bed03.firebaseio.com', + projectId: 'advreact-bed03', storageBucket: '', - messagingSenderId: '874599443389' + messagingSenderId: '389238619888' } initializeApp(config) From a097e798f40a8b3600ec79a2680d878b63589c9a Mon Sep 17 00:00:00 2001 From: Max Date: Sat, 7 Jul 2018 16:47:36 +0300 Subject: [PATCH 02/10] created events duck --- admin/src/ducks/events.js | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 admin/src/ducks/events.js diff --git a/admin/src/ducks/events.js b/admin/src/ducks/events.js new file mode 100644 index 0000000..5492024 --- /dev/null +++ b/admin/src/ducks/events.js @@ -0,0 +1,35 @@ +import { Record, List } from 'immutable' + +// Constants +export const GET_EVENTS_REQUEST = 'GET_EVENTS_REQUEST' +export const GET_EVENTS_SUCCESS = 'GET_EVENTS_SUCCESS' +export const GET_EVENTS_ERROR = 'GET_EVENTS_ERROR' + +// Reducer +const ReducerState = Record({ + events: new List([]), + fetching: false +}) + +const EventRecord = Record({ + title: null, + url: null, + where: null, + when: null, + month: null, + submissionDeadline: null +}) + +export default function reducer(state = new ReducerState(), action) { + const { type, payload } = action + + switch (type) { + case GET_EVENTS_REQUEST: + return state.update('fetching', (fetching) => false) + } +} + +// Action Creators +export const getEvents = () => ({ + type: GET_EVENTS_REQUEST +}) From fa31136f7bb99c9b0041d75de5420a816a327172 Mon Sep 17 00:00:00 2001 From: Max Date: Sat, 7 Jul 2018 18:07:51 +0300 Subject: [PATCH 03/10] added events reducer --- admin/src/ducks/events.js | 50 ++++++++++++++++++++++++--------- admin/src/redux/reducer.js | 4 ++- admin/src/routes/admin.js | 2 ++ admin/src/routes/events-page.js | 20 +++++++++++++ 4 files changed, 61 insertions(+), 15 deletions(-) create mode 100644 admin/src/routes/events-page.js diff --git a/admin/src/ducks/events.js b/admin/src/ducks/events.js index 5492024..b45df4f 100644 --- a/admin/src/ducks/events.js +++ b/admin/src/ducks/events.js @@ -1,31 +1,53 @@ import { Record, List } from 'immutable' // Constants +export const moduleName = 'events' export const GET_EVENTS_REQUEST = 'GET_EVENTS_REQUEST' export const GET_EVENTS_SUCCESS = 'GET_EVENTS_SUCCESS' export const GET_EVENTS_ERROR = 'GET_EVENTS_ERROR' // Reducer -const ReducerState = Record({ - events: new List([]), - fetching: false -}) +// const ReducerState = Record({ +// events: new List([]), +// fetching: false +// }) +// +// const EventRecord = Record({ +// title: null, +// url: null, +// where: null, +// when: null, +// month: null, +// submissionDeadline: null +// }) -const EventRecord = Record({ - title: null, - url: null, - where: null, - when: null, - month: null, - submissionDeadline: null -}) +const initialState = { + entities: [], + fetching: false +} -export default function reducer(state = new ReducerState(), action) { +export default function reducer(state = initialState, action) { const { type, payload } = action switch (type) { case GET_EVENTS_REQUEST: - return state.update('fetching', (fetching) => false) + return { + ...state, + fetching: true + } + case GET_EVENTS_SUCCESS: + return { + ...state, + entities: payload, + fetching: false + } + case GET_EVENTS_ERROR: + return { + ...state, + fetching: false + } + default: + return state } } diff --git a/admin/src/redux/reducer.js b/admin/src/redux/reducer.js index 60ea924..c28e1e8 100644 --- a/admin/src/redux/reducer.js +++ b/admin/src/redux/reducer.js @@ -2,9 +2,11 @@ import { combineReducers } from '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 eventsReducer, { moduleName as eventsModule } from '../ducks/events' export default combineReducers({ form, [authModule]: authReducer, - [peopleModule]: peopleReducer + [peopleModule]: peopleReducer, + [eventsModule]: eventsReducer }) diff --git a/admin/src/routes/admin.js b/admin/src/routes/admin.js index aa30167..f0edbd1 100644 --- a/admin/src/routes/admin.js +++ b/admin/src/routes/admin.js @@ -1,6 +1,7 @@ import React, { Component } from 'react' import { Route } from 'react-router-dom' import PersonPage from './person-page' +import EventsPage from './events-page' class AdminPage extends Component { static propTypes = {} @@ -10,6 +11,7 @@ class AdminPage extends Component {

Admin Page

+
) } diff --git a/admin/src/routes/events-page.js b/admin/src/routes/events-page.js new file mode 100644 index 0000000..2a31a7c --- /dev/null +++ b/admin/src/routes/events-page.js @@ -0,0 +1,20 @@ +import React, { Component } from 'react' +import { connect } from 'react-redux' +import { getEvents } from '../ducks/events' + +class EventsPage extends Component { + static propTypes = {} + + componentDidMount() { + this.props.getEvents() + } + + render() { + return
hello
+ } +} + +export default connect( + null, + { getEvents } +)(EventsPage) From 1909743fe2f0f4650316220361ae03bfcda0d3d5 Mon Sep 17 00:00:00 2001 From: Max Date: Sun, 8 Jul 2018 05:52:07 +0300 Subject: [PATCH 04/10] events saga --- admin/src/ducks/events.js | 21 +++++++++++++++++++++ admin/src/redux/saga.js | 3 ++- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/admin/src/ducks/events.js b/admin/src/ducks/events.js index b45df4f..be73989 100644 --- a/admin/src/ducks/events.js +++ b/admin/src/ducks/events.js @@ -1,4 +1,7 @@ import { Record, List } from 'immutable' +import { put, takeLatest, call } from 'redux-saga/effects' +import { delay } from 'redux-saga' +import firebase from 'firebase/app' // Constants export const moduleName = 'events' @@ -55,3 +58,21 @@ export default function reducer(state = initialState, action) { export const getEvents = () => ({ type: GET_EVENTS_REQUEST }) + +// Sagas +function* getEventsSaga() { + const ref = firebase.database().ref('/events') + // делей для видимости лоадера + yield call(delay, 1000) + + const snapshot = yield call([ref, ref.once], 'value') + + yield put({ + type: GET_EVENTS_SUCCESS, + payload: snapshot.val() + }) +} + +export function* saga() { + yield takeLatest(GET_EVENTS_REQUEST, getEventsSaga) +} diff --git a/admin/src/redux/saga.js b/admin/src/redux/saga.js index ca88652..71a1ad8 100644 --- a/admin/src/redux/saga.js +++ b/admin/src/redux/saga.js @@ -1,7 +1,8 @@ import { all } from 'redux-saga/effects' import { saga as peopleSaga } from '../ducks/people' import { saga as authSaga } from '../ducks/auth' +import { saga as eventsSaga } from '../ducks/events' export default function*() { - yield all([authSaga(), peopleSaga()]) + yield all([authSaga(), peopleSaga(), eventsSaga()]) } From d7fe1fe3e396234090c4e47aa3b88c683c8406b0 Mon Sep 17 00:00:00 2001 From: Max Date: Sun, 8 Jul 2018 06:22:02 +0300 Subject: [PATCH 05/10] events list component events selector --- admin/src/components/events/events-list.js | 21 +++++++++++++++++++++ admin/src/ducks/events.js | 17 +++++++++++++---- admin/src/routes/events-page.js | 21 ++++++++------------- 3 files changed, 42 insertions(+), 17 deletions(-) create mode 100644 admin/src/components/events/events-list.js diff --git a/admin/src/components/events/events-list.js b/admin/src/components/events/events-list.js new file mode 100644 index 0000000..d05e692 --- /dev/null +++ b/admin/src/components/events/events-list.js @@ -0,0 +1,21 @@ +import React, { Component, Fragment } from 'react' +import { getEvents, eventsSelector, moduleName } from '../../ducks/events' +import { connect } from 'react-redux' + +class EventsList extends Component { + componentDidMount() { + this.props.getEvents() + } + + render() { + return hey) + } +} + +export default connect( + (state) => ({ + events: eventsSelector(state), + fetching: state[moduleName].fetching + }), + { getEvents } +)(EventsList) diff --git a/admin/src/ducks/events.js b/admin/src/ducks/events.js index be73989..62998b1 100644 --- a/admin/src/ducks/events.js +++ b/admin/src/ducks/events.js @@ -1,13 +1,14 @@ import { Record, List } from 'immutable' import { put, takeLatest, call } from 'redux-saga/effects' +import { createSelector } from 'reselect' import { delay } from 'redux-saga' import firebase from 'firebase/app' // Constants export const moduleName = 'events' -export const GET_EVENTS_REQUEST = 'GET_EVENTS_REQUEST' -export const GET_EVENTS_SUCCESS = 'GET_EVENTS_SUCCESS' -export const GET_EVENTS_ERROR = 'GET_EVENTS_ERROR' +export const GET_EVENTS_REQUEST = `${moduleName}/GET_EVENTS_REQUEST` +export const GET_EVENTS_SUCCESS = `${moduleName}/GET_EVENTS_SUCCESS` +export const GET_EVENTS_ERROR = `${moduleName}/GET_EVENTS_ERROR` // Reducer // const ReducerState = Record({ @@ -25,7 +26,7 @@ export const GET_EVENTS_ERROR = 'GET_EVENTS_ERROR' // }) const initialState = { - entities: [], + entities: {}, fetching: false } @@ -54,6 +55,14 @@ export default function reducer(state = initialState, action) { } } +// Selectors +export const stateSelector = (state) => state[moduleName] +export const eventsSelector = createSelector( + stateSelector, + // state => state.entities.valueSeq().toArray() + (state) => state.entities +) + // Action Creators export const getEvents = () => ({ type: GET_EVENTS_REQUEST diff --git a/admin/src/routes/events-page.js b/admin/src/routes/events-page.js index 2a31a7c..4d5ccbb 100644 --- a/admin/src/routes/events-page.js +++ b/admin/src/routes/events-page.js @@ -1,20 +1,15 @@ import React, { Component } from 'react' -import { connect } from 'react-redux' -import { getEvents } from '../ducks/events' +import EventsList from '../components/events/events-list' class EventsPage extends Component { - static propTypes = {} - - componentDidMount() { - this.props.getEvents() - } - render() { - return
hello
+ return ( +
+

Events list

+ +
+ ) } } -export default connect( - null, - { getEvents } -)(EventsPage) +export default EventsPage From 21580d35cc72cc72e7f8e5787c9b03150eccffea Mon Sep 17 00:00:00 2001 From: Max Date: Sun, 8 Jul 2018 06:41:43 +0300 Subject: [PATCH 06/10] immutable --- admin/src/components/events/events-list.js | 5 +- admin/src/ducks/events.js | 55 +++++++++------------- 2 files changed, 27 insertions(+), 33 deletions(-) diff --git a/admin/src/components/events/events-list.js b/admin/src/components/events/events-list.js index d05e692..fdd7d38 100644 --- a/admin/src/components/events/events-list.js +++ b/admin/src/components/events/events-list.js @@ -8,7 +8,10 @@ class EventsList extends Component { } render() { - return hey) + console.log(this.props.events) + const { events, fetching } = this.props + console.log() + return
{fetching ?
(
:
))
}
} } diff --git a/admin/src/ducks/events.js b/admin/src/ducks/events.js index 62998b1..07cefc2 100644 --- a/admin/src/ducks/events.js +++ b/admin/src/ducks/events.js @@ -1,4 +1,4 @@ -import { Record, List } from 'immutable' +import { Record, OrderedMap } from 'immutable' import { put, takeLatest, call } from 'redux-saga/effects' import { createSelector } from 'reselect' import { delay } from 'redux-saga' @@ -11,45 +11,30 @@ export const GET_EVENTS_SUCCESS = `${moduleName}/GET_EVENTS_SUCCESS` export const GET_EVENTS_ERROR = `${moduleName}/GET_EVENTS_ERROR` // Reducer -// const ReducerState = Record({ -// events: new List([]), -// fetching: false -// }) -// -// const EventRecord = Record({ -// title: null, -// url: null, -// where: null, -// when: null, -// month: null, -// submissionDeadline: null -// }) - -const initialState = { - entities: {}, +const ReducerState = Record({ + entities: new OrderedMap([]), fetching: false -} +}) -export default function reducer(state = initialState, action) { +const EventRecord = Record({ + title: null, + url: null, + where: null, + when: null, + month: null, + submissionDeadline: null +}) + +export default function reducer(state = new ReducerState(), action) { const { type, payload } = action switch (type) { case GET_EVENTS_REQUEST: - return { - ...state, - fetching: true - } + return state.set('fetching', true) case GET_EVENTS_SUCCESS: - return { - ...state, - entities: payload, - fetching: false - } + return state.set('fetching', false).set('entities', payload) case GET_EVENTS_ERROR: - return { - ...state, - fetching: false - } + return state.set('fetching', false) default: return state } @@ -85,3 +70,9 @@ function* getEventsSaga() { export function* saga() { yield takeLatest(GET_EVENTS_REQUEST, getEventsSaga) } + +// utils +export const eventsResponseToState = (events) => { + console.log(events) + return [] +} From d0b741d32bc7c4ec8b2bdc63c306071c6bc3f883 Mon Sep 17 00:00:00 2001 From: Max Date: Sun, 8 Jul 2018 07:48:42 +0300 Subject: [PATCH 07/10] event list view --- admin/src/components/events/events-list.js | 31 +++++++++++++++++++--- admin/src/components/events/events.css | 16 +++++++++++ admin/src/ducks/events.js | 20 +++++++------- 3 files changed, 55 insertions(+), 12 deletions(-) create mode 100644 admin/src/components/events/events.css diff --git a/admin/src/components/events/events-list.js b/admin/src/components/events/events-list.js index fdd7d38..00a8880 100644 --- a/admin/src/components/events/events-list.js +++ b/admin/src/components/events/events-list.js @@ -1,6 +1,7 @@ import React, { Component, Fragment } from 'react' import { getEvents, eventsSelector, moduleName } from '../../ducks/events' import { connect } from 'react-redux' +import './events.css' class EventsList extends Component { componentDidMount() { @@ -8,10 +9,34 @@ class EventsList extends Component { } render() { - console.log(this.props.events) const { events, fetching } = this.props - console.log() - return
{fetching ?
(
:
))
}
+ { + if (fetching) { + return
Loading...
+ } else { + return ( +
+ {events.map((event) => ( +
+
{event.title}
+
{event.when}
+
{event.where}
+
{event.url}
+
+ ))} +
+ ) + } + } + return ( +
+ {fetching ? ( +
(
+ ) : ( +
{events.map((event) => event.title)}
+ )} +
+ ) } } diff --git a/admin/src/components/events/events.css b/admin/src/components/events/events.css new file mode 100644 index 0000000..fc58cbf --- /dev/null +++ b/admin/src/components/events/events.css @@ -0,0 +1,16 @@ +.events-list-item { + box-shadow: 0 1px 3px 0 rgba(0,0,0,.2), 0 1px 1px 0 rgba(0,0,0,.14), 0 2px 1px -1px rgba(0,0,0,.12); + padding: 24px 16px; + font-family: Arial sans-serif; + margin: 8px; + max-width: 50%; +} + +.events-list-item__title { + font-size: 24px; +} + +.events-list-item__date { + font-size: 12px; + margin-bottom: 12px; +} \ No newline at end of file diff --git a/admin/src/ducks/events.js b/admin/src/ducks/events.js index 07cefc2..dfb0e59 100644 --- a/admin/src/ducks/events.js +++ b/admin/src/ducks/events.js @@ -12,7 +12,7 @@ export const GET_EVENTS_ERROR = `${moduleName}/GET_EVENTS_ERROR` // Reducer const ReducerState = Record({ - entities: new OrderedMap([]), + entities: new OrderedMap(), fetching: false }) @@ -32,7 +32,9 @@ export default function reducer(state = new ReducerState(), action) { case GET_EVENTS_REQUEST: return state.set('fetching', true) case GET_EVENTS_SUCCESS: - return state.set('fetching', false).set('entities', payload) + return state + .set('fetching', false) + .set('entities', eventsResponseToState(payload)) case GET_EVENTS_ERROR: return state.set('fetching', false) default: @@ -42,10 +44,8 @@ export default function reducer(state = new ReducerState(), action) { // Selectors export const stateSelector = (state) => state[moduleName] -export const eventsSelector = createSelector( - stateSelector, - // state => state.entities.valueSeq().toArray() - (state) => state.entities +export const eventsSelector = createSelector(stateSelector, (state) => + state.entities.valueSeq().toArray() ) // Action Creators @@ -72,7 +72,9 @@ export function* saga() { } // utils -export const eventsResponseToState = (events) => { - console.log(events) - return [] +export const eventsResponseToState = (values) => { + return Object.entries(values).reduce( + (item, [uid, value]) => item.set(uid, new EventRecord({ uid, ...value })), + new OrderedMap({}) + ) } From 3590277e803305fad650061186bae275eba93bae Mon Sep 17 00:00:00 2001 From: Max Date: Sun, 8 Jul 2018 08:57:15 +0300 Subject: [PATCH 08/10] auth spec --- admin/src/ducks/auth.spec.js | 40 ++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 admin/src/ducks/auth.spec.js diff --git a/admin/src/ducks/auth.spec.js b/admin/src/ducks/auth.spec.js new file mode 100644 index 0000000..d67c8f5 --- /dev/null +++ b/admin/src/ducks/auth.spec.js @@ -0,0 +1,40 @@ +import { call, put } from 'redux-saga/effects' +import firebase from 'firebase/app' +import { SIGN_UP_REQUEST, SIGN_UP_SUCCESS, signUpSaga } from './auth' + +describe('Auth duck sign up saga', () => { + it('should sign up with new email and password', () => { + const auth = firebase.auth() + const credentials = { + email: `test${+new Date()}@test.com`, + password: 'qwerty123' + } + + const action = { + type: SIGN_UP_REQUEST, + payload: credentials + } + + const saga = signUpSaga(action) + + expect(saga.next().value).toEqual( + call( + [auth, auth.createUserWithEmailAndPassword], + credentials.email, + credentials.password + ) + ) + + const user = { + email: credentials.email, + uid: '123' + } + + expect(saga.next(user).value).toEqual( + put({ + type: SIGN_UP_SUCCESS, + payload: { user } + }) + ) + }) +}) From c949d24e6562184f2c8d2e41657ba1da18d437f6 Mon Sep 17 00:00:00 2001 From: Max Date: Sun, 8 Jul 2018 09:29:41 +0300 Subject: [PATCH 09/10] auth spec --- admin/src/ducks/auth.spec.js | 45 ++++++++++++++++++++++++++++++++++-- 1 file changed, 43 insertions(+), 2 deletions(-) diff --git a/admin/src/ducks/auth.spec.js b/admin/src/ducks/auth.spec.js index d67c8f5..043fd4e 100644 --- a/admin/src/ducks/auth.spec.js +++ b/admin/src/ducks/auth.spec.js @@ -1,6 +1,13 @@ -import { call, put } from 'redux-saga/effects' +import { call, put, apply } from 'redux-saga/effects' import firebase from 'firebase/app' -import { SIGN_UP_REQUEST, SIGN_UP_SUCCESS, signUpSaga } from './auth' +import { + SIGN_UP_REQUEST, + SIGN_UP_SUCCESS, + SIGN_IN_REQUEST, + SIGN_IN_SUCCESS, + signUpSaga, + signInSaga +} from './auth' describe('Auth duck sign up saga', () => { it('should sign up with new email and password', () => { @@ -37,4 +44,38 @@ describe('Auth duck sign up saga', () => { }) ) }) + + it('should sign in', () => { + const auth = firebase.auth() + + const credentials = { + email: `test${+new Date()}@test.com`, + password: 'qwerty123' + } + + const action = { + type: SIGN_IN_REQUEST, + payload: credentials + } + + const saga = signUpSaga(action) + + expect(saga.next().value).toEqual( + apply(auth, auth.signInWithEmailAndPassword, [ + credentials.email, + credentials.password + ]) + ) + + const user = { + email: credentials.email + } + + expect(saga.next(user).value).toEqual( + put({ + type: SIGN_IN_SUCCESS, + payload: { user } + }) + ) + }) }) From eea14d6738cbe9931b3641084029523d720248da Mon Sep 17 00:00:00 2001 From: Max Date: Sun, 8 Jul 2018 09:30:42 +0300 Subject: [PATCH 10/10] auth spec --- admin/src/ducks/auth.spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/admin/src/ducks/auth.spec.js b/admin/src/ducks/auth.spec.js index 043fd4e..0d06c8a 100644 --- a/admin/src/ducks/auth.spec.js +++ b/admin/src/ducks/auth.spec.js @@ -58,7 +58,7 @@ describe('Auth duck sign up saga', () => { payload: credentials } - const saga = signUpSaga(action) + const saga = signInSaga(action) expect(saga.next().value).toEqual( apply(auth, auth.signInWithEmailAndPassword, [