-
{input.name}
+
+ {input.name}
{errorText}
diff --git a/src/components/common/ProtectedRoute.js b/src/components/common/ProtectedRoute.js
index da53475..5f23add 100644
--- a/src/components/common/ProtectedRoute.js
+++ b/src/components/common/ProtectedRoute.js
@@ -1,7 +1,7 @@
import React, { Component } from 'react'
import {Route} from 'react-router-dom'
import {connect} from 'react-redux'
-import {userSelector} from '../../ducks/auth'
+import {userAuthorizedSelector} from '../../ducks/auth'
class ProtectedRoute extends Component {
static propTypes = {
@@ -21,5 +21,5 @@ class ProtectedRoute extends Component {
}
export default connect(state => ({
- authorized: !!userSelector(state)
-}), null, null, { pure: false })(ProtectedRoute)
\ No newline at end of file
+ authorized: userAuthorizedSelector(state)
+}), null, null, { pure: false })(ProtectedRoute)
diff --git a/src/components/common/Submenu.js b/src/components/common/Submenu.js
new file mode 100644
index 0000000..370f97e
--- /dev/null
+++ b/src/components/common/Submenu.js
@@ -0,0 +1,30 @@
+import React, { Component } from 'react'
+import { NavLink } from 'react-router-dom'
+
+class Submenu extends Component {
+ render() {
+ return (
+
+ {this.props.links.map(this.renderSubmenuItem.bind(this))}
+
+ )
+ }
+
+ renderSubmenuItem(item, index) {
+ const { to, title } = item
+
+ const props = {
+ key: index,
+ activeClassName: 'active',
+ to,
+ }
+
+ return (
+
+ {title}
+
+ )
+ }
+}
+
+export default Submenu
diff --git a/src/components/events/EventTableVirtualized2.js b/src/components/events/EventTableVirtualized2.js
new file mode 100644
index 0000000..4681059
--- /dev/null
+++ b/src/components/events/EventTableVirtualized2.js
@@ -0,0 +1,83 @@
+import React, { Component } from 'react'
+import {Table, Column, InfiniteLoader} from 'react-virtualized'
+import {connect} from 'react-redux'
+import {
+ fetchUpTo,
+ loadedEventCountSelector,
+ loadedEventSelector,
+} from '../../ducks/events2'
+// import Loader from '../common/Loader'
+import 'react-virtualized/styles.css'
+
+class EventTableVirtualized extends Component {
+ render() {
+ const { loadedEventCount } = this.props;
+
+ const props = {
+ isRowLoaded: index => index < loadedEventCount,
+ loadMoreRows: ({stopIndex}) => {
+ return new Promise(resolve => {
+ this.props.fetchUpTo(stopIndex, resolve)
+ })
+ },
+ rowCount: 596,
+ // minimumBatchSize: 100,
+ // threshold: 100,
+ }
+
+ return (
+
+ {({onRowsRendered, registerChild}) => {
+ return (
+ this.props.selectEvent(rowData.uid)}
+ onRowsRendered={onRowsRendered}
+ ref={registerChild}
+ >
+
+
+
+
+ )
+ }}
+
+ )
+ }
+
+ rowGetter = ({ index }) => {
+ const { loadedEvents=[] } = this.props
+
+ if (!loadedEvents[index]) {
+ return {}
+ }
+
+ return this.props.loadedEvents[index]
+ }
+}
+
+export default connect(state => ({
+ loadedEventCount: loadedEventCountSelector(state),
+ loadedEvents: loadedEventSelector(state),
+}), {
+ fetchUpTo,
+})(EventTableVirtualized)
diff --git a/src/components/routes/Auth.js b/src/components/routes/Auth.js
index ec4898e..a8abf42 100644
--- a/src/components/routes/Auth.js
+++ b/src/components/routes/Auth.js
@@ -1,5 +1,5 @@
import React, { Component } from 'react'
-import {Route, NavLink} from 'react-router-dom'
+import {Route} from 'react-router-dom'
import {connect} from 'react-redux'
import {signUp, signIn} from '../../ducks/auth'
import SignIn from '../auth/SignIn'
@@ -14,8 +14,6 @@ class AuthPage extends Component {
return (
Auth page
- sign in
- sign up
}/>
}/>
@@ -26,4 +24,4 @@ class AuthPage extends Component {
handleSignUp = ({email, password}) => this.props.signUp(email, password)
}
-export default connect(null, { signUp, signIn })(AuthPage)
\ No newline at end of file
+export default connect(null, { signUp, signIn })(AuthPage)
diff --git a/src/components/routes/EventsPage2.js b/src/components/routes/EventsPage2.js
new file mode 100644
index 0000000..1d59511
--- /dev/null
+++ b/src/components/routes/EventsPage2.js
@@ -0,0 +1,18 @@
+import React, { Component } from 'react'
+import EventsTable2 from '../events/EventTableVirtualized2'
+
+class EventsPage2 extends Component {
+ static propTypes = {
+
+ };
+
+ render() {
+ return (
+
+ { }
+
+ )
+ }
+}
+
+export default EventsPage2
\ No newline at end of file
diff --git a/src/config.js b/src/config.js
index 2782a0b..6ce5a80 100644
--- a/src/config.js
+++ b/src/config.js
@@ -1,12 +1,12 @@
import firebase from 'firebase'
-export const appName = 'advreact-1610'
+export const appName = 'advreact-1610-9cb0c'
firebase.initializeApp({
- apiKey: "AIzaSyB31xpTtp4Jln_hb2kAbE4PGf6Mi8EgLyA",
+ apiKey: "AIzaSyBNaOQkLL75ZGoeaNtqbe63wEjjWLzLOPY",
authDomain: `${appName}.firebaseapp.com`,
databaseURL: `https://${appName}.firebaseio.com`,
projectId: appName,
storageBucket: "",
- messagingSenderId: "397157634637"
+ messagingSenderId: "266748171955"
})
\ No newline at end of file
diff --git a/src/ducks/auth.js b/src/ducks/auth.js
index 30c4e2e..cf2191a 100644
--- a/src/ducks/auth.js
+++ b/src/ducks/auth.js
@@ -51,6 +51,7 @@ export default function reducer(state = new ReducerRecord(), action) {
export const stateSelector = state => state[moduleName]
export const userSelector = createSelector(stateSelector, state => state.user)
+export const userAuthorizedSelector = createSelector(stateSelector, state => !!state.user)
/**
* Action Creators
@@ -130,7 +131,7 @@ export function * watchStatusChangeSaga() {
while (true) {
yield take(SIGN_IN_SUCCESS)
- yield (put(replace('/events')))
+ yield (put(replace('/events2')))
}
}
@@ -140,4 +141,4 @@ export function * saga() {
signInSaga(),
watchStatusChangeSaga()
])
-}
\ No newline at end of file
+}
diff --git a/src/ducks/events2.js b/src/ducks/events2.js
new file mode 100644
index 0000000..65dbebf
--- /dev/null
+++ b/src/ducks/events2.js
@@ -0,0 +1,116 @@
+import {all, takeEvery, put, call, select} from 'redux-saga/effects'
+import {Record, OrderedMap, OrderedSet} from 'immutable'
+import firebase from 'firebase'
+import {createSelector} from 'reselect'
+import {appName} from '../config'
+import {fbToEntities} from './utils'
+
+/**
+ * Constants
+ * */
+export const moduleName = 'events'
+const prefix = `${appName}/${moduleName}`
+
+export const FETCH_UP_TO_REQUEST = `${prefix}/FETCH_UP_TO_REQUEST`
+export const FETCH_UP_TO_SUCCESS = `${prefix}/FETCH_UP_TO_SUCCESS`
+
+
+
+/**
+ * Reducer
+ * */
+
+export const ReducerRecord = Record({
+ loading: false,
+ loaded: false,
+ entities: new OrderedMap({}),
+ selected: new OrderedSet([])
+})
+
+export const EventRecord = Record({
+ uid: null,
+ month: null,
+ submissionDeadline: null,
+ title: null,
+ url: null,
+ when: null,
+ where: null
+})
+
+export default function reducer(state=new ReducerRecord(), action) {
+ const { type, payload } = action
+
+ switch (type) {
+ case FETCH_UP_TO_REQUEST:
+ return state.set('loading', true)
+
+ case FETCH_UP_TO_SUCCESS: {
+ let newEntities = fbToEntities(payload.entities, EventRecord)
+
+ return state
+ .set('loading', false)
+ .set('entities', state.get('entities').merge(newEntities))
+ }
+
+ default:
+ return state
+ }
+}
+
+
+/**
+ * Action creators
+ * */
+
+export function fetchUpTo(requestedNumber, resolve) {
+ return {
+ type: FETCH_UP_TO_REQUEST,
+ payload: {requestedNumber, resolve},
+ }
+}
+
+/**
+ * Selectors
+ * */
+
+export const stateSelector = state => state[moduleName]
+export const loadedEventSelector = createSelector(stateSelector, state => state.get('entities').toArray())
+export const loadedEventKyesSelector = createSelector(loadedEventSelector, loadedEvents => loadedEvents.map(item => item.uid))
+export const loadedEventCountSelector = createSelector(loadedEventSelector, loadedEvents => loadedEvents.length)
+export const lastLoadedEventSelector = createSelector(loadedEventSelector, loadedEventCountSelector, (loadedEvents, loadedEventCount) => loadedEvents[loadedEventCount - 1] || {})
+export const lastLoadedEventUidSelector = createSelector(lastLoadedEventSelector, lastLoadedEvent => lastLoadedEvent.uid || '')
+
+/**
+ * Sagas
+ * */
+
+export function* fetchUpToSaga(action) {
+ const eventsRef = firebase.database().ref('events')
+ const loadedCount = yield select(loadedEventCountSelector)
+ const lastLoadedEventUid = yield select(lastLoadedEventUidSelector)
+ const { requestedNumber, resolve } = action.payload
+
+ if (loadedCount >= requestedNumber) {
+ return call(resolve)
+ }
+
+ const chunkCount = requestedNumber - loadedCount
+ const query1 = yield call([eventsRef, eventsRef.orderByKey])
+ const query2 = yield call([query1, query1.limitToFirst], chunkCount)
+ const query3 = yield call([query2, query2.startAt], lastLoadedEventUid || '')
+ const snapshot = yield call([query3, query3.once], 'value')
+ const entities = snapshot.val()
+
+ yield put({
+ type: FETCH_UP_TO_SUCCESS,
+ payload: {entities},
+ })
+
+ return call(resolve)
+}
+
+export function* saga() {
+ yield all([
+ takeEvery(FETCH_UP_TO_REQUEST, fetchUpToSaga),
+ ])
+}
diff --git a/src/ducks/saga.js b/src/ducks/saga.js
new file mode 100644
index 0000000..b950cab
--- /dev/null
+++ b/src/ducks/saga.js
@@ -0,0 +1,3 @@
+export function* helloSaga() {
+ console.log('Hello Sagas!')
+}
diff --git a/src/redux/index.js b/src/redux/index.js
index c280e68..5a98793 100644
--- a/src/redux/index.js
+++ b/src/redux/index.js
@@ -1,6 +1,7 @@
import {createStore, applyMiddleware} from 'redux'
import {routerMiddleware} from 'react-router-redux'
import logger from 'redux-logger'
+// import thunk from 'redux-thunk'
import createSagaMiddleware from 'redux-saga'
import reducer from './reducer'
import saga from './saga'
diff --git a/src/redux/reducer.js b/src/redux/reducer.js
index ce22e54..86f9506 100644
--- a/src/redux/reducer.js
+++ b/src/redux/reducer.js
@@ -3,7 +3,7 @@ import {routerReducer as router} from 'react-router-redux'
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 eventModule} from '../ducks/events'
+import eventsReducer, {moduleName as eventModule} from '../ducks/events2'
export default combineReducers({
router, form,
diff --git a/src/redux/saga.js b/src/redux/saga.js
index ee83976..a22eba5 100644
--- a/src/redux/saga.js
+++ b/src/redux/saga.js
@@ -1,7 +1,7 @@
import {all} from 'redux-saga/effects'
import {saga as peopleSaga} from '../ducks/people'
import {saga as authSaga} from '../ducks/auth'
-import {saga as eventsSaga} from '../ducks/events'
+import {saga as eventsSaga} from '../ducks/events2'
export default function * () {