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
181 changes: 181 additions & 0 deletions admin/src/components/events/events-table-virtualized-lazy-loading.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
import React, { Component } from 'react'
import { connect } from 'react-redux'
import {
fetchEventsWithPagination,
toggleSelection as handleSelect,
eventListSelector,
loadedSelector,
loadingSelector,
loadedRowCount,
loadingRowCount,
loadedRowsMap,
clearData,
changeLoadingInfo
} from '../../ducks/events'
import Loader from '../common/loader'
import { InfiniteLoader, AutoSizer, List } from 'react-virtualized'
import 'react-virtualized/styles.css'

export const width = 900
export const columnWidth = 300
export const height = 420
export const rowHeight = 40

const STATUS_LOADING = 1
const STATUS_LOADED = 2

export class EventsTable extends Component {
// state = {
// // loadedRowCount: 0,
// loadedRowsMap: {}
// // loadingRowCount: 0
// }
static propTypes = {}

componentDidMount() {
this.props.fetchEventsWithPagination &&
this.props.fetchEventsWithPagination()
}

componentWillUnmount() {
Object.keys(this.timeoutIdMap).forEach((timeoutId) => {
clearTimeout(timeoutId)
})
}

render() {
const {
loading,
// loaded,
events,
clearData,
loadedRowCount,
loadingRowCount
} = this.props

return (
<div>
<div>
<button onClick={clearData}>Flush Cached Data</button>
<br />
<br />

<div>
{loadingRowCount} loading, {loadedRowCount} loaded
</div>
<br />
<hr />
</div>
{loading && !loadedRowCount ? (
<Loader />
) : (
<InfiniteLoader
isRowLoaded={this.isRowLoaded}
loadMoreRows={this.loadMoreRows}
rowCount={events.length}
>
{({ onRowsRendered, registerChild }) => (
<AutoSizer disableHeight>
{({ width }) => (
<List
ref={registerChild}
height={height}
onRowsRendered={onRowsRendered}
rowCount={events.length}
rowHeight={rowHeight}
rowRenderer={this.rowRenderer}
width={width}
/>
)}
</AutoSizer>
)}
</InfiniteLoader>
)}
</div>
)
}

handleRowClick = (event) => () => {
this.props.handleSelect(event.uid)
}

timeoutIdMap = () => {}

isRowLoaded = ({ index }) => {
const { loadedRowsMap } = this.props
return !!loadedRowsMap[index] // STATUS_LOADING or STATUS_LOADED
}

loadMoreRows = ({ startIndex, stopIndex }) => {
const { loadedRowsMap, loadingRowCount } = this.props
const increment = stopIndex - startIndex + 1

for (var i = startIndex; i <= stopIndex; i++) {
loadedRowsMap[i] = STATUS_LOADING
}

this.props.changeLoadingInfo({
loadingRowCount: loadingRowCount + increment
})

const timeoutId = setTimeout(() => {
const { loadedRowCount, loadingRowCount } = this.props
delete this.timeoutIdMap[timeoutId]

for (var i = startIndex; i <= stopIndex; i++) {
loadedRowsMap[i] = STATUS_LOADED
}

this.props.changeLoadingInfo({
loadingRowCount: loadingRowCount - increment,
loadedRowCount: loadedRowCount + increment
})

promiseResolver({
size: loadingRowCount,
startAt: startIndex,
endAt: stopIndex
})
}, 1000 + Math.round(Math.random() * 2000))

this.timeoutIdMap[timeoutId] = true

let promiseResolver

return new Promise((resolve) => {
promiseResolver = (pagination) =>
resolve(this.props.fetchEventsWithPagination(pagination))
})
}

rowRenderer = ({ index, key, style }) => {
const { events, loadedRowsMap } = this.props

const row = events[index]
let content

if (loadedRowsMap[index] === STATUS_LOADED) {
content = row.title
} else {
content = <div style={{ width: 100 }} />
}

return (
<div key={key} style={style} onClick={this.handleRowClick(row)}>
{content}
</div>
)
}
}

export default connect(
(state) => ({
events: eventListSelector(state),
loading: loadingSelector(state),
loaded: loadedSelector(state),
loadedRowCount: loadedRowCount(state),
loadingRowCount: loadingRowCount(state),
loadedRowsMap: loadedRowsMap(state)
}),
{ fetchEventsWithPagination, handleSelect, clearData, changeLoadingInfo }
)(EventsTable)
32 changes: 26 additions & 6 deletions admin/src/components/events/events-table-virtualized.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@ import Loader from '../common/loader'
import { Table, Column } from 'react-virtualized'
import 'react-virtualized/styles.css'

export const width = 900
export const columnWidth = 300
export const height = 420
export const rowHeight = 40

export class EventsTable extends Component {
static propTypes = {}

Expand All @@ -24,20 +29,35 @@ export class EventsTable extends Component {
return (
<Table
rowCount={events.length}
width={400}
height={300}
width={width}
height={height}
rowGetter={this.rowGetter}
rowHeight={50}
rowHeight={rowHeight}
overscanRowCount={0}
>
<Column dataKey="title" width={300} />
<Column dataKey="where" width={300} />
<Column dataKey="when" width={300} />
<Column
cellRenderer={({ cellData, rowData }) => (
<div
className="test--event-list_item"
onClick={this.handleRowClick(rowData)}
>
{cellData}
</div>
)}
dataKey="title"
width={columnWidth}
/>
<Column dataKey="where" width={columnWidth} />
<Column dataKey="when" width={columnWidth} />
</Table>
)
}

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

handleRowClick = (event) => () => {
this.props.handleSelect(event.uid)
}
}

export default connect(
Expand Down
75 changes: 75 additions & 0 deletions admin/src/components/events/events-table-virtualized.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import React from 'react'
import {
EventsTable,
width,
height,
rowHeight,
columnWidth
} from './events-table-virtualized'
import { shallow, mount } from 'enzyme'
import { Table, Column } from 'react-virtualized'

import Loader from '../common/loader'
import eventsMocks from '../../mocks/conferences'

const defaultOverscanRowCount = 1

const events = eventsMocks.map((event) => ({
...event,
uid: Math.random().toString()
}))

describe('EventsVirtualizedTable', () => {
it('should render loader', () => {
const container = shallow(<EventsTable events={[]} loading />)

expect(container.contains(<Loader />)).toBe(true)
})

it('should render visible events', () => {
const container = mount(<EventsTable events={events} />)

expect(container.find('.test--event-list_item').length).toEqual(
Math.round(height / rowHeight) + defaultOverscanRowCount
)
})

it('should render 3 colunms', () => {
const container = shallow(<EventsTable events={events} />)

expect(container.children().length).toEqual(3)
})

it('should render first column with key title', () => {
const container = shallow(<EventsTable events={events} />)

expect(
container
.children()
.find({ dataKey: 'title' })
.exists()
).toEqual(true)
})

it('should fetch all events', (done) => {
shallow(<EventsTable events={[]} fetchAllEvents={() => done()} />)
})

it('should select an event', () => {
let selectedEventId = null

const container = mount(
<EventsTable
events={events}
handleSelect={(id) => (selectedEventId = id)}
/>
)

container
.find('.test--event-list_item')
.first()
.simulate('click')

expect(selectedEventId).toEqual(events[0].uid)
})
})
16 changes: 0 additions & 16 deletions admin/src/config.js

This file was deleted.

Loading