aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNoah Loomans <noahloomans@gmail.com>2018-02-19 22:49:26 +0100
committerNoah Loomans <noahloomans@gmail.com>2018-02-19 22:49:26 +0100
commit5be066cc2714ca6cbd75d8786c859d8767df0ccb (patch)
tree4b9b66e68612eb9df03a73453907031c03420415
parent50671ed027f874992ac50cfb21e123f579440737 (diff)
Merge reducers into single file
-rw-r--r--src/client/react/components/container/HelpBox.js2
-rw-r--r--src/client/react/components/container/Results.js4
-rw-r--r--src/client/react/components/container/Search.js13
-rw-r--r--src/client/react/components/container/View.js2
-rw-r--r--src/client/react/lib/getSearchResults.js22
-rw-r--r--src/client/react/reducers.js126
-rw-r--r--src/client/react/reducers.test.js253
-rw-r--r--src/client/react/reducers/search.js109
-rw-r--r--src/client/react/reducers/search.test.js198
-rw-r--r--src/client/react/reducers/view.js73
10 files changed, 403 insertions, 399 deletions
diff --git a/src/client/react/components/container/HelpBox.js b/src/client/react/components/container/HelpBox.js
index 37b5c7e..31624db 100644
--- a/src/client/react/components/container/HelpBox.js
+++ b/src/client/react/components/container/HelpBox.js
@@ -47,7 +47,7 @@ class HelpBox extends React.Component {
const mapStateToProps = state => ({
results: state.search.results,
- searchText: state.search.searchText,
+ searchText: state.search.text,
});
export default connect(mapStateToProps)(HelpBox);
diff --git a/src/client/react/components/container/Results.js b/src/client/react/components/container/Results.js
index 0f08d7a..5434eb4 100644
--- a/src/client/react/components/container/Results.js
+++ b/src/client/react/components/container/Results.js
@@ -86,8 +86,8 @@ class Results extends React.Component {
const mapStateToProps = state => ({
results: state.search.results,
- searchText: state.search.searchText,
- selectedResult: state.search.selectedResult,
+ searchText: state.search.text,
+ selectedResult: state.search.result,
});
export default withRouter(connect(mapStateToProps)(Results));
diff --git a/src/client/react/components/container/Search.js b/src/client/react/components/container/Search.js
index 1c4ca4f..30ccad8 100644
--- a/src/client/react/components/container/Search.js
+++ b/src/client/react/components/container/Search.js
@@ -64,13 +64,13 @@ class Search extends React.Component {
componentDidMount() {
const urlUser = userFromMatch(this.props.match);
- this.props.dispatch({ type: 'SEARCH/SET_USERS', urlUser });
+ this.props.dispatch({ type: 'SEARCH/SET_USER', user: urlUser });
}
componentWillReceiveProps(nextProps) {
if (nextProps.match !== this.props.match) {
const urlUser = userFromMatch(nextProps.match);
- this.props.dispatch({ type: 'SEARCH/SET_USERS', urlUser });
+ this.props.dispatch({ type: 'SEARCH/SET_USER', user: urlUser });
}
}
@@ -103,7 +103,7 @@ class Search extends React.Component {
case 'Escape':
event.preventDefault();
- this.props.dispatch({ type: 'SEARCH/SET_USERS', urlUser });
+ this.props.dispatch({ type: 'SEARCH/SET_USER', user: urlUser });
break;
case 'Enter':
@@ -112,7 +112,7 @@ class Search extends React.Component {
// 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.
// Therefor, we need to dispatch the SET_USER command manually.
- this.props.dispatch({ type: 'SEARCH/SET_USERS', urlUser });
+ this.props.dispatch({ type: 'SEARCH/SET_USER', user: urlUser });
} else if (result) {
this.props.history.push(`/${result}`);
}
@@ -170,9 +170,8 @@ class Search extends React.Component {
const mapStateToProps = state => ({
results: state.search.results,
- searchText: state.search.searchText,
- selectedResult: state.search.selectedResult,
- isExactMatch: state.search.isExactMatch,
+ searchText: state.search.text,
+ selectedResult: state.search.selected,
});
export default withRouter(connect(mapStateToProps)(Search));
diff --git a/src/client/react/components/container/View.js b/src/client/react/components/container/View.js
index 28aaad3..b374300 100644
--- a/src/client/react/components/container/View.js
+++ b/src/client/react/components/container/View.js
@@ -114,7 +114,7 @@ class View extends React.Component {
}
const mapStateToProps = state => ({
- schedules: state.view.schedules,
+ schedules: state.schedules,
});
export default withRouter(connect(mapStateToProps)(View));
diff --git a/src/client/react/lib/getSearchResults.js b/src/client/react/lib/getSearchResults.js
new file mode 100644
index 0000000..fa012ac
--- /dev/null
+++ b/src/client/react/lib/getSearchResults.js
@@ -0,0 +1,22 @@
+import FuzzySearch from 'fuzzy-search';
+import uniqBy from 'lodash/uniqBy';
+import users from '../users';
+
+function getSearchResults(query) {
+ const searcher = new FuzzySearch(users.allUsers, ['value', 'alt']);
+
+ if (query.trim() === '') {
+ return [];
+ }
+
+ const allResults = searcher.search(query);
+ const uniqResults = uniqBy(allResults, result => result.id);
+ const firstResults = uniqResults.splice(0, 4);
+
+ const userIds = firstResults.map(result => result.id);
+
+ return userIds;
+}
+
+export default getSearchResults;
+
diff --git a/src/client/react/reducers.js b/src/client/react/reducers.js
index 13795f7..accf464 100644
--- a/src/client/react/reducers.js
+++ b/src/client/react/reducers.js
@@ -18,13 +18,123 @@
*
*/
-import { combineReducers } from 'redux';
-import search from './reducers/search';
-import view from './reducers/view';
+import getSearchResults from './lib/getSearchResults';
+import users from './users';
-const rootReducer = combineReducers({
- search,
- view,
-});
+const DEFAULT_STATE = {
+ // results: [
+ // 's/18562',
+ // ],
+ search: {
+ results: [],
+ text: '',
+ selected: null,
+ },
+ schedules: {},
+};
-export default rootReducer;
+const schedule = (state = {}, action) => {
+ switch (action.type) {
+ case 'VIEW/FETCH_SCHEDULE_REQUEST':
+ return {
+ ...state,
+ state: 'FETCHING',
+ };
+ case 'VIEW/FETCH_SCHEDULE_SUCCESS':
+ return {
+ ...state,
+ state: 'FINISHED',
+ htmlStr: action.htmlStr,
+ };
+ default:
+ return state;
+ }
+};
+
+function reducer(state = DEFAULT_STATE, action) {
+ switch (action.type) {
+ case 'SEARCH/SET_USER': {
+ const { user } = action;
+
+ if (user == null) {
+ return {
+ ...state,
+ search: DEFAULT_STATE.search,
+ };
+ }
+
+ return {
+ ...state,
+ search: {
+ results: [],
+ text: users.byId[user].value,
+ selected: user,
+ },
+ };
+ }
+
+ case 'SEARCH/INPUT_CHANGE':
+ return {
+ ...state,
+ search: {
+ results: getSearchResults(action.searchText),
+ text: action.searchText,
+ selected: null,
+ },
+ };
+
+ case 'SEARCH/CHANGE_SELECTED_RESULT': {
+ const prevSelectedResult = state.search.selected;
+ const prevSelectedResultIndex = state.search.results.indexOf(prevSelectedResult);
+ let nextSelectedResultIndex =
+ prevSelectedResultIndex + action.relativeChange;
+
+ if (nextSelectedResultIndex < -1) {
+ nextSelectedResultIndex = state.search.results.length - 1;
+ } else if (nextSelectedResultIndex > state.search.results.length - 1) {
+ nextSelectedResultIndex = -1;
+ }
+
+ const nextSelectedResult =
+ nextSelectedResultIndex === -1
+ ? null
+ : state.search.results[nextSelectedResultIndex];
+
+ return {
+ ...state,
+ search: {
+ ...state.search,
+ selected: nextSelectedResult,
+ },
+ };
+ }
+
+ case 'VIEW/FETCH_SCHEDULE_REQUEST':
+ case 'VIEW/FETCH_SCHEDULE_SUCCESS':
+ return {
+ ...state,
+ schedules: {
+ ...state.schedules,
+ [action.user]:
+ state.schedules[action.user]
+ ? {
+ // This user already exists in our state, extend it.
+ ...state.schedules[action.user],
+ [action.week]: schedule(state.schedules[action.user][action.week], action),
+ }
+ : {
+ // This user does not already exist in our state.
+ [action.week]: schedule(undefined, action),
+ },
+ },
+ };
+
+ default:
+ return state;
+ }
+}
+
+export default reducer;
+export const _test = {
+ DEFAULT_STATE,
+};
diff --git a/src/client/react/reducers.test.js b/src/client/react/reducers.test.js
new file mode 100644
index 0000000..cd195b0
--- /dev/null
+++ b/src/client/react/reducers.test.js
@@ -0,0 +1,253 @@
+/**
+ * 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/>.
+ *
+ */
+
+window.USERS = [
+ { type: 's', value: '18561' },
+ { type: 's', value: '18562' },
+ { type: 's', value: '18563' },
+ { type: 's', value: '18564' },
+ { type: 's', value: '18565' },
+ { type: 's', value: '18566' },
+ { type: 's', value: '18567' },
+ { type: 's', value: '18568' },
+ { type: 's', value: '18569' },
+];
+
+const deepFreeze = require('deep-freeze');
+const reducer = require('./reducers').default;
+const { DEFAULT_STATE } = require('./reducers')._test;
+
+describe('reducers', () => {
+ describe('search', () => {
+ describe('SEARCH/SET_USER', () => {
+ it('Resets the search state if the user is null', () => {
+ const prevState = { search: { foo: 'bar' } };
+ const action = { type: 'SEARCH/SET_USER', user: null };
+
+ deepFreeze([prevState, action]);
+
+ expect(reducer(prevState, action)).toEqual({
+ search: DEFAULT_STATE.search,
+ });
+ });
+
+ it('Sets all the values of that user properly', () => {
+ expect(reducer(undefined, { type: 'SEARCH/SET_USER', user: 's/18561' })).toEqual({
+ ...DEFAULT_STATE,
+ search: {
+ results: [],
+ text: '18561',
+ selected: 's/18561',
+ },
+ });
+ });
+ });
+
+ describe('SEARCH/INPUT_CHANGE', () => {
+ it('Returns no results when nothing is typed in', () => {
+ expect(reducer(undefined, { type: 'SEARCH/INPUT_CHANGE', searchText: '' })).toEqual({
+ ...DEFAULT_STATE,
+ search: {
+ results: [],
+ text: '',
+ selected: null,
+ },
+ });
+ });
+
+ it('Returns no results when a space is typed in', () => {
+ expect(reducer(undefined, { type: 'SEARCH/INPUT_CHANGE', searchText: ' ' })).toEqual({
+ ...DEFAULT_STATE,
+ search: {
+ results: [],
+ text: ' ',
+ selected: null,
+ },
+ });
+ });
+
+ it('Preforms a basic search, only returning four results', () => {
+ expect(reducer(undefined, { type: 'SEARCH/INPUT_CHANGE', searchText: '18' })).toEqual({
+ ...DEFAULT_STATE,
+ search: {
+ results: [
+ 's/18561',
+ 's/18562',
+ 's/18563',
+ 's/18564',
+ ],
+ text: '18',
+ selected: null,
+ },
+ });
+ });
+ });
+
+ describe('SEARCH/CHANGE_SELECTED_RESULT', () => {
+ it('Does nothing when there are no results', () => {
+ const actionPlus = { type: 'SEARCH/CHANGE_SELECTED_RESULT', relativeChange: +1 };
+ const actionMin = { type: 'SEARCH/CHANGE_SELECTED_RESULT', relativeChange: -1 };
+
+ deepFreeze([DEFAULT_STATE, actionPlus, actionMin]);
+
+ const nextStatePlus = reducer(DEFAULT_STATE, actionPlus);
+ const nextStateMin = reducer(DEFAULT_STATE, actionMin);
+ expect(nextStatePlus).toEqual(DEFAULT_STATE);
+ expect(nextStateMin).toEqual(DEFAULT_STATE);
+ });
+
+ it('Switches to the correct selectedResult when no selected result is selected', () => {
+ const prevState = {
+ ...DEFAULT_STATE,
+ search: {
+ results: ['s/18561', 's/18562', 's/18563'],
+ text: '1856',
+ selected: null,
+ },
+ };
+
+ const actionPlus = { type: 'SEARCH/CHANGE_SELECTED_RESULT', relativeChange: +1 };
+ const actionMin = { type: 'SEARCH/CHANGE_SELECTED_RESULT', relativeChange: -1 };
+
+ deepFreeze([prevState, actionPlus, actionMin]);
+
+ const nextStatePlus = reducer(prevState, actionPlus);
+ const nextStateMin = reducer(prevState, actionMin);
+
+ expect(nextStatePlus).toEqual({
+ ...prevState,
+ search: {
+ ...prevState.search,
+ selected: 's/18561',
+ },
+ });
+ expect(nextStateMin).toEqual({
+ ...prevState,
+ search: {
+ ...prevState.search,
+ selected: 's/18563',
+ },
+ });
+ });
+
+ it('Switches to the correct selectedResult when there is a selected result selected', () => {
+ const prevState = {
+ ...DEFAULT_STATE,
+ search: {
+ results: ['s/18561', 's/18562', 's/18563'],
+ text: '1856',
+ selected: 's/18562',
+ },
+ };
+
+ const actionPlus = { type: 'SEARCH/CHANGE_SELECTED_RESULT', relativeChange: +1 };
+ const actionMin = { type: 'SEARCH/CHANGE_SELECTED_RESULT', relativeChange: -1 };
+
+ deepFreeze([prevState, actionPlus, actionMin]);
+
+ const nextStatePlus = reducer(prevState, actionPlus);
+ const nextStateMin = reducer(prevState, actionMin);
+
+ expect(nextStatePlus).toEqual({
+ ...prevState,
+ search: {
+ ...prevState.search,
+ selected: 's/18563',
+ },
+ });
+ expect(nextStateMin).toEqual({
+ ...prevState,
+ search: {
+ ...prevState.search,
+ selected: 's/18561',
+ },
+ });
+ });
+
+ it('Properly wraps around when incrementing', () => {
+ expect(reducer({
+ ...DEFAULT_STATE,
+ search: {
+ results: ['s/18561', 's/18562', 's/18563'],
+ text: '1856',
+ selected: 's/18563',
+ },
+ }, { type: 'SEARCH/CHANGE_SELECTED_RESULT', relativeChange: +1 })).toEqual({
+ ...DEFAULT_STATE,
+ search: {
+ results: ['s/18561', 's/18562', 's/18563'],
+ text: '1856',
+ selected: null,
+ },
+ });
+
+ expect(reducer({
+ ...DEFAULT_STATE,
+ search: {
+ results: ['s/18561', 's/18562', 's/18563'],
+ text: '1856',
+ selected: null,
+ },
+ }, { type: 'SEARCH/CHANGE_SELECTED_RESULT', relativeChange: +1 })).toEqual({
+ ...DEFAULT_STATE,
+ search: {
+ results: ['s/18561', 's/18562', 's/18563'],
+ text: '1856',
+ selected: 's/18561',
+ },
+ });
+ });
+
+ it('Properly wraps around when decrementing', () => {
+ expect(reducer({
+ ...DEFAULT_STATE,
+ search: {
+ results: ['s/18561', 's/18562', 's/18563'],
+ text: '1856',
+ selected: 's/18561',
+ },
+ }, { type: 'SEARCH/CHANGE_SELECTED_RESULT', relativeChange: -1 })).toEqual({
+ ...DEFAULT_STATE,
+ search: {
+ results: ['s/18561', 's/18562', 's/18563'],
+ text: '1856',
+ selected: null,
+ },
+ });
+
+ expect(reducer({
+ ...DEFAULT_STATE,
+ search: {
+ results: ['s/18561', 's/18562', 's/18563'],
+ text: '1856',
+ selected: null,
+ },
+ }, { type: 'SEARCH/CHANGE_SELECTED_RESULT', relativeChange: -1 })).toEqual({
+ ...DEFAULT_STATE,
+ search: {
+ results: ['s/18561', 's/18562', 's/18563'],
+ text: '1856',
+ selected: 's/18563',
+ },
+ });
+ });
+ });
+ });
+});
diff --git a/src/client/react/reducers/search.js b/src/client/react/reducers/search.js
deleted file mode 100644
index dcc7ec6..0000000
--- a/src/client/react/reducers/search.js
+++ /dev/null
@@ -1,109 +0,0 @@
-/**
- * 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 FuzzySearch from 'fuzzy-search';
-import uniqBy from 'lodash/uniqBy';
-import users from '../users';
-
-const DEFAULT_STATE = {
- // results: [
- // 's/18562',
- // ],
- results: [],
- searchText: '',
- selectedResult: null,
-};
-
-function getSearchResults(allUsers, query) {
- const searcher = new FuzzySearch(allUsers, ['value', 'alt']);
-
- if (query.trim() === '') {
- return [];
- }
-
- const allResults = searcher.search(query);
- const uniqResults = uniqBy(allResults, result => result.id);
- const firstResults = uniqResults.splice(0, 4);
-
- const userIds = firstResults.map(result => result.id);
-
- return userIds;
-}
-
-const search = (state = DEFAULT_STATE, action) => {
- switch (action.type) {
- case 'SEARCH/SET_USER': {
- const { user } = action;
-
- if (user == null) {
- return DEFAULT_STATE;
- }
-
- return {
- ...state,
- results: [],
- searchText: users.byId[user].value,
- selectedResult: user,
- };
- }
-
- case 'SEARCH/INPUT_CHANGE':
- return {
- ...state,
- results: getSearchResults(users.allUsers, action.searchText),
- searchText: action.searchText,
- selectedResult: null,
- };
-
- case 'SEARCH/CHANGE_SELECTED_RESULT': {
- const { results } = state;
-
- const prevSelectedResult = state.selectedResult;
- const prevSelectedResultIndex = results.indexOf(prevSelectedResult);
- let nextSelectedResultIndex =
- prevSelectedResultIndex + action.relativeChange;
-
- if (nextSelectedResultIndex < -1) {
- nextSelectedResultIndex = results.length - 1;
- } else if (nextSelectedResultIndex > results.length - 1) {
- nextSelectedResultIndex = -1;
- }
-
- const nextSelectedResult =
- nextSelectedResultIndex === -1
- ? null
- : results[nextSelectedResultIndex];
-
- return {
- ...state,
- selectedResult: nextSelectedResult,
- };
- }
-
- default:
- return state;
- }
-};
-
-export default search;
-
-export const _test = {
- DEFAULT_STATE,
-};
diff --git a/src/client/react/reducers/search.test.js b/src/client/react/reducers/search.test.js
deleted file mode 100644
index 48ca05a..0000000
--- a/src/client/react/reducers/search.test.js
+++ /dev/null
@@ -1,198 +0,0 @@
-/**
- * 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/>.
- *
- */
-
-window.USERS = [
- { type: 's', value: '18561' },
- { type: 's', value: '18562' },
- { type: 's', value: '18563' },
- { type: 's', value: '18564' },
- { type: 's', value: '18565' },
- { type: 's', value: '18566' },
- { type: 's', value: '18567' },
- { type: 's', value: '18568' },
- { type: 's', value: '18569' },
-];
-
-const deepFreeze = require('deep-freeze');
-const search = require('./search').default;
-const { _test } = require('./search');
-
-describe('reducers', () => {
- describe('search', () => {
- describe('SEARCH/SET_USER', () => {
- it('Resets to the default state if the user is null', () => {
- expect(search({ foo: 'bar' }, { type: 'SEARCH/SET_USER', user: null })).toEqual(_test.DEFAULT_STATE);
- });
-
- it('Sets all the values of that user properly', () => {
- expect(search(undefined, { type: 'SEARCH/SET_USER', user: 's/18561' })).toEqual({
- results: [],
- searchText: '18561',
- selectedResult: 's/18561',
- });
- });
- });
-
- describe('SEARCH/INPUT_CHANGE', () => {
- it('Returns no results when nothing is typed in', () => {
- expect(search(undefined, { type: 'SEARCH/INPUT_CHANGE', searchText: '' })).toEqual({
- results: [],
- searchText: '',
- selectedResult: null,
- });
- });
-
- it('Returns no results when a space is typed in', () => {
- expect(search(undefined, { type: 'SEARCH/INPUT_CHANGE', searchText: ' ' })).toEqual({
- results: [],
- searchText: ' ',
- selectedResult: null,
- });
- });
-
- it('Preforms a basic search, only returning four results', () => {
- expect(search(undefined, { type: 'SEARCH/INPUT_CHANGE', searchText: '18' })).toEqual({
- results: [
- 's/18561',
- 's/18562',
- 's/18563',
- 's/18564',
- ],
- searchText: '18',
- selectedResult: null,
- });
- });
- });
-
- describe('SEARCH/CHANGE_SELECTED_RESULT', () => {
- it('Does nothing when there are no results', () => {
- const prevState = {
- results: [],
- searchText: '',
- selectedResult: null,
- };
-
- const actionPlus = { type: 'SEARCH/CHANGE_SELECTED_RESULT', relativeChange: +1 };
- const actionMin = { type: 'SEARCH/CHANGE_SELECTED_RESULT', relativeChange: -1 };
-
- deepFreeze([prevState, actionPlus, actionMin]);
-
- const nextStatePlus = search(prevState, actionPlus);
- const nextStateMin = search(prevState, actionMin);
- expect(nextStatePlus).toEqual(prevState);
- expect(nextStateMin).toEqual(prevState);
- });
-
- it('Switches to the correct selectedResult when no selected result is selected', () => {
- const prevState = {
- results: ['s/18561', 's/18562', 's/18563'],
- searchText: '1856',
- selectedResult: null,
- };
-
- const actionPlus = { type: 'SEARCH/CHANGE_SELECTED_RESULT', relativeChange: +1 };
- const actionMin = { type: 'SEARCH/CHANGE_SELECTED_RESULT', relativeChange: -1 };
-
- deepFreeze([prevState, actionPlus, actionMin]);
-
- const nextStatePlus = search(prevState, actionPlus);
- const nextStateMin = search(prevState, actionMin);
-
- expect(nextStatePlus).toEqual({
- ...prevState,
- selectedResult: 's/18561',
- });
- expect(nextStateMin).toEqual({
- ...prevState,
- selectedResult: 's/18563',
- });
- });
-
- it('Switches to the correct selectedResult when there is a selected result selected', () => {
- const prevState = {
- results: ['s/18561', 's/18562', 's/18563'],
- searchText: '1856',
- selectedResult: 's/18562',
- };
-
- const actionPlus = { type: 'SEARCH/CHANGE_SELECTED_RESULT', relativeChange: +1 };
- const actionMin = { type: 'SEARCH/CHANGE_SELECTED_RESULT', relativeChange: -1 };
-
- deepFreeze([prevState, actionPlus, actionMin]);
-
- const nextStatePlus = search(prevState, actionPlus);
- const nextStateMin = search(prevState, actionMin);
-
- expect(nextStatePlus).toEqual({
- ...prevState,
- selectedResult: 's/18563',
- });
- expect(nextStateMin).toEqual({
- ...prevState,
- selectedResult: 's/18561',
- });
- });
-
- it('Properly wraps around when incrementing', () => {
- expect(search({
- results: ['s/18561', 's/18562', 's/18563'],
- searchText: '1856',
- selectedResult: 's/18563',
- }, { type: 'SEARCH/CHANGE_SELECTED_RESULT', relativeChange: +1 })).toEqual({
- results: ['s/18561', 's/18562', 's/18563'],
- searchText: '1856',
- selectedResult: null,
- });
-
- expect(search({
- results: ['s/18561', 's/18562', 's/18563'],
- searchText: '1856',
- selectedResult: null,
- }, { type: 'SEARCH/CHANGE_SELECTED_RESULT', relativeChange: +1 })).toEqual({
- results: ['s/18561', 's/18562', 's/18563'],
- searchText: '1856',
- selectedResult: 's/18561',
- });
- });
-
- it('Properly wraps around when decrementing', () => {
- expect(search({
- results: ['s/18561', 's/18562', 's/18563'],
- searchText: '1856',
- selectedResult: 's/18561',
- }, { type: 'SEARCH/CHANGE_SELECTED_RESULT', relativeChange: -1 })).toEqual({
- results: ['s/18561', 's/18562', 's/18563'],
- searchText: '1856',
- selectedResult: null,
- });
-
- expect(search({
- results: ['s/18561', 's/18562', 's/18563'],
- searchText: '1856',
- selectedResult: null,
- }, { type: 'SEARCH/CHANGE_SELECTED_RESULT', relativeChange: -1 })).toEqual({
- results: ['s/18561', 's/18562', 's/18563'],
- searchText: '1856',
- selectedResult: 's/18563',
- });
- });
- });
- });
-});
diff --git a/src/client/react/reducers/view.js b/src/client/react/reducers/view.js
deleted file mode 100644
index 8fa56b8..0000000
--- a/src/client/react/reducers/view.js
+++ /dev/null
@@ -1,73 +0,0 @@
-/**
- * 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/>.
- *
- */
-
-const schedule = (state = {}, action) => {
- switch (action.type) {
- case 'VIEW/FETCH_SCHEDULE_REQUEST':
- return {
- ...state,
- state: 'FETCHING',
- };
- case 'VIEW/FETCH_SCHEDULE_SUCCESS':
- return {
- ...state,
- state: 'FINISHED',
- htmlStr: action.htmlStr,
- };
- default:
- return state;
- }
-};
-
-const DEFAULT_STATE = {
- schedules: {},
-};
-
-const view = (state = DEFAULT_STATE, action) => {
- switch (action.type) {
- case 'VIEW/FETCH_SCHEDULE_REQUEST':
- case 'VIEW/FETCH_SCHEDULE_SUCCESS':
- return {
- ...state,
- schedules: {
- ...state.schedules,
- [action.user]:
- state.schedules[action.user]
- ? {
- // This user already exists in our state, extend it.
- ...state.schedules[action.user],
- [action.week]: schedule(state.schedules[action.user][action.week], action),
- }
- : {
- // This user does not already exist in our state.
- [action.week]: schedule(undefined, action),
- },
- },
- };
- default:
- return state;
- }
-};
-
-export default view;
-
-export const _test = {
- DEFAULT_STATE,
-};