Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,15 @@
build
build-dev
build-tmp
node_modules
*.log
*.lock
*.rar
*.zip
.idea
.vscode
.project
org.eclipse*
.settings
.DS_Store
Thumbs.db
19,757 changes: 19,757 additions & 0 deletions admin/package-lock.json

Large diffs are not rendered by default.

25 changes: 20 additions & 5 deletions admin/src/components/events/selected-events-list.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,34 @@
import React, { Component } from 'react'
import { connect } from 'react-redux'
import { List } from 'react-virtualized'
import { selectedEventsSelector } from '../../ducks/events'
import SelectedEventCard from './selected-event-card'
import 'react-virtualized/styles.css'

class SelectedEventsList extends Component {
static propTypes = {}

render() {
return <div>{this.eventList()}</div>
const { events } = this.props

return (
<List
width={400}
height={200}
rowCount={events.length}
rowHeight={100}
rowRenderer={this.getRow}
/>
)
}

eventList = () =>
this.props.events.map((event) => (
<SelectedEventCard key={event.id} event={event} />
))
getRow = ({ index, key, style }) => (
<SelectedEventCard
key={key}
event={this.props.events[index]}
style={style}
/>
)
}

export default connect((state) => ({
Expand Down
33 changes: 2 additions & 31 deletions admin/src/components/events/virtualized-events-table.js
Original file line number Diff line number Diff line change
@@ -1,53 +1,24 @@
import React, { Component } from 'react'
import { connect } from 'react-redux'
import { Table, Column } from 'react-virtualized'
import {
fetchAllEvents,
toggleSelection,
eventListSelector,
loadedSelector,
loadingSelector
} from '../../ducks/events'
import Loader from '../common/loader'
import 'react-virtualized/styles.css'

export class VirtualizedEventsTable extends Component {
static propTypes = {}

componentDidMount() {
this.props.fetchAllEvents()
}

render() {
const { loading, events } = this.props
if (loading) return <Loader />
return (
<Table
width={600}
height={500}
rowHeight={40}
headerHeight={60}
rowClassName="table-events"
overscanRowCount={5}
rowCount={events.length}
rowGetter={this.rowGetter}
onRowClick={this.handleClick}
{...this.props}
>
<Column dataKey="title" label="Title" width={300} />
<Column dataKey="where" label="Where" width={300} />
<Column dataKey="when" label="When" width={300} />
</Table>
)
}

rowGetter = ({ index }) => this.props.events[index]
handleClick = ({ rowData }) => this.props.toggleSelection(rowData.id)
}

export default connect(
(state) => ({
events: eventListSelector(state),
loading: loadingSelector(state),
loaded: loadedSelector(state)
}),
{ fetchAllEvents, toggleSelection }
)(VirtualizedEventsTable)
22 changes: 22 additions & 0 deletions admin/src/components/events/virtualized-events-table.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import React from 'react'
import Enzyme, { render } from 'enzyme'
import { VirtualizedEventsTable } from './virtualized-events-table'
import Adapter from 'enzyme-adapter-react-16'

Enzyme.configure({ adapter: new Adapter() })

describe('Virtualized events table', () => {
it('Should render some columns', () => {
const countElements = 15
const container = render(
<VirtualizedEventsTable
rowCount={countElements}
rowGetter={() => {
return {}
}}
/>
)

expect(container.find('.table-events').length).toEqual(countElements + 1)
})
})
61 changes: 61 additions & 0 deletions admin/src/components/events/virtualized-lazy-events-table.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import React, { Component } from 'react'
import { connect } from 'react-redux'
import { InfiniteLoader } from 'react-virtualized'
import {
fetchAllEvents,
toggleSelection,
eventListSelector,
loadedSelector,
loadingSelector,
fetchLazyEvents
} from '../../ducks/events'
import Loader from '../common/loader'
import 'react-virtualized/styles.css'
import { VirtualizedEventsTable } from './virtualized-events-table'

class VirtualizedLazyEvents extends Component {
componentDidMount() {
this.props.fetchAllEvents()
}

render() {
const { loading, events } = this.props
if (loading) return <Loader />

return (
<InfiniteLoader
isRowLoaded={this.getStateRow}
loadMoreRows={this.getMoreRows}
rowCount={events.length}
>
{({ onRowsRendered, registerChild }) => (
<VirtualizedEventsTable
onRowsRendered={onRowsRendered}
ref={registerChild}
rowCount={events.length}
rowGetter={this.rowGetter}
onRowClick={this.handleClick}
/>
)}
</InfiniteLoader>
)
}

getStateRow = ({ index }) => index < this.props.events.length

getMoreRows = ({ startIndex, stopIndex }) =>
this.props.fetchLazyEvents(stopIndex)

rowGetter = ({ index }) => this.props.events[index]

handleClick = ({ rowData }) => this.props.toggleSelection(rowData.id)
}

export default connect(
(state) => ({
events: eventListSelector(state),
loading: loadingSelector(state),
loaded: loadedSelector(state)
}),
{ fetchAllEvents, toggleSelection, fetchLazyEvents }
)(VirtualizedLazyEvents)
4 changes: 2 additions & 2 deletions admin/src/components/routes/admin/events-page.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React, { Component } from 'react'
import EventsTable from '../../events/virtualized-events-table'
import VirtualizedLazyEvents from '../../events/virtualized-lazy-events-table'
import SelectedEventsList from '../../events/selected-events-list'

class EventsPage extends Component {
Expand All @@ -9,7 +9,7 @@ class EventsPage extends Component {
return (
<div>
<SelectedEventsList />
<EventsTable />
<VirtualizedLazyEvents />
</div>
)
}
Expand Down
46 changes: 44 additions & 2 deletions admin/src/ducks/events.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { all, takeEvery, put, call } from 'redux-saga/effects'
import { all, takeEvery, put, call, select } from 'redux-saga/effects'
import { appName } from '../config'
import { Record, List, OrderedSet } from 'immutable'
import { createSelector } from 'reselect'
Expand All @@ -15,6 +15,10 @@ export const FETCH_ALL_REQUEST = `${prefix}/FETCH_ALL_REQUEST`
export const FETCH_ALL_START = `${prefix}/FETCH_ALL_START`
export const FETCH_ALL_SUCCESS = `${prefix}/FETCH_ALL_SUCCESS`

export const FETCH_LAZY_EVENTS_REQUEST = `${prefix}/FETCH_LAZY_EVENTS_REQUEST`
export const FETCH_LAZY_START = `${prefix}/FETCH_LAZY_START`
export const FETCH_LAZY_SUCCESS = `${prefix}/FETCH_LAZY_SUCCESS`

export const TOGGLE_SELECTION = `${prefix}/TOGGLE_SELECTION`

/**
Expand All @@ -23,6 +27,7 @@ export const TOGGLE_SELECTION = `${prefix}/TOGGLE_SELECTION`
export const ReducerRecord = Record({
loading: false,
loaded: false,
eventsLoaded: false,
selected: new OrderedSet([]),
entities: new List([])
})
Expand All @@ -43,12 +48,18 @@ export default function reducer(state = new ReducerRecord(), action) {
switch (type) {
case FETCH_ALL_START:
return state.set('loading', true)
case FETCH_LAZY_START:
return state.set('eventsLoaded', false)

case FETCH_ALL_SUCCESS:
return state
.set('loading', false)
.set('loaded', true)
.set('entities', fbToEntities(payload, EventRecord))
case FETCH_LAZY_SUCCESS:
return state
.set('eventsLoaded', true)
.mergeIn(['entities'], fbToEntities(payload, EventRecord))

case TOGGLE_SELECTION:
return state.update('selected', (selected) =>
Expand Down Expand Up @@ -113,6 +124,13 @@ export function toggleSelection(id) {
}
}

export function fetchLazyEvents(id) {
return {
type: FETCH_LAZY_EVENTS_REQUEST,
payload: { id }
}
}

/**
* Sagas
* */
Expand All @@ -130,6 +148,30 @@ export function* fetchAllSaga() {
})
}

export function* fetchLazySaga() {
const state = yield select(stateSelector)

if (state.loading || state.loaded) return

yield put({
type: FETCH_LAZY_START
})

const lastElements = state.entities.last()
const events = yield call(
api.fetchCountEvents,
lastElements && lastElements.id
)

yield put({
type: FETCH_LAZY_SUCCESS,
payload: events
})
}

export function* saga() {
yield all([takeEvery(FETCH_ALL_REQUEST, fetchAllSaga)])
yield all([
takeEvery(FETCH_ALL_REQUEST, fetchAllSaga),
takeEvery(FETCH_LAZY_EVENTS_REQUEST, fetchLazySaga)
])
}
9 changes: 9 additions & 0 deletions admin/src/services/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,15 @@ class ApiService {
.collection('events')
.get()
.then((res) => res.docs.map((doc) => doc.data()))

fetchCountEvents = (lastId = '', limit = 15) =>
this.fb
.firestore()
.collection('events')
.limitToFirst(limit)
.startAt(lastId)
.get()
.then((res) => res.docs.map((doc) => doc.data()))
}

export default new ApiService()