From 7d8765b6c9d9b63a69cbab6d0f003b564c4f09ab Mon Sep 17 00:00:00 2001 From: User Date: Wed, 30 May 2018 20:04:31 +0200 Subject: [PATCH 1/3] save events for person --- admin/src/ducks/people.js | 36 +++++++++++++++++++++++++++++++----- 1 file changed, 31 insertions(+), 5 deletions(-) diff --git a/admin/src/ducks/people.js b/admin/src/ducks/people.js index 40562f7..15a0e70 100644 --- a/admin/src/ducks/people.js +++ b/admin/src/ducks/people.js @@ -1,7 +1,7 @@ import { appName } from '../config' import { Record, OrderedMap } from 'immutable' import { createSelector } from 'reselect' -import { put, call, all, takeEvery } from 'redux-saga/effects' +import { put, call, all, takeEvery, select } from 'redux-saga/effects' import { reset } from 'redux-form' import firebase from 'firebase/app' import { fbToEntities } from './utils' @@ -18,8 +18,8 @@ export const ADD_PERSON_SUCCESS = `${prefix}/ADD_PERSON_SUCCESS` export const FETCH_ALL_REQUEST = `${prefix}/FETCH_ALL_REQUEST` export const FETCH_ALL_SUCCESS = `${prefix}/FETCH_ALL_SUCCESS` -export const ADD_EVENT = `${prefix}/ADD_EVENT` - +export const ADD_EVENT_TO_PERSON = `${prefix}/ADD_EVENT_TO_PERSON` +export const ADD_EVENT_TO_PERSON_SUCCESS = `${prefix}/ADD_EVENT_TO_PERSON_SUCCESS` /** * Reducer * */ @@ -42,6 +42,12 @@ export default function reducer(state = new ReducerState(), action) { case ADD_PERSON_SUCCESS: return state.setIn(['entities', payload.uid], new PersonRecord(payload)) + case ADD_EVENT_TO_PERSON_SUCCESS: + return state.updateIn( + ['entities', payload.personUid, 'events'], + (events) => [...new Set([...events, payload.eventUid])] + ) + case FETCH_ALL_SUCCESS: return state.set('entities', fbToEntities(payload, PersonRecord)) @@ -68,6 +74,11 @@ export const personSelector = createSelector( (entities, uid) => entities.get(uid) ) +export const personEventsSelector = createSelector( + personSelector, + (person) => person.events +) + /** * Action Creators * */ @@ -87,7 +98,7 @@ export function fetchAllPeople() { export function addEventToPerson(eventUid, personUid) { return { - type: ADD_EVENT, + type: ADD_EVENT_TO_PERSON, payload: { eventUid, personUid } } } @@ -96,6 +107,20 @@ export function addEventToPerson(eventUid, personUid) { * Sagas */ +export function* addEventToPersonSaga(action) { + const { eventUid, personUid } = action.payload + const eventsRef = firebase.database().ref(`people/${personUid}/events`) + const events = yield select(personEventsSelector, { uid: personUid }) + const nextPersonEvents = [...new Set([...events, eventUid])] + + yield call([eventsRef, eventsRef.set], nextPersonEvents) + + yield put({ + type: ADD_EVENT_TO_PERSON_SUCCESS, + payload: { eventUid, personUid } + }) +} + export function* addPersonSaga(action) { yield put({ type: ADD_PERSON_START, @@ -128,6 +153,7 @@ export function* fetchAllSaga() { export const saga = function*() { yield all([ takeEvery(ADD_PERSON, addPersonSaga), - takeEvery(FETCH_ALL_REQUEST, fetchAllSaga) + takeEvery(FETCH_ALL_REQUEST, fetchAllSaga), + takeEvery(ADD_EVENT_TO_PERSON, addEventToPersonSaga) ]) } From 014d9994eb52785efdac9896ba2998dad47475fb Mon Sep 17 00:00:00 2001 From: User Date: Wed, 30 May 2018 20:46:20 +0200 Subject: [PATCH 2/3] add cart component --- admin/src/components/cart/index.js | 35 ++++++ .../components/events/selected-event-card.js | 2 +- admin/src/config.js | 6 +- admin/src/ducks/cart.js | 102 ++++++++++++++++++ admin/src/routes/events-page.js | 2 + 5 files changed, 143 insertions(+), 4 deletions(-) create mode 100644 admin/src/components/cart/index.js create mode 100644 admin/src/ducks/cart.js diff --git a/admin/src/components/cart/index.js b/admin/src/components/cart/index.js new file mode 100644 index 0000000..bd60414 --- /dev/null +++ b/admin/src/components/cart/index.js @@ -0,0 +1,35 @@ +import React, { Component } from 'react' +import { DropTarget } from 'react-dnd' +import { connect } from 'react-redux' +import { deleteItemByType } from '../../ducks/cart' + +class Cart extends Component { + static propTypes = {} + + render() { + const { event, connectDropTarget, canReceive, hovered } = this.props + const borderColor = canReceive ? (hovered ? 'green' : 'red') : 'black' + return connectDropTarget( +
+

πŸ›’

+
+ ) + } +} + +const spec = { + drop(props, monitor) { + const { deleteItemByType } = props + deleteItemByType(monitor.getItem().uid) + } +} + +const collect = (connect, monitor) => ({ + connectDropTarget: connect.dropTarget(), + canReceive: monitor.canDrop(), + hovered: monitor.isOver() +}) + +export default connect(null, { deleteItemByType })( + DropTarget(['person', 'event'], spec, collect)(Cart) +) diff --git a/admin/src/components/events/selected-event-card.js b/admin/src/components/events/selected-event-card.js index e901cd5..8e62585 100644 --- a/admin/src/components/events/selected-event-card.js +++ b/admin/src/components/events/selected-event-card.js @@ -1,5 +1,5 @@ import React, { Component } from 'react' -import { DropTarget } from 'react-dnd' +import { DropTarget, DragSource } from 'react-dnd' import { connect } from 'react-redux' import { addEventToPerson } from '../../ducks/people' diff --git a/admin/src/config.js b/admin/src/config.js index aa22b3b..8f4a95d 100644 --- a/admin/src/config.js +++ b/admin/src/config.js @@ -2,15 +2,15 @@ import firebase from 'firebase/app' import 'firebase/auth' import 'firebase/database' -export const appName = 'advreact-10-05' +export const appName = 'advreact-10-05-ee9f5' export const config = { - apiKey: 'AIzaSyCbMQM0eQUSQ0SuLVAu9ZNPUcm4rdbiB8U', + apiKey: 'AIzaSyA9z4Xmknc0zIAIfvWCfe4XWwhwqiTO9h0', authDomain: `${appName}.firebaseapp.com`, databaseURL: `https://${appName}.firebaseio.com`, projectId: appName, storageBucket: '', - messagingSenderId: '1094825197832' + messagingSenderId: '963790431937' } firebase.initializeApp(config) diff --git a/admin/src/ducks/cart.js b/admin/src/ducks/cart.js new file mode 100644 index 0000000..183b142 --- /dev/null +++ b/admin/src/ducks/cart.js @@ -0,0 +1,102 @@ +import { appName } from '../config' +import { Record, OrderedMap } from 'immutable' +import { createSelector } from 'reselect' +import { put, call, all, takeEvery, select } from 'redux-saga/effects' +import { reset } from 'redux-form' +import firebase from 'firebase/app' +import { fbToEntities } from './utils' + +/** + * Constants + * */ +export const moduleName = 'cart' +const prefix = `${appName}/${moduleName}` +export const DELETE_ITEM = `${prefix}/DELETE_ITEM` +export const DELETE_ITEM_SUCCESS = `${prefix}/DELETE_ITEM_SUCCESS` + +/** + * Reducer + * */ +const ReducerState = Record({ + entities: new OrderedMap({}) +}) + +const PersonRecord = Record({ + uid: null, + firstName: null, + lastName: null, + email: null, + events: [] +}) + +export default function reducer(state = new ReducerState(), action) { + const { type, payload } = action + + switch (type) { + case DELETE_ITEM_SUCCESS: + // return state.updateIn( + // ['entities', payload.personUid, 'events'], + // (events) => [...new Set([...events, payload.eventUid])] + // ) + return state + + default: + return state + } +} + +/** + * Selectors + * */ +export const stateSelector = (state) => state[moduleName] +export const entitiesSelector = createSelector( + stateSelector, + (state) => state.entities +) +export const peopleSelector = createSelector(entitiesSelector, (entities) => + entities.valueSeq().toArray() +) +export const idSelector = (_, props) => props.uid +export const personSelector = createSelector( + entitiesSelector, + idSelector, + (entities, uid) => entities.get(uid) +) + +export const personEventsSelector = createSelector( + personSelector, + (person) => person.events +) + +/** + * Action Creators + * */ + +export function deleteItemByType(eventUid, personUid) { + return { + type: DELETE_ITEM, + payload: { eventUid, personUid } + } +} + +/** + * Sagas + */ + +export function* deleteItemByTypeSaga(action) { + // const { eventUid, personUid } = action.payload + // const eventsRef = firebase.database().ref(`people/${personUid}/events`) + // const events = yield select(personEventsSelector, { uid: personUid }) + // const nextPersonEvents = [...new Set([...events, eventUid])] + // + // yield call([eventsRef, eventsRef.set], nextPersonEvents) + + yield put({ + type: DELETE_ITEM_SUCCESS, + payload: action.payload + }) +} + +export const saga = function*() { + yield all([takeEvery(DELETE_ITEM, deleteItemByTypeSaga)]) +} diff --git a/admin/src/routes/events-page.js b/admin/src/routes/events-page.js index d893d20..15907cd 100644 --- a/admin/src/routes/events-page.js +++ b/admin/src/routes/events-page.js @@ -2,6 +2,7 @@ import React, { Component } from 'react' import EventsTable from '../components/events/virtualized-lazy-table' import SelectedEvents from '../components/events/selected-events' import PeopleList from '../components/people/people-list' +import Cart from '../components/cart' class EventsPage extends Component { static propTypes = {} @@ -9,6 +10,7 @@ class EventsPage extends Component { render() { return (
+ From d308d73e6a9867f1640682d97216ce710982b83a Mon Sep 17 00:00:00 2001 From: User Date: Sat, 2 Jun 2018 00:03:38 +0200 Subject: [PATCH 3/3] completed duck cart --- admin/src/components/cart/index.js | 10 +++- admin/src/components/events/drag-table-row.js | 30 ++++++++++ .../components/events/selected-event-card.js | 2 +- .../events/virtualized-lazy-table.js | 12 +++- admin/src/components/people/person-card.js | 1 + admin/src/ducks/cart.js | 56 ++++--------------- admin/src/redux/reducer.js | 4 +- admin/src/redux/saga.js | 3 +- 8 files changed, 65 insertions(+), 53 deletions(-) create mode 100644 admin/src/components/events/drag-table-row.js diff --git a/admin/src/components/cart/index.js b/admin/src/components/cart/index.js index bd60414..186a2b4 100644 --- a/admin/src/components/cart/index.js +++ b/admin/src/components/cart/index.js @@ -7,11 +7,15 @@ class Cart extends Component { static propTypes = {} render() { - const { event, connectDropTarget, canReceive, hovered } = this.props + const { connectDropTarget, canReceive, hovered } = this.props const borderColor = canReceive ? (hovered ? 'green' : 'red') : 'black' return connectDropTarget(
-

πŸ›’

+

+ + πŸ›’ + +

) } @@ -20,7 +24,7 @@ class Cart extends Component { const spec = { drop(props, monitor) { const { deleteItemByType } = props - deleteItemByType(monitor.getItem().uid) + deleteItemByType(monitor.getItem().uid, monitor.getItem().type) } } diff --git a/admin/src/components/events/drag-table-row.js b/admin/src/components/events/drag-table-row.js new file mode 100644 index 0000000..f19008b --- /dev/null +++ b/admin/src/components/events/drag-table-row.js @@ -0,0 +1,30 @@ +import React, { Component } from 'react' +import { DragSource } from 'react-dnd' + +class DragTableCell extends Component { + static propTypes = {} + + render() { + const { event, connectDragSource } = this.props + return ( +
+ {connectDragSource({event.title})} +
+ ) + } +} + +const spec = { + beginDrag(props) { + return { + uid: props.event.uid, + type: 'events' + } + } +} + +const collect = (connect, monitor) => ({ + connectDragSource: connect.dragSource() +}) + +export default DragSource('event', spec, collect)(DragTableCell) diff --git a/admin/src/components/events/selected-event-card.js b/admin/src/components/events/selected-event-card.js index 8e62585..e901cd5 100644 --- a/admin/src/components/events/selected-event-card.js +++ b/admin/src/components/events/selected-event-card.js @@ -1,5 +1,5 @@ import React, { Component } from 'react' -import { DropTarget, DragSource } from 'react-dnd' +import { DropTarget } from 'react-dnd' import { connect } from 'react-redux' import { addEventToPerson } from '../../ducks/people' diff --git a/admin/src/components/events/virtualized-lazy-table.js b/admin/src/components/events/virtualized-lazy-table.js index c309a0f..29669b3 100644 --- a/admin/src/components/events/virtualized-lazy-table.js +++ b/admin/src/components/events/virtualized-lazy-table.js @@ -8,6 +8,7 @@ import { eventListSelector } from '../../ducks/events' import { Table, Column, InfiniteLoader } from 'react-virtualized' +import DragTableCell from './drag-table-row' import 'react-virtualized/styles.css' export class EventLazyTable extends Component { @@ -39,7 +40,12 @@ export class EventLazyTable extends Component { onRowsRendered={onRowsRendered} rowClassName="test__event_table_row" > - + @@ -62,6 +68,10 @@ export class EventLazyTable extends Component { const { toggleSelection } = this.props toggleSelection && toggleSelection(rowData.uid) } + + cellRenderer = (props) => ( + + ) } export default connect( diff --git a/admin/src/components/people/person-card.js b/admin/src/components/people/person-card.js index df5bbe8..14abb66 100644 --- a/admin/src/components/people/person-card.js +++ b/admin/src/components/people/person-card.js @@ -26,6 +26,7 @@ const spec = { beginDrag(props) { return { uid: props.person.uid, + type: 'people', DragPreview } } diff --git a/admin/src/ducks/cart.js b/admin/src/ducks/cart.js index 183b142..21f345f 100644 --- a/admin/src/ducks/cart.js +++ b/admin/src/ducks/cart.js @@ -1,10 +1,7 @@ import { appName } from '../config' import { Record, OrderedMap } from 'immutable' -import { createSelector } from 'reselect' -import { put, call, all, takeEvery, select } from 'redux-saga/effects' -import { reset } from 'redux-form' +import { put, call, all, takeEvery } from 'redux-saga/effects' import firebase from 'firebase/app' -import { fbToEntities } from './utils' /** * Constants @@ -18,28 +15,16 @@ export const DELETE_ITEM_SUCCESS = `${prefix}/DELETE_ITEM_SUCCESS` * Reducer * */ const ReducerState = Record({ - entities: new OrderedMap({}) -}) - -const PersonRecord = Record({ - uid: null, - firstName: null, - lastName: null, - email: null, - events: [] + elements: new OrderedMap({}) }) export default function reducer(state = new ReducerState(), action) { - const { type, payload } = action + const { type } = action switch (type) { case DELETE_ITEM_SUCCESS: - // return state.updateIn( - // ['entities', payload.personUid, 'events'], - // (events) => [...new Set([...events, payload.eventUid])] - // ) + // ΠΌΠΎΠΆΠ½ΠΎ Π»ΠΈ ΠΏΡ€ΠΈ Π΄Π°Π½Π½ΠΎΠΌ ΠΏΠΎΠ΄Ρ…ΠΎΠ΄Π΅ ΠΏΡ€ΠΎΠΏΠ°Ρ‚Ρ‡ΠΈΡ‚ΡŒ список events ΠΈΠ»ΠΈ people? return state - default: return state } @@ -48,34 +33,15 @@ export default function reducer(state = new ReducerState(), action) { /** * Selectors * */ -export const stateSelector = (state) => state[moduleName] -export const entitiesSelector = createSelector( - stateSelector, - (state) => state.entities -) -export const peopleSelector = createSelector(entitiesSelector, (entities) => - entities.valueSeq().toArray() -) -export const idSelector = (_, props) => props.uid -export const personSelector = createSelector( - entitiesSelector, - idSelector, - (entities, uid) => entities.get(uid) -) - -export const personEventsSelector = createSelector( - personSelector, - (person) => person.events -) /** * Action Creators * */ -export function deleteItemByType(eventUid, personUid) { +export function deleteItemByType(itemUid, type) { return { type: DELETE_ITEM, - payload: { eventUid, personUid } + payload: { itemUid, type } } } @@ -84,12 +50,10 @@ export function deleteItemByType(eventUid, personUid) { */ export function* deleteItemByTypeSaga(action) { - // const { eventUid, personUid } = action.payload - // const eventsRef = firebase.database().ref(`people/${personUid}/events`) - // const events = yield select(personEventsSelector, { uid: personUid }) - // const nextPersonEvents = [...new Set([...events, eventUid])] - // - // yield call([eventsRef, eventsRef.set], nextPersonEvents) + const { itemUid, type } = action.payload + const itemRef = firebase.database().ref(`${type}/${itemUid}`) + + yield call([itemRef, itemRef.remove], '') yield put({ type: DELETE_ITEM_SUCCESS, diff --git a/admin/src/redux/reducer.js b/admin/src/redux/reducer.js index 7e88eca..30f86e2 100644 --- a/admin/src/redux/reducer.js +++ b/admin/src/redux/reducer.js @@ -4,11 +4,13 @@ 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' +import cartReducer, { moduleName as cartModule } from '../ducks/cart' export default combineReducers({ router, form, [authModule]: authReducer, [peopleModule]: peopleReducer, - [eventsModule]: eventsReducer + [eventsModule]: eventsReducer, + [cartModule]: cartReducer }) diff --git a/admin/src/redux/saga.js b/admin/src/redux/saga.js index 9d0ed64..07a5d42 100644 --- a/admin/src/redux/saga.js +++ b/admin/src/redux/saga.js @@ -2,7 +2,8 @@ import { all } from 'redux-saga/effects' import { saga as authSaga } from '../ducks/auth' import { saga as peopleSaga } from '../ducks/people' import { saga as eventsSaga } from '../ducks/events' +import { saga as cartSaga } from '../ducks/cart' export default function*() { - yield all([authSaga(), peopleSaga(), eventsSaga()]) + yield all([authSaga(), peopleSaga(), eventsSaga(), cartSaga()]) }