diff options
Diffstat (limited to 'src/client')
-rw-r--r-- | src/client/react/App.js | 6 | ||||
-rw-r--r-- | src/client/react/index.js | 12 | ||||
-rw-r--r-- | src/client/react/lib/getHistory.js | 35 | ||||
-rw-r--r-- | src/client/react/lib/url.js | 11 | ||||
-rw-r--r-- | src/client/react/store/actions.js | 54 | ||||
-rw-r--r-- | src/client/react/store/reducers.js | 1 | ||||
-rw-r--r-- | src/client/react/store/selectors.js | 30 |
7 files changed, 78 insertions, 71 deletions
diff --git a/src/client/react/App.js b/src/client/react/App.js index 522b746..f4cb848 100644 --- a/src/client/react/App.js +++ b/src/client/react/App.js @@ -2,7 +2,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import { Provider } from 'react-redux'; -import { Router } from 'react-router-dom'; +import { ConnectedRouter } from 'connected-react-router'; import AppRouter from './AppRouter'; @@ -17,9 +17,9 @@ export default class App extends React.Component { return ( <Provider store={store}> - <Router history={history}> + <ConnectedRouter history={history}> <AppRouter /> - </Router> + </ConnectedRouter> </Provider> ); } diff --git a/src/client/react/index.js b/src/client/react/index.js index f01a361..f41c9e3 100644 --- a/src/client/react/index.js +++ b/src/client/react/index.js @@ -24,12 +24,12 @@ import 'whatwg-fetch'; import React from 'react'; import ReactDOM from 'react-dom'; import { createStore, applyMiddleware, compose as reduxCompose } from 'redux'; +import { connectRouter, routerMiddleware } from 'connected-react-router'; import thunk from 'redux-thunk'; import moment from 'moment'; import createHistory from 'history/createBrowserHistory'; -import makeGetHistory from './lib/getHistory'; import reducer from './store/reducers'; import App from './App'; import './index.scss'; @@ -43,14 +43,14 @@ const history = createHistory(); const compose = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || reduxCompose; const store = createStore( - reducer, + connectRouter(history)(reducer), // Redux devtools extension // https://github.com/zalmoxisus/redux-devtools-extension compose( - applyMiddleware(thunk.withExtraArgument({ - getHistory: makeGetHistory(history), - moment, - })), + applyMiddleware( + routerMiddleware(history), + thunk, + ), ), ); diff --git a/src/client/react/lib/getHistory.js b/src/client/react/lib/getHistory.js deleted file mode 100644 index daa984b..0000000 --- a/src/client/react/lib/getHistory.js +++ /dev/null @@ -1,35 +0,0 @@ -import { - weekFromLocation, - userFromLocation, - makeUpdatePathname, - makeUpdateQuery, -} from './url'; - -/** - * Make a getHistory function. This function is used in index.js when creating - * the redux store. - * @param {history} history - * The history object from the `history` package. - * There may only be a single shared history object in the application, which - * is why it's delivered from `../index.js`. - */ -export default function makeGetHistory(history) { - /** - * Get a collection of helpers for common browser history interactions, and a - * collection of precalculated values from the address bar. This function is - * used in actions. - */ - return function getHistory() { - const user = userFromLocation(history.location); - const week = weekFromLocation(history.location); - const updatePathname = makeUpdatePathname(history); - const updateQuery = makeUpdateQuery(history); - - return { - user, - week, - updatePathname, - updateQuery, - }; - }; -} diff --git a/src/client/react/lib/url.js b/src/client/react/lib/url.js index 442e5eb..bb5b483 100644 --- a/src/client/react/lib/url.js +++ b/src/client/react/lib/url.js @@ -71,17 +71,6 @@ export function makeSetWeek(history) { }; } -export function makeUpdatePathname(history) { - return function updatePathname(pathname) { - const query = history.location.search; - if (pathname) { - history.push(`/${pathname}${query}`); - } else { - history.push(`/${query}`); - } - }; -} - export function makeUpdateQuery(history) { return function updateQuery(newQuery) { const query = queryString.stringify({ diff --git a/src/client/react/store/actions.js b/src/client/react/store/actions.js index 2d2cd30..e7ef91d 100644 --- a/src/client/react/store/actions.js +++ b/src/client/react/store/actions.js @@ -1,19 +1,40 @@ +import { push } from 'connected-react-router'; +import queryString from 'query-string'; import users from '../users'; +import { selectUser, selectWeek, selectCurrentWeek } from './selectors'; import purifyWeek from '../lib/purifyWeek'; import withinRange from '../lib/withinRange'; -export function setUser(newUser) { - return (dispatch, getState, { getHistory }) => { - const { updatePathname } = getHistory(); +function updatePathname(pathname = '') { + return (dispatch, getState) => { + const query = getState().router.location.search; + dispatch(push(`/${pathname}${query}`)); + }; +} +function updateQuery(newQuery) { + return (dispatch, getState) => { + const { location } = getState().router; + const query = queryString.stringify({ + ...queryString.parse(location.search), + ...newQuery, + }); + + dispatch(push(`${location.pathname}?${query}`)); + }; +} + +export function setUser(newUser) { + return (dispatch) => { dispatch({ type: 'SEARCH/RESET' }); - updatePathname(newUser); + dispatch(updatePathname(newUser)); }; } export function shiftRoom(shift) { - return (dispatch, getState, { getHistory }) => { - const { user } = getHistory(); + return (dispatch, getState) => { + const state = getState(); + const user = selectUser(state); const { allRoomIds } = users; if (users.byId[user].type !== 'r') throw new Error('User must be a room'); @@ -31,27 +52,28 @@ export function shiftRoom(shift) { } export function setWeek(newWeek) { - return (dispatch, getState, { getHistory, moment }) => { - const { updateQuery } = getHistory(); + return (dispatch, getState) => { + const state = getState(); + const isCurrentWeek = selectCurrentWeek(state) === newWeek; - const isCurrentWeek = moment().week() === newWeek; - - updateQuery({ + dispatch(updateQuery({ week: isCurrentWeek ? undefined : newWeek, - }); + })); }; } export function shiftWeek(shift) { - return (dispatch, getState, { getHistory }) => { - const { week } = getHistory(); + return (dispatch, getState) => { + const state = getState(); + const week = selectWeek(state); dispatch(setWeek(purifyWeek(week + shift))); }; } export function showRoomFinder() { - return (dispatch, getState, { getHistory }) => { - const { user } = getHistory(); + return (dispatch, getState) => { + const state = getState(); + const user = selectUser(state); if (user == null || users.byId[user].type !== 'r') { // We are not currently viewing a room, correct the situation. diff --git a/src/client/react/store/reducers.js b/src/client/react/store/reducers.js index 4a3576d..cd68d96 100644 --- a/src/client/react/store/reducers.js +++ b/src/client/react/store/reducers.js @@ -22,6 +22,7 @@ import getSearchResults from '../lib/getSearchResults'; import withinRange from '../lib/withinRange'; const DEFAULT_STATE = { + timestamp: Date.now(), search: null, isRoomFinderVisible: false, schedules: {}, diff --git a/src/client/react/store/selectors.js b/src/client/react/store/selectors.js new file mode 100644 index 0000000..8264cdb --- /dev/null +++ b/src/client/react/store/selectors.js @@ -0,0 +1,30 @@ +import moment from 'moment'; +import queryString from 'query-string'; +import purifyWeek from '../lib/purifyWeek'; +import users from '../users'; + +export function selectUser(store) { + const { location } = store.router; + const match = location.pathname.match(/^\/([stcr])\/([-0-9a-zA-Z]+)/); + if (!match) return null; + + const user = `${match[1]}/${match[2]}`; + if (!users.allIds.includes(user)) return null; + + return user; +} + +export function selectCurrentWeek(store) { + return moment(store.now).week(); +} + +export function selectWeek(store) { + const { location } = store.router; + const weekStr = queryString.parse(location.search).week; + + if (!weekStr) { + return selectCurrentWeek(store); + } + + return purifyWeek(parseInt(weekStr, 10)); +} |