diff options
author | Noah Loomans <noahloomans@gmail.com> | 2018-02-19 22:49:26 +0100 |
---|---|---|
committer | Noah Loomans <noahloomans@gmail.com> | 2018-02-19 22:49:26 +0100 |
commit | 5be066cc2714ca6cbd75d8786c859d8767df0ccb (patch) | |
tree | 4b9b66e68612eb9df03a73453907031c03420415 /src/client | |
parent | 50671ed027f874992ac50cfb21e123f579440737 (diff) |
Merge reducers into single file
Diffstat (limited to 'src/client')
-rw-r--r-- | src/client/react/components/container/HelpBox.js | 2 | ||||
-rw-r--r-- | src/client/react/components/container/Results.js | 4 | ||||
-rw-r--r-- | src/client/react/components/container/Search.js | 13 | ||||
-rw-r--r-- | src/client/react/components/container/View.js | 2 | ||||
-rw-r--r-- | src/client/react/lib/getSearchResults.js | 22 | ||||
-rw-r--r-- | src/client/react/reducers.js | 126 | ||||
-rw-r--r-- | src/client/react/reducers.test.js | 253 | ||||
-rw-r--r-- | src/client/react/reducers/search.js | 109 | ||||
-rw-r--r-- | src/client/react/reducers/search.test.js | 198 | ||||
-rw-r--r-- | src/client/react/reducers/view.js | 73 |
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, -}; |