From 8c1c556677bb17dd163b0aa21abd8d44c888b4b5 Mon Sep 17 00:00:00 2001 From: Denis Date: Tue, 29 May 2018 21:45:10 +0000 Subject: [PATCH 1/2] add event to person in firebase --- admin/src/ducks/people.js | 35 +++++++++++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/admin/src/ducks/people.js b/admin/src/ducks/people.js index 40562f7..b392418 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' @@ -19,6 +19,8 @@ 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_START = `${prefix}/ADD_EVENT_START` +export const ADD_EVENT_SUCCESS = `${prefix}/ADD_EVENT_SUCCESS` /** * Reducer @@ -42,6 +44,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_SUCCESS: + return state.updateIn( + ['entities', payload.personUid, 'events'], + (events) => [...events, payload.eventUid] + ) + case FETCH_ALL_SUCCESS: return state.set('entities', fbToEntities(payload, PersonRecord)) @@ -67,6 +75,10 @@ export const personSelector = createSelector( idSelector, (entities, uid) => entities.get(uid) ) +export const personEventsSelector = createSelector( + personSelector, + (person) => person.events +) /** * Action Creators @@ -125,9 +137,28 @@ export function* fetchAllSaga() { }) } +export function* addEventToPersonSaga({ payload: { eventUid, personUid } }) { + yield put({ + type: ADD_EVENT_START, + payload: { eventUid, personUid } + }) + + const eventsRef = firebase.database().ref(`people/${personUid}/events`) + + const events = yield select(personEventsSelector, { uid: personUid }) + + yield call([eventsRef, eventsRef.set], [...events, eventUid]) + + yield put({ + type: ADD_EVENT_SUCCESS, + payload: { eventUid, personUid } + }) +} + export const saga = function*() { yield all([ takeEvery(ADD_PERSON, addPersonSaga), - takeEvery(FETCH_ALL_REQUEST, fetchAllSaga) + takeEvery(FETCH_ALL_REQUEST, fetchAllSaga), + takeEvery(ADD_EVENT, addEventToPersonSaga) ]) } From 66aec5f502d750a399186dbf80ffaea820fdbbb8 Mon Sep 17 00:00:00 2001 From: Denis Date: Tue, 29 May 2018 22:37:00 +0000 Subject: [PATCH 2/2] delete events and people with dnd --- admin/src/components/common/trash.js | 43 +++++++++++++++++++ .../components/events/draggable-table-row.js | 19 ++++++++ .../events/virtualized-lazy-table.js | 4 ++ admin/src/ducks/events.js | 36 +++++++++++++++- admin/src/ducks/people.js | 31 +++++++++++++ admin/src/routes/events-page.js | 2 + 6 files changed, 134 insertions(+), 1 deletion(-) create mode 100644 admin/src/components/common/trash.js create mode 100644 admin/src/components/events/draggable-table-row.js diff --git a/admin/src/components/common/trash.js b/admin/src/components/common/trash.js new file mode 100644 index 0000000..2f9624f --- /dev/null +++ b/admin/src/components/common/trash.js @@ -0,0 +1,43 @@ +import React, { Component } from 'react' +import { DropTarget } from 'react-dnd' +import { connect } from 'react-redux' +import { deletePerson } from '../../ducks/people' +import { deleteEvent } from '../../ducks/events' + +const style = { + position: 'fixed', + top: 0, + right: 0, + fontSize: '10em' +} + +class Trash extends Component { + render() { + const { connectDropTarget } = this.props + return connectDropTarget(
🗑
) + } +} + +const spec = { + drop(props, monitor) { + const { deletePerson, deleteEvent } = props + const itemType = monitor.getItemType() + const uid = monitor.getItem().uid + + if (itemType === 'person') { + deletePerson(uid) + } + + if (itemType === 'event') { + deleteEvent(uid) + } + } +} + +const collect = (connect) => ({ + connectDropTarget: connect.dropTarget() +}) + +export default connect(null, { deletePerson, deleteEvent })( + DropTarget(['person', 'event'], spec, collect)(Trash) +) diff --git a/admin/src/components/events/draggable-table-row.js b/admin/src/components/events/draggable-table-row.js new file mode 100644 index 0000000..4435368 --- /dev/null +++ b/admin/src/components/events/draggable-table-row.js @@ -0,0 +1,19 @@ +import { DragSource } from 'react-dnd' +import { defaultTableRowRenderer } from 'react-virtualized' + +const DraggableTableRow = ({ connectDragSource, ...props }) => + connectDragSource(defaultTableRowRenderer(props)) + +const spec = { + beginDrag(props) { + return { + uid: props.rowData.uid + } + } +} + +const collect = (connect, monitor) => ({ + connectDragSource: connect.dragSource() +}) + +export default DragSource('event', spec, collect)(DraggableTableRow) diff --git a/admin/src/components/events/virtualized-lazy-table.js b/admin/src/components/events/virtualized-lazy-table.js index c309a0f..818a0bd 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 DraggableTableRow from './draggable-table-row' import 'react-virtualized/styles.css' export class EventLazyTable extends Component { @@ -38,6 +39,7 @@ export class EventLazyTable extends Component { onRowClick={this.handleRowClick} onRowsRendered={onRowsRendered} rowClassName="test__event_table_row" + rowRenderer={this.rowRenderer} > @@ -48,6 +50,8 @@ export class EventLazyTable extends Component { ) } + rowRenderer = (props) => + isRowLoaded = ({ index }) => index < this.props.events.length loadMoreRows = () => { diff --git a/admin/src/ducks/events.js b/admin/src/ducks/events.js index 0fd43e7..72984ca 100644 --- a/admin/src/ducks/events.js +++ b/admin/src/ducks/events.js @@ -21,6 +21,10 @@ export const FETCH_LAZY_SUCCESS = `${prefix}/FETCH_LAZY_SUCCESS` export const TOGGLE_SELECTION = `${prefix}/TOGGLE_SELECTION` +export const DELETE_EVENT = `${prefix}/DELETE_EVENT` +export const DELETE_EVENT_START = `${prefix}/DELETE_EVENT_START` +export const DELETE_EVENT_SUCCESS = `${prefix}/DELETE_EVENT_SUCCESS` + /** * Reducer * */ @@ -70,6 +74,9 @@ export default function reducer(state = new ReducerRecord(), action) { : selected.add(payload.uid) ) + case DELETE_EVENT_SUCCESS: + return state.deleteIn(['entities', payload.uid]) + default: return state } @@ -129,6 +136,13 @@ export function fetchLazy() { } } +export function deleteEvent(uid) { + return { + type: DELETE_EVENT, + payload: { uid } + } +} + /** * Sagas * */ @@ -179,6 +193,26 @@ export const fetchLazySaga = function*() { } } +export function* deleteEventSaga({ payload: { uid } }) { + yield put({ + type: DELETE_EVENT_START, + payload: { uid } + }) + + const eventRef = firebase.database().ref(`events/${uid}`) + + yield call([eventRef, eventRef.remove]) + + yield put({ + type: DELETE_EVENT_SUCCESS, + payload: { uid } + }) +} + export function* saga() { - yield all([takeEvery(FETCH_ALL_REQUEST, fetchAllSaga), fetchLazySaga()]) + yield all([ + takeEvery(FETCH_ALL_REQUEST, fetchAllSaga), + fetchLazySaga(), + takeEvery(DELETE_EVENT, deleteEventSaga) + ]) } diff --git a/admin/src/ducks/people.js b/admin/src/ducks/people.js index b392418..b3d3dc7 100644 --- a/admin/src/ducks/people.js +++ b/admin/src/ducks/people.js @@ -15,6 +15,10 @@ export const ADD_PERSON = `${prefix}/ADD_PERSON` export const ADD_PERSON_START = `${prefix}/ADD_PERSON_START` export const ADD_PERSON_SUCCESS = `${prefix}/ADD_PERSON_SUCCESS` +export const DELETE_PERSON = `${prefix}/DELETE_PERSON` +export const DELETE_PERSON_START = `${prefix}/DELETE_PERSON_START` +export const DELETE_PERSON_SUCCESS = `${prefix}/DELETE_PERSON_SUCCESS` + export const FETCH_ALL_REQUEST = `${prefix}/FETCH_ALL_REQUEST` export const FETCH_ALL_SUCCESS = `${prefix}/FETCH_ALL_SUCCESS` @@ -44,6 +48,9 @@ export default function reducer(state = new ReducerState(), action) { case ADD_PERSON_SUCCESS: return state.setIn(['entities', payload.uid], new PersonRecord(payload)) + case DELETE_PERSON_SUCCESS: + return state.deleteIn(['entities', payload.uid]) + case ADD_EVENT_SUCCESS: return state.updateIn( ['entities', payload.personUid, 'events'], @@ -91,6 +98,13 @@ export function addPerson(person) { } } +export function deletePerson(uid) { + return { + type: DELETE_PERSON, + payload: { uid } + } +} + export function fetchAllPeople() { return { type: FETCH_ALL_REQUEST @@ -126,6 +140,22 @@ export function* addPersonSaga(action) { yield put(reset('person')) } +export function* deletePersonSaga({ payload: { uid } }) { + yield put({ + type: DELETE_PERSON_START, + payload: { uid } + }) + + const personRef = firebase.database().ref(`people/${uid}`) + + yield call([personRef, personRef.remove]) + + yield put({ + type: DELETE_PERSON_SUCCESS, + payload: { uid } + }) +} + export function* fetchAllSaga() { const peopleRef = firebase.database().ref('people') @@ -158,6 +188,7 @@ export function* addEventToPersonSaga({ payload: { eventUid, personUid } }) { export const saga = function*() { yield all([ takeEvery(ADD_PERSON, addPersonSaga), + takeEvery(DELETE_PERSON, deletePersonSaga), takeEvery(FETCH_ALL_REQUEST, fetchAllSaga), takeEvery(ADD_EVENT, addEventToPersonSaga) ]) diff --git a/admin/src/routes/events-page.js b/admin/src/routes/events-page.js index d893d20..d9373b4 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 Trash from '../components/common/trash' class EventsPage extends Component { static propTypes = {} @@ -12,6 +13,7 @@ class EventsPage extends Component { + ) }