aboutsummaryrefslogtreecommitdiff
path: root/src/client/react
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/react')
-rw-r--r--src/client/react/components/container/WeekSelector.js66
-rw-r--r--src/client/react/components/presentational/WeekSelector.js81
-rw-r--r--src/client/react/components/presentational/WeekSelector.scss40
-rw-r--r--src/client/react/lib/getHistory.js12
-rw-r--r--src/client/react/lib/url.js18
-rw-r--r--src/client/react/store/actions.js31
6 files changed, 179 insertions, 69 deletions
diff --git a/src/client/react/components/container/WeekSelector.js b/src/client/react/components/container/WeekSelector.js
index bc428cc..96c5663 100644
--- a/src/client/react/components/container/WeekSelector.js
+++ b/src/client/react/components/container/WeekSelector.js
@@ -18,75 +18,19 @@
*
*/
-import React from 'react';
-import PropTypes from 'prop-types';
-import moment from 'moment';
import { connect } from 'react-redux';
import { withRouter } from 'react-router-dom';
+import { setWeek } from '../../store/actions';
+import { weekFromLocation } from '../../lib/url';
-import ArrowBackIcon from 'react-icons/lib/md/arrow-back';
-import ArrowForwardIcon from 'react-icons/lib/md/arrow-forward';
-
-import purifyWeek from '../../lib/purifyWeek';
-import { makeSetWeek, weekFromLocation } from '../../lib/url';
-
-import './WeekSelector.scss';
-
-class WeekSelector extends React.Component {
- static propTypes = {
- // react-router
- week: PropTypes.number.isRequired,
- setWeek: PropTypes.func.isRequired,
- };
-
- getWeekText() {
- const { week } = this.props;
-
- const currentWeek = moment().week();
-
- switch (week) {
- case currentWeek:
- return `Huidige week • ${week}`;
- case currentWeek + 1:
- return `Volgende week • ${week}`;
- case currentWeek - 1:
- return `Vorige week • ${week}`;
- default:
- return `Week ${week}`;
- }
- }
-
- updateWeek(change) {
- const { week, setWeek } = this.props;
- const newWeek = purifyWeek(week + change);
-
- const isCurrentWeek = moment().week() === newWeek;
- setWeek(isCurrentWeek ? undefined : newWeek);
- }
-
- render() {
- return (
- <div className="WeekSelector">
- <button type="button" onClick={() => this.updateWeek(-1)}>
- <ArrowBackIcon />
- </button>
- <div className="text">
- {this.getWeekText()}
- </div>
- <button type="button" onClick={() => this.updateWeek(+1)}>
- <ArrowForwardIcon />
- </button>
- </div>
- );
- }
-}
+import WeekSelector from '../presentational/WeekSelector';
const mapStateToProps = (state, { location }) => ({
week: weekFromLocation(location),
});
-const mapDispatchToProps = (dispatch, { history }) => ({
- setWeek: makeSetWeek(history),
+const mapDispatchToProps = dispatch => ({
+ setWeek: newWeek => dispatch(setWeek(newWeek)),
});
export default withRouter(connect(mapStateToProps, mapDispatchToProps)(WeekSelector));
diff --git a/src/client/react/components/presentational/WeekSelector.js b/src/client/react/components/presentational/WeekSelector.js
new file mode 100644
index 0000000..9f69121
--- /dev/null
+++ b/src/client/react/components/presentational/WeekSelector.js
@@ -0,0 +1,81 @@
+/**
+ * Copyright (C) 2018 Noah Loomans
+ *
+ * This file is part of rooster.hetmml.nl.
+ *
+ * rooster.hetmml.nl is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * rooster.hetmml.nl is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with rooster.hetmml.nl. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+import React from 'react';
+import PropTypes from 'prop-types';
+import moment from 'moment';
+
+import ArrowBackIcon from 'react-icons/lib/md/arrow-back';
+import ArrowForwardIcon from 'react-icons/lib/md/arrow-forward';
+
+import purifyWeek from '../../lib/purifyWeek';
+
+import './WeekSelector.scss';
+
+class WeekSelector extends React.Component {
+ static propTypes = {
+ // react-router
+ week: PropTypes.number.isRequired,
+ setWeek: PropTypes.func.isRequired,
+ };
+
+ getWeekText() {
+ const { week } = this.props;
+
+ const currentWeek = moment().week();
+
+ switch (week) {
+ case currentWeek:
+ return `Huidige week • ${week}`;
+ case currentWeek + 1:
+ return `Volgende week • ${week}`;
+ case currentWeek - 1:
+ return `Vorige week • ${week}`;
+ default:
+ return `Week ${week}`;
+ }
+ }
+
+ updateWeek(change) {
+ const { week, setWeek } = this.props;
+ const newWeek = purifyWeek(week + change);
+
+ const isCurrentWeek = moment().week() === newWeek;
+ setWeek(isCurrentWeek ? undefined : newWeek);
+ }
+
+ render() {
+ return (
+ <div className="WeekSelector">
+ <button type="button" onClick={() => this.updateWeek(-1)}>
+ <ArrowBackIcon />
+ </button>
+ <div className="text">
+ {this.getWeekText()}
+ </div>
+ <button type="button" onClick={() => this.updateWeek(+1)}>
+ <ArrowForwardIcon />
+ </button>
+ </div>
+ );
+ }
+}
+
+export default WeekSelector;
diff --git a/src/client/react/components/presentational/WeekSelector.scss b/src/client/react/components/presentational/WeekSelector.scss
new file mode 100644
index 0000000..dd71fea
--- /dev/null
+++ b/src/client/react/components/presentational/WeekSelector.scss
@@ -0,0 +1,40 @@
+.WeekSelector {
+ display: flex;
+ padding: 8px;
+ padding-bottom: 0;
+ background-color: #F44336;
+ color: white;
+ align-items: center;
+
+ .text {
+ flex-grow: 1;
+ text-align: center;
+ }
+
+ button {
+ background-color: initial;
+ border: initial;
+ color: inherit;
+ padding: 8px;
+ border-radius: 4px;
+
+ svg {
+ font-size: 2em;
+ }
+
+ &:focus {
+ background-color: #D32F2F;
+ outline: none;
+ }
+
+ &:active {
+ background-color: #B81111;
+ outline: none;
+ }
+
+ &::-moz-focus-inner {
+ /* Remove the dotted line outline from Firefox */
+ border: 0;
+ }
+ }
+}
diff --git a/src/client/react/lib/getHistory.js b/src/client/react/lib/getHistory.js
index 642a9a8..5fef902 100644
--- a/src/client/react/lib/getHistory.js
+++ b/src/client/react/lib/getHistory.js
@@ -1,22 +1,22 @@
import {
- makeSetUser,
- makeSetWeek,
weekFromLocation,
userFromLocation,
+ makeUpdatePathname,
+ makeUpdateQuery,
} from './url';
export default function makeGetHistory(history) {
return function getHistory() {
const user = userFromLocation(history.location);
const week = weekFromLocation(history.location);
- const setUser = makeSetUser(history);
- const setWeek = makeSetWeek(history);
+ const updatePathname = makeUpdatePathname(history);
+ const updateQuery = makeUpdateQuery(history);
return {
user,
week,
- setUser,
- setWeek,
+ updatePathname,
+ updateQuery,
};
};
}
diff --git a/src/client/react/lib/url.js b/src/client/react/lib/url.js
index fcd3e6a..752fec2 100644
--- a/src/client/react/lib/url.js
+++ b/src/client/react/lib/url.js
@@ -70,3 +70,21 @@ export function makeSetWeek(history) {
history.push(`${history.location.pathname}?${query}`);
};
}
+
+export function makeUpdatePathname(history) {
+ return function updatePathname(pathname) {
+ const query = history.location.search;
+ history.push(`/${pathname}${query}`);
+ };
+}
+
+export function makeUpdateQuery(history) {
+ return function updateQuery(newQuery) {
+ const query = queryString.stringify({
+ ...queryString.parse(history.location.search),
+ ...newQuery,
+ });
+
+ history.push(`${history.location.pathname}?${query}`);
+ };
+}
diff --git a/src/client/react/store/actions.js b/src/client/react/store/actions.js
index c4cc9ba..30b573c 100644
--- a/src/client/react/store/actions.js
+++ b/src/client/react/store/actions.js
@@ -1,12 +1,39 @@
import users from '../users';
+export function setUser(newUser) {
+ return (dispatch, getState, getHistory) => {
+ const { user, updatePathname } = getHistory();
+
+ if (newUser === user) {
+ // EDGE CASE: The user is set if the user changes, but it doesn't
+ // change if the result is already the one we are viewing.
+ // Causing the <Results /> object to not collapse when a user is
+ // selected.
+ // Therefor, we need to dispatch the SET_USER command manually.
+ dispatch({ type: 'SEARCH/SET_USER', user });
+ } else {
+ updatePathname(newUser);
+ }
+ };
+}
+
+export function setWeek(newWeek) {
+ return (dispatchEvent, getState, getHistory) => {
+ const { updateQuery } = getHistory();
+
+ updateQuery({
+ week: newWeek,
+ });
+ };
+}
+
export function showRoomFinder() {
return (dispatch, getState, getHistory) => {
- const { user, setUser } = getHistory();
+ const { user } = getHistory();
if (user == null || users.byId[user].type !== 'r') {
// We are not currently viewing a room, correct the situation.
- setUser(users.allRoomIds[0]);
+ dispatch(setUser(users.allRoomIds[0]));
}
dispatch({ type: 'ROOM_FINDER/SHOW' });