aboutsummaryrefslogtreecommitdiff
path: root/src/client/react
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/react')
-rw-r--r--src/client/react/App.js6
-rw-r--r--src/client/react/index.js12
-rw-r--r--src/client/react/lib/getHistory.js35
-rw-r--r--src/client/react/lib/url.js11
-rw-r--r--src/client/react/store/actions.js54
-rw-r--r--src/client/react/store/reducers.js1
-rw-r--r--src/client/react/store/selectors.js30
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));
+}