diff --git a/admin/src/components/events/events-table-virtualized.js b/admin/src/components/events/events-table-virtualized.js
index 272ce38..941effc 100644
--- a/admin/src/components/events/events-table-virtualized.js
+++ b/admin/src/components/events/events-table-virtualized.js
@@ -2,7 +2,7 @@ import React, { Component } from 'react'
import { connect } from 'react-redux'
import { Table, Column } from 'react-virtualized'
import {
- fetchAllEvents,
+ fetchLazyEvents,
selectEvent,
eventListSelector,
loadedSelector,
@@ -15,12 +15,12 @@ export class EventsTableVirtualized extends Component {
static propTypes = {}
componentDidMount() {
- this.props.fetchAllEvents()
+ this.props.fetchLazyEvents()
}
render() {
const { events, loading } = this.props
- if (loading) return
+ if (loading && !events.length) return
return (
@@ -43,6 +44,12 @@ export class EventsTableVirtualized extends Component {
rowGetter = ({ index }) => this.props.events[index]
handleSelect = ({ rowData }) => this.props.selectEvent(rowData.uid)
+
+ handleScroll = ({ stopIndex }) => {
+ if (stopIndex > this.props.events.length - 3) {
+ this.props.fetchLazyEvents()
+ }
+ }
}
export default connect(
@@ -51,5 +58,5 @@ export default connect(
loading: loadingSelector(state),
loaded: loadedSelector(state)
}),
- { fetchAllEvents, selectEvent }
+ { fetchLazyEvents, selectEvent }
)(EventsTableVirtualized)
diff --git a/admin/src/components/events/events-table-virtualized.test.js b/admin/src/components/events/events-table-virtualized.test.js
new file mode 100644
index 0000000..8c8060f
--- /dev/null
+++ b/admin/src/components/events/events-table-virtualized.test.js
@@ -0,0 +1,21 @@
+import React from 'react'
+import Enzyme, { shallow } from 'enzyme'
+import Adapter from 'enzyme-adapter-react-16'
+import { EventsTableVirtualized } from './events-table-virtualized'
+import Loader from '../common/loader'
+
+Enzyme.configure({ adapter: new Adapter() })
+
+describe('EventsTableVirtualized', () => {
+ it('should render a loader', () => {
+ const container = shallow(
+ {}} />
+ )
+
+ expect(container.contains()).toBe(true)
+ })
+
+ it('should fetch lazy events', (done) => {
+ shallow()
+ })
+})
diff --git a/admin/src/ducks/events.js b/admin/src/ducks/events.js
index 2718eed..d87ec01 100644
--- a/admin/src/ducks/events.js
+++ b/admin/src/ducks/events.js
@@ -10,10 +10,14 @@ import { fbToEntities } from './utils'
* */
export const moduleName = 'events'
const prefix = `${appName}/${moduleName}`
+const fetchLimit = 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_REQUEST = `${prefix}/FETCH_LAZY_REQUEST`
+export const FETCH_LAZY_START = `${prefix}/FETCH_LAZY_START`
+export const FETCH_LAZY_SUCCESS = `${prefix}/FETCH_LAZY_SUCCESS`
export const TOGGLE_SELECT = `${prefix}/TOGGLE_SELECT`
/**
@@ -49,6 +53,17 @@ export default function reducer(state = new ReducerRecord(), action) {
.set('loaded', true)
.set('entities', fbToEntities(payload, EventRecord))
+ case FETCH_LAZY_START:
+ return state.set('loading', true)
+
+ case FETCH_LAZY_SUCCESS: {
+ const loadedEntities = state.entities.size ? state.entities : null
+
+ return state
+ .set('loading', false)
+ .set('entities', fbToEntities(payload, EventRecord, loadedEntities))
+ }
+
case TOGGLE_SELECT:
return state.update(
'selected',
@@ -84,6 +99,11 @@ export const eventListSelector = createSelector(entitiesSelector, (entities) =>
entities.toArray()
)
+export const lastEventKeySelector = createSelector(
+ eventListSelector,
+ (events) => (events.length ? events[events.length - 1].uid : '')
+)
+
export const selectionSelector = createSelector(
stateSelector,
(state) => state.selected
@@ -106,6 +126,12 @@ export function fetchAllEvents() {
}
}
+export function fetchLazyEvents() {
+ return {
+ type: FETCH_LAZY_REQUEST
+ }
+}
+
export const selectEvent = (uid) => ({
type: TOGGLE_SELECT,
payload: { uid }
@@ -132,6 +158,30 @@ export function* fetchAllSaga() {
})
}
+export function* fetchLazySaga() {
+ const eventsState = yield select(stateSelector)
+ if (eventsState.loading) return
+
+ yield put({
+ type: FETCH_LAZY_START
+ })
+
+ const fetchStartAt = yield select(lastEventKeySelector)
+ const ref = firebase
+ .database()
+ .ref('events')
+ .orderByKey()
+ .limitToFirst(fetchLimit)
+ .startAt(fetchStartAt)
+ const snapshot = yield call([ref, ref.once], 'value')
+
+ yield put({
+ type: FETCH_LAZY_SUCCESS,
+ payload: snapshot.val()
+ })
+}
+
export function* saga() {
yield all([takeEvery(FETCH_ALL_REQUEST, fetchAllSaga)])
+ yield all([takeEvery(FETCH_LAZY_REQUEST, fetchLazySaga)])
}
diff --git a/admin/src/ducks/utils.js b/admin/src/ducks/utils.js
index eb16523..8b292f5 100644
--- a/admin/src/ducks/utils.js
+++ b/admin/src/ducks/utils.js
@@ -4,10 +4,17 @@ export function generateId() {
return Date.now() + Math.random()
}
-export function fbToEntities(values, DataRecord) {
- return new List(
+export function fbToEntities(values, DataRecord, initailValues) {
+ const newList = new List(
Object.entries(values).map(
([uid, value]) => new DataRecord({ uid, ...value })
)
)
+
+ // такой подход для этой утилиты ок? Или лучше выделить новую функцию?
+ if (initailValues) {
+ return new List(initailValues).concat(newList)
+ }
+
+ return newList
}