From 7bd3b6766536e33146bb55506c79619a1ab7d3b3 Mon Sep 17 00:00:00 2001 From: Noah Loomans Date: Sun, 10 Dec 2017 11:10:05 +0100 Subject: Move reducers and actions into seperate folders --- src/client/react/reducers/search.js | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 src/client/react/reducers/search.js (limited to 'src/client/react/reducers') diff --git a/src/client/react/reducers/search.js b/src/client/react/reducers/search.js new file mode 100644 index 0000000..05926c9 --- /dev/null +++ b/src/client/react/reducers/search.js @@ -0,0 +1,21 @@ +const DEFAULT_STATE = { + searchInput: '', + searchResults: [], +}; + +const search = (state = DEFAULT_STATE, action) => { + switch (action.type) { + case 'SEARCH/TYPE': + return { + ...state, + searchInput: action.typedValue, + searchResults: [ + { type: 's', name: '18561' }, + ], + }; + default: + return state; + } +}; + +export default search; -- cgit v1.1 From 1286c6556115f80218a4828d29b288f56b3d795f Mon Sep 17 00:00:00 2001 From: Noah Loomans Date: Sun, 10 Dec 2017 11:13:08 +0100 Subject: Rename onType to onInputChange --- src/client/react/reducers/search.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/client/react/reducers') diff --git a/src/client/react/reducers/search.js b/src/client/react/reducers/search.js index 05926c9..08be519 100644 --- a/src/client/react/reducers/search.js +++ b/src/client/react/reducers/search.js @@ -5,7 +5,7 @@ const DEFAULT_STATE = { const search = (state = DEFAULT_STATE, action) => { switch (action.type) { - case 'SEARCH/TYPE': + case 'SEARCH/INPUT_CHANGE': return { ...state, searchInput: action.typedValue, -- cgit v1.1 From 9f6a36d1f1a16c1a777a23fcc8c986c45ee0a116 Mon Sep 17 00:00:00 2001 From: Noah Loomans Date: Sun, 10 Dec 2017 13:25:46 +0100 Subject: Add some basic styling --- src/client/react/reducers/search.js | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'src/client/react/reducers') diff --git a/src/client/react/reducers/search.js b/src/client/react/reducers/search.js index 08be519..a695184 100644 --- a/src/client/react/reducers/search.js +++ b/src/client/react/reducers/search.js @@ -1,6 +1,7 @@ const DEFAULT_STATE = { searchInput: '', searchResults: [], + hasFocus: false, }; const search = (state = DEFAULT_STATE, action) => { @@ -13,6 +14,11 @@ const search = (state = DEFAULT_STATE, action) => { { type: 's', name: '18561' }, ], }; + case 'SEARCH/FOCUS_CHANGE': + return { + ...state, + hasFocus: action.hasFocus, + }; default: return state; } -- cgit v1.1 From 7e63aa14ea4298a1511f75e875ca001d2bd61ee8 Mon Sep 17 00:00:00 2001 From: Noah Loomans Date: Sun, 10 Dec 2017 13:53:07 +0100 Subject: Add results --- src/client/react/reducers/search.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/client/react/reducers') diff --git a/src/client/react/reducers/search.js b/src/client/react/reducers/search.js index a695184..50233a7 100644 --- a/src/client/react/reducers/search.js +++ b/src/client/react/reducers/search.js @@ -11,7 +11,7 @@ const search = (state = DEFAULT_STATE, action) => { ...state, searchInput: action.typedValue, searchResults: [ - { type: 's', name: '18561' }, + { type: 's', value: '18561' }, ], }; case 'SEARCH/FOCUS_CHANGE': -- cgit v1.1 From 29338e66b28daee52f7fe5a5cdab49140b3e5a60 Mon Sep 17 00:00:00 2001 From: Noah Loomans Date: Sun, 10 Dec 2017 14:06:11 +0100 Subject: Show correct icon based on user type --- src/client/react/reducers/search.js | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src/client/react/reducers') diff --git a/src/client/react/reducers/search.js b/src/client/react/reducers/search.js index 50233a7..4e2032d 100644 --- a/src/client/react/reducers/search.js +++ b/src/client/react/reducers/search.js @@ -12,6 +12,9 @@ const search = (state = DEFAULT_STATE, action) => { searchInput: action.typedValue, searchResults: [ { type: 's', value: '18561' }, + { type: 'c', value: '5H2' }, + { type: 't', value: 'akh' }, + { type: 'r', value: '008-mk' }, ], }; case 'SEARCH/FOCUS_CHANGE': -- cgit v1.1 From 36dc0fb88258af24069f61935656334c35ef13b3 Mon Sep 17 00:00:00 2001 From: Noah Loomans Date: Sun, 10 Dec 2017 14:23:35 +0100 Subject: Make search function --- src/client/react/reducers/search.js | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) (limited to 'src/client/react/reducers') diff --git a/src/client/react/reducers/search.js b/src/client/react/reducers/search.js index 4e2032d..72fa469 100644 --- a/src/client/react/reducers/search.js +++ b/src/client/react/reducers/search.js @@ -1,21 +1,36 @@ +/* global USERS */ +import fuzzy from 'fuzzy'; + const DEFAULT_STATE = { searchInput: '', - searchResults: [], + searchResults: [ + { type: 's', value: '18561' }, + ], hasFocus: false, }; +function getSearchResults(query) { + if (query.trim() === '') { + return []; + } + + const allResults = fuzzy.filter(query, USERS, { + extract: user => user.value, + }); + + const firstResults = allResults.splice(0, 4); + const users = firstResults.map(result => result.original); + + return users; +} + const search = (state = DEFAULT_STATE, action) => { switch (action.type) { case 'SEARCH/INPUT_CHANGE': return { ...state, searchInput: action.typedValue, - searchResults: [ - { type: 's', value: '18561' }, - { type: 'c', value: '5H2' }, - { type: 't', value: 'akh' }, - { type: 'r', value: '008-mk' }, - ], + searchResults: getSearchResults(action.typedValue), }; case 'SEARCH/FOCUS_CHANGE': return { -- cgit v1.1 From 797fb96cd0001d6c739c89507befc73d3d8a6614 Mon Sep 17 00:00:00 2001 From: Noah Loomans Date: Sun, 10 Dec 2017 15:58:25 +0100 Subject: Show user icon instead of search icon on exact match --- src/client/react/reducers/search.js | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) (limited to 'src/client/react/reducers') diff --git a/src/client/react/reducers/search.js b/src/client/react/reducers/search.js index 72fa469..dd737ed 100644 --- a/src/client/react/reducers/search.js +++ b/src/client/react/reducers/search.js @@ -6,6 +6,7 @@ const DEFAULT_STATE = { searchResults: [ { type: 's', value: '18561' }, ], + exactMatch: null, hasFocus: false, }; @@ -26,12 +27,22 @@ function getSearchResults(query) { const search = (state = DEFAULT_STATE, action) => { switch (action.type) { - case 'SEARCH/INPUT_CHANGE': + case 'SEARCH/INPUT_CHANGE': { + let results = getSearchResults(action.typedValue); + let exactMatch = false; + + if ((results.length > 0) && (action.typedValue === results[0].value)) { + [exactMatch] = results; + results = results.splice(1); + } + return { ...state, searchInput: action.typedValue, - searchResults: getSearchResults(action.typedValue), + searchResults: results, + exactMatch, }; + } case 'SEARCH/FOCUS_CHANGE': return { ...state, -- cgit v1.1 From 088f0a2c1ca5d305d83ff001650cca729643c718 Mon Sep 17 00:00:00 2001 From: Noah Loomans Date: Sun, 10 Dec 2017 19:12:20 +0100 Subject: Use when when there is no exact match --- src/client/react/reducers/search.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/client/react/reducers') diff --git a/src/client/react/reducers/search.js b/src/client/react/reducers/search.js index dd737ed..5d8fee5 100644 --- a/src/client/react/reducers/search.js +++ b/src/client/react/reducers/search.js @@ -29,7 +29,7 @@ const search = (state = DEFAULT_STATE, action) => { switch (action.type) { case 'SEARCH/INPUT_CHANGE': { let results = getSearchResults(action.typedValue); - let exactMatch = false; + let exactMatch = null; if ((results.length > 0) && (action.typedValue === results[0].value)) { [exactMatch] = results; -- cgit v1.1 From ddccdcf22bb5008022e93c4789311fb2da95d7cf Mon Sep 17 00:00:00 2001 From: Noah Loomans Date: Sun, 10 Dec 2017 19:24:53 +0100 Subject: Refactor state names --- src/client/react/reducers/search.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'src/client/react/reducers') diff --git a/src/client/react/reducers/search.js b/src/client/react/reducers/search.js index 5d8fee5..52f3b4e 100644 --- a/src/client/react/reducers/search.js +++ b/src/client/react/reducers/search.js @@ -2,8 +2,8 @@ import fuzzy from 'fuzzy'; const DEFAULT_STATE = { - searchInput: '', - searchResults: [ + input: '', + results: [ { type: 's', value: '18561' }, ], exactMatch: null, @@ -31,6 +31,8 @@ const search = (state = DEFAULT_STATE, action) => { let results = getSearchResults(action.typedValue); let exactMatch = null; + // Is the typed value exactly the same as the first result? Then show the + // appropiate icon instead of the generic search icon. if ((results.length > 0) && (action.typedValue === results[0].value)) { [exactMatch] = results; results = results.splice(1); @@ -38,8 +40,8 @@ const search = (state = DEFAULT_STATE, action) => { return { ...state, - searchInput: action.typedValue, - searchResults: results, + input: action.typedValue, + results, exactMatch, }; } -- cgit v1.1 From b00e556ebff50558e6532683ff2763825c51646f Mon Sep 17 00:00:00 2001 From: Noah Loomans Date: Mon, 11 Dec 2017 20:52:17 +0100 Subject: Move hasFocus to internal state --- src/client/react/reducers/search.js | 6 ------ 1 file changed, 6 deletions(-) (limited to 'src/client/react/reducers') diff --git a/src/client/react/reducers/search.js b/src/client/react/reducers/search.js index 52f3b4e..d61689b 100644 --- a/src/client/react/reducers/search.js +++ b/src/client/react/reducers/search.js @@ -7,7 +7,6 @@ const DEFAULT_STATE = { { type: 's', value: '18561' }, ], exactMatch: null, - hasFocus: false, }; function getSearchResults(query) { @@ -45,11 +44,6 @@ const search = (state = DEFAULT_STATE, action) => { exactMatch, }; } - case 'SEARCH/FOCUS_CHANGE': - return { - ...state, - hasFocus: action.hasFocus, - }; default: return state; } -- cgit v1.1 From fe27a0819a60caaa69b059f0c86d95ab0c4084b7 Mon Sep 17 00:00:00 2001 From: Noah Loomans Date: Wed, 13 Dec 2017 12:26:36 +0100 Subject: Prepair changeSelectedResult --- src/client/react/reducers/search.js | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'src/client/react/reducers') diff --git a/src/client/react/reducers/search.js b/src/client/react/reducers/search.js index d61689b..f566b49 100644 --- a/src/client/react/reducers/search.js +++ b/src/client/react/reducers/search.js @@ -6,7 +6,8 @@ const DEFAULT_STATE = { results: [ { type: 's', value: '18561' }, ], - exactMatch: null, + selectedResult: null, + isExactMatch: false, }; function getSearchResults(query) { @@ -28,12 +29,14 @@ const search = (state = DEFAULT_STATE, action) => { switch (action.type) { case 'SEARCH/INPUT_CHANGE': { let results = getSearchResults(action.typedValue); - let exactMatch = null; + let selectedResult = null; + let isExactMatch = false; // Is the typed value exactly the same as the first result? Then show the // appropiate icon instead of the generic search icon. if ((results.length > 0) && (action.typedValue === results[0].value)) { - [exactMatch] = results; + [selectedResult] = results; + isExactMatch = true; results = results.splice(1); } @@ -41,7 +44,8 @@ const search = (state = DEFAULT_STATE, action) => { ...state, input: action.typedValue, results, - exactMatch, + selectedResult, + isExactMatch, }; } default: -- cgit v1.1 From 503ab5c66ab524dfe36aed84a01899cd07ed2bc5 Mon Sep 17 00:00:00 2001 From: Noah Loomans Date: Wed, 13 Dec 2017 15:53:19 +0100 Subject: Allow selection of result using keyboard --- src/client/react/reducers/search.js | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) (limited to 'src/client/react/reducers') diff --git a/src/client/react/reducers/search.js b/src/client/react/reducers/search.js index f566b49..6ef0f4d 100644 --- a/src/client/react/reducers/search.js +++ b/src/client/react/reducers/search.js @@ -48,6 +48,34 @@ const search = (state = DEFAULT_STATE, action) => { isExactMatch, }; } + + case 'SEARCH/CHANGE_SELECTED_RESULT': { + const { results, isExactMatch } = 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; + } + + let nextSelectedResult = + nextSelectedResultIndex === -1 + ? null + : results[nextSelectedResultIndex]; + + if (isExactMatch) { + nextSelectedResult = prevSelectedResult; + } + + return { + ...state, + selectedResult: nextSelectedResult, + }; + } default: return state; } -- cgit v1.1 From 778dfdc728a101fca9ece3a14e590d3b8e1d43e1 Mon Sep 17 00:00:00 2001 From: Noah Loomans Date: Thu, 14 Dec 2017 12:32:07 +0100 Subject: Use id's instead of user objects --- src/client/react/reducers/search.js | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) (limited to 'src/client/react/reducers') diff --git a/src/client/react/reducers/search.js b/src/client/react/reducers/search.js index 6ef0f4d..cad491b 100644 --- a/src/client/react/reducers/search.js +++ b/src/client/react/reducers/search.js @@ -1,43 +1,42 @@ -/* global USERS */ import fuzzy from 'fuzzy'; +import users from '../users'; const DEFAULT_STATE = { input: '', results: [ - { type: 's', value: '18561' }, + 's/18562', ], selectedResult: null, isExactMatch: false, }; -function getSearchResults(query) { +function getSearchResults(allUsers, query) { if (query.trim() === '') { return []; } - const allResults = fuzzy.filter(query, USERS, { + const allResults = fuzzy.filter(query, allUsers, { extract: user => user.value, }); const firstResults = allResults.splice(0, 4); - const users = firstResults.map(result => result.original); + const userIds = firstResults.map(result => result.original.id); - return users; + return userIds; } const search = (state = DEFAULT_STATE, action) => { switch (action.type) { case 'SEARCH/INPUT_CHANGE': { - let results = getSearchResults(action.typedValue); + const results = getSearchResults(users.allUsers, action.typedValue); let selectedResult = null; let isExactMatch = false; // Is the typed value exactly the same as the first result? Then show the // appropiate icon instead of the generic search icon. - if ((results.length > 0) && (action.typedValue === results[0].value)) { + if ((results.length === 1) && (action.typedValue === users.byId[results[0]].value)) { [selectedResult] = results; isExactMatch = true; - results = results.splice(1); } return { @@ -51,6 +50,9 @@ const search = (state = DEFAULT_STATE, action) => { case 'SEARCH/CHANGE_SELECTED_RESULT': { const { results, isExactMatch } = state; + + if (isExactMatch) return state; + const prevSelectedResult = state.selectedResult; const prevSelectedResultIndex = results.indexOf(prevSelectedResult); let nextSelectedResultIndex = @@ -62,15 +64,11 @@ const search = (state = DEFAULT_STATE, action) => { nextSelectedResultIndex = -1; } - let nextSelectedResult = + const nextSelectedResult = nextSelectedResultIndex === -1 ? null : results[nextSelectedResultIndex]; - if (isExactMatch) { - nextSelectedResult = prevSelectedResult; - } - return { ...state, selectedResult: nextSelectedResult, -- cgit v1.1 From a77272bfbebed7239c0c49049e211f4a6e597617 Mon Sep 17 00:00:00 2001 From: Noah Loomans Date: Thu, 14 Dec 2017 12:32:13 +0100 Subject: Add tests for search.js --- src/client/react/reducers/search.test.js | 142 +++++++++++++++++++++++++++++++ 1 file changed, 142 insertions(+) create mode 100644 src/client/react/reducers/search.test.js (limited to 'src/client/react/reducers') diff --git a/src/client/react/reducers/search.test.js b/src/client/react/reducers/search.test.js new file mode 100644 index 0000000..ccf6fae --- /dev/null +++ b/src/client/react/reducers/search.test.js @@ -0,0 +1,142 @@ +window.USERS = []; + +const deepFreeze = require('deep-freeze'); +const search = require('./search').default; +const { changeSelectedResult } = require('../actions/search'); + +describe('reducers', () => { + describe('search', () => { + describe('SEARCH/CHANGE_SELECTED_RESULT', () => { + it('Does nothing when there are no results', () => { + const prevState = { + results: [], + selectedResult: null, + isExactMatch: false, + }; + + const actionPlus = changeSelectedResult(+1); + const actionMin = changeSelectedResult(-1); + + deepFreeze([prevState, actionPlus, actionMin]); + + const nextStatePlus = search(prevState, actionPlus); + const nextStateMin = search(prevState, actionMin); + expect(nextStatePlus).toEqual(prevState); + expect(nextStateMin).toEqual(prevState); + }); + + it('Does nothing when there is an exact match', () => { + const prevState = { + results: ['s/18561'], + selectedResult: 's/18561', + isExactMatch: true, + }; + + const actionPlus = changeSelectedResult(+1); + const actionMin = changeSelectedResult(-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'], + selectedResult: null, + isExactMatch: false, + }; + + const actionPlus = changeSelectedResult(+1); + const actionMin = changeSelectedResult(-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'], + selectedResult: 's/18562', + isExactMatch: false, + }; + + const actionPlus = changeSelectedResult(+1); + const actionMin = changeSelectedResult(-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 arround when incrementing', () => { + expect(search({ + results: ['s/18561', 's/18562', 's/18563'], + selectedResult: 's/18563', + isExactMatch: false, + }, changeSelectedResult(+1))).toEqual({ + results: ['s/18561', 's/18562', 's/18563'], + selectedResult: null, + isExactMatch: false, + }); + + expect(search({ + results: ['s/18561', 's/18562', 's/18563'], + selectedResult: null, + isExactMatch: false, + }, changeSelectedResult(+1))).toEqual({ + results: ['s/18561', 's/18562', 's/18563'], + selectedResult: 's/18561', + isExactMatch: false, + }); + }); + + it('Properly wraps arround when decrementing', () => { + expect(search({ + results: ['s/18561', 's/18562', 's/18563'], + selectedResult: 's/18561', + isExactMatch: false, + }, changeSelectedResult(-1))).toEqual({ + results: ['s/18561', 's/18562', 's/18563'], + selectedResult: null, + isExactMatch: false, + }); + + expect(search({ + results: ['s/18561', 's/18562', 's/18563'], + selectedResult: null, + isExactMatch: false, + }, changeSelectedResult(-1))).toEqual({ + results: ['s/18561', 's/18562', 's/18563'], + selectedResult: 's/18563', + isExactMatch: false, + }); + }); + }); + }); +}); -- cgit v1.1 From 5caa2d35af001302b4b837ede18ef5c7041287af Mon Sep 17 00:00:00 2001 From: Noah Loomans Date: Thu, 14 Dec 2017 12:45:23 +0100 Subject: Add tests for SEARCH/INPUT_CHANGE --- src/client/react/reducers/search.test.js | 59 ++++++++++++++++++++++++++++++-- 1 file changed, 57 insertions(+), 2 deletions(-) (limited to 'src/client/react/reducers') diff --git a/src/client/react/reducers/search.test.js b/src/client/react/reducers/search.test.js index ccf6fae..13f79d2 100644 --- a/src/client/react/reducers/search.test.js +++ b/src/client/react/reducers/search.test.js @@ -1,11 +1,66 @@ -window.USERS = []; +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 { changeSelectedResult } = require('../actions/search'); +const { inputChange, changeSelectedResult } = require('../actions/search'); describe('reducers', () => { describe('search', () => { + describe('SEARCH/INPUT_CHANGE', () => { + it('Returns no results when nothing is typed in', () => { + expect(search(undefined, inputChange(''))).toEqual({ + input: '', + results: [], + selectedResult: null, + isExactMatch: false, + }); + }); + + it('Returns no results when a space is typed in', () => { + expect(search(undefined, inputChange(' '))).toEqual({ + input: ' ', + results: [], + selectedResult: null, + isExactMatch: false, + }); + }); + + it('Preforms a basic search, only returning four results', () => { + expect(search(undefined, inputChange('18'))).toEqual({ + input: '18', + results: [ + 's/18561', + 's/18562', + 's/18563', + 's/18564', + ], + selectedResult: null, + isExactMatch: false, + }); + }); + + it('Selects the first result and sets isExactMatch to true when there is an exact match', () => { + expect(search(undefined, inputChange('18561'))).toEqual({ + input: '18561', + results: [ + 's/18561', + ], + selectedResult: 's/18561', + isExactMatch: true, + }); + }); + }); + describe('SEARCH/CHANGE_SELECTED_RESULT', () => { it('Does nothing when there are no results', () => { const prevState = { -- cgit v1.1 From ebb7aaf5d62fea0d3b9ac0ceb7c8b3fa3578ba59 Mon Sep 17 00:00:00 2001 From: Noah Loomans Date: Thu, 14 Dec 2017 12:47:02 +0100 Subject: Add an extra new line --- src/client/react/reducers/search.js | 1 + 1 file changed, 1 insertion(+) (limited to 'src/client/react/reducers') diff --git a/src/client/react/reducers/search.js b/src/client/react/reducers/search.js index cad491b..29d0e5c 100644 --- a/src/client/react/reducers/search.js +++ b/src/client/react/reducers/search.js @@ -74,6 +74,7 @@ const search = (state = DEFAULT_STATE, action) => { selectedResult: nextSelectedResult, }; } + default: return state; } -- cgit v1.1 From bb5b3629445ed6a52c3a088dbc2dd08b7a326f8a Mon Sep 17 00:00:00 2001 From: Noah Loomans Date: Thu, 14 Dec 2017 16:24:10 +0100 Subject: Remove input value from redux --- src/client/react/reducers/search.js | 2 -- src/client/react/reducers/search.test.js | 4 ---- 2 files changed, 6 deletions(-) (limited to 'src/client/react/reducers') diff --git a/src/client/react/reducers/search.js b/src/client/react/reducers/search.js index 29d0e5c..2a7e7a5 100644 --- a/src/client/react/reducers/search.js +++ b/src/client/react/reducers/search.js @@ -2,7 +2,6 @@ import fuzzy from 'fuzzy'; import users from '../users'; const DEFAULT_STATE = { - input: '', results: [ 's/18562', ], @@ -41,7 +40,6 @@ const search = (state = DEFAULT_STATE, action) => { return { ...state, - input: action.typedValue, results, selectedResult, isExactMatch, diff --git a/src/client/react/reducers/search.test.js b/src/client/react/reducers/search.test.js index 13f79d2..e0ca18e 100644 --- a/src/client/react/reducers/search.test.js +++ b/src/client/react/reducers/search.test.js @@ -19,7 +19,6 @@ describe('reducers', () => { describe('SEARCH/INPUT_CHANGE', () => { it('Returns no results when nothing is typed in', () => { expect(search(undefined, inputChange(''))).toEqual({ - input: '', results: [], selectedResult: null, isExactMatch: false, @@ -28,7 +27,6 @@ describe('reducers', () => { it('Returns no results when a space is typed in', () => { expect(search(undefined, inputChange(' '))).toEqual({ - input: ' ', results: [], selectedResult: null, isExactMatch: false, @@ -37,7 +35,6 @@ describe('reducers', () => { it('Preforms a basic search, only returning four results', () => { expect(search(undefined, inputChange('18'))).toEqual({ - input: '18', results: [ 's/18561', 's/18562', @@ -51,7 +48,6 @@ describe('reducers', () => { it('Selects the first result and sets isExactMatch to true when there is an exact match', () => { expect(search(undefined, inputChange('18561'))).toEqual({ - input: '18561', results: [ 's/18561', ], -- cgit v1.1 From f0c8cf0e79f003514fd65a70def5820205955a77 Mon Sep 17 00:00:00 2001 From: Noah Loomans Date: Thu, 21 Dec 2017 12:06:41 +0100 Subject: Move to typescript --- src/client/react/reducers/search.js | 81 ------------- src/client/react/reducers/search.test.js | 193 ------------------------------- src/client/react/reducers/search.test.ts | 193 +++++++++++++++++++++++++++++++ src/client/react/reducers/search.ts | 90 ++++++++++++++ 4 files changed, 283 insertions(+), 274 deletions(-) delete mode 100644 src/client/react/reducers/search.js delete mode 100644 src/client/react/reducers/search.test.js create mode 100644 src/client/react/reducers/search.test.ts create mode 100644 src/client/react/reducers/search.ts (limited to 'src/client/react/reducers') diff --git a/src/client/react/reducers/search.js b/src/client/react/reducers/search.js deleted file mode 100644 index 2a7e7a5..0000000 --- a/src/client/react/reducers/search.js +++ /dev/null @@ -1,81 +0,0 @@ -import fuzzy from 'fuzzy'; -import users from '../users'; - -const DEFAULT_STATE = { - results: [ - 's/18562', - ], - selectedResult: null, - isExactMatch: false, -}; - -function getSearchResults(allUsers, query) { - if (query.trim() === '') { - return []; - } - - const allResults = fuzzy.filter(query, allUsers, { - extract: user => user.value, - }); - - const firstResults = allResults.splice(0, 4); - const userIds = firstResults.map(result => result.original.id); - - return userIds; -} - -const search = (state = DEFAULT_STATE, action) => { - switch (action.type) { - case 'SEARCH/INPUT_CHANGE': { - const results = getSearchResults(users.allUsers, action.typedValue); - let selectedResult = null; - let isExactMatch = false; - - // Is the typed value exactly the same as the first result? Then show the - // appropiate icon instead of the generic search icon. - if ((results.length === 1) && (action.typedValue === users.byId[results[0]].value)) { - [selectedResult] = results; - isExactMatch = true; - } - - return { - ...state, - results, - selectedResult, - isExactMatch, - }; - } - - case 'SEARCH/CHANGE_SELECTED_RESULT': { - const { results, isExactMatch } = state; - - if (isExactMatch) return 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; diff --git a/src/client/react/reducers/search.test.js b/src/client/react/reducers/search.test.js deleted file mode 100644 index e0ca18e..0000000 --- a/src/client/react/reducers/search.test.js +++ /dev/null @@ -1,193 +0,0 @@ -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 { inputChange, changeSelectedResult } = require('../actions/search'); - -describe('reducers', () => { - describe('search', () => { - describe('SEARCH/INPUT_CHANGE', () => { - it('Returns no results when nothing is typed in', () => { - expect(search(undefined, inputChange(''))).toEqual({ - results: [], - selectedResult: null, - isExactMatch: false, - }); - }); - - it('Returns no results when a space is typed in', () => { - expect(search(undefined, inputChange(' '))).toEqual({ - results: [], - selectedResult: null, - isExactMatch: false, - }); - }); - - it('Preforms a basic search, only returning four results', () => { - expect(search(undefined, inputChange('18'))).toEqual({ - results: [ - 's/18561', - 's/18562', - 's/18563', - 's/18564', - ], - selectedResult: null, - isExactMatch: false, - }); - }); - - it('Selects the first result and sets isExactMatch to true when there is an exact match', () => { - expect(search(undefined, inputChange('18561'))).toEqual({ - results: [ - 's/18561', - ], - selectedResult: 's/18561', - isExactMatch: true, - }); - }); - }); - - describe('SEARCH/CHANGE_SELECTED_RESULT', () => { - it('Does nothing when there are no results', () => { - const prevState = { - results: [], - selectedResult: null, - isExactMatch: false, - }; - - const actionPlus = changeSelectedResult(+1); - const actionMin = changeSelectedResult(-1); - - deepFreeze([prevState, actionPlus, actionMin]); - - const nextStatePlus = search(prevState, actionPlus); - const nextStateMin = search(prevState, actionMin); - expect(nextStatePlus).toEqual(prevState); - expect(nextStateMin).toEqual(prevState); - }); - - it('Does nothing when there is an exact match', () => { - const prevState = { - results: ['s/18561'], - selectedResult: 's/18561', - isExactMatch: true, - }; - - const actionPlus = changeSelectedResult(+1); - const actionMin = changeSelectedResult(-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'], - selectedResult: null, - isExactMatch: false, - }; - - const actionPlus = changeSelectedResult(+1); - const actionMin = changeSelectedResult(-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'], - selectedResult: 's/18562', - isExactMatch: false, - }; - - const actionPlus = changeSelectedResult(+1); - const actionMin = changeSelectedResult(-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 arround when incrementing', () => { - expect(search({ - results: ['s/18561', 's/18562', 's/18563'], - selectedResult: 's/18563', - isExactMatch: false, - }, changeSelectedResult(+1))).toEqual({ - results: ['s/18561', 's/18562', 's/18563'], - selectedResult: null, - isExactMatch: false, - }); - - expect(search({ - results: ['s/18561', 's/18562', 's/18563'], - selectedResult: null, - isExactMatch: false, - }, changeSelectedResult(+1))).toEqual({ - results: ['s/18561', 's/18562', 's/18563'], - selectedResult: 's/18561', - isExactMatch: false, - }); - }); - - it('Properly wraps arround when decrementing', () => { - expect(search({ - results: ['s/18561', 's/18562', 's/18563'], - selectedResult: 's/18561', - isExactMatch: false, - }, changeSelectedResult(-1))).toEqual({ - results: ['s/18561', 's/18562', 's/18563'], - selectedResult: null, - isExactMatch: false, - }); - - expect(search({ - results: ['s/18561', 's/18562', 's/18563'], - selectedResult: null, - isExactMatch: false, - }, changeSelectedResult(-1))).toEqual({ - results: ['s/18561', 's/18562', 's/18563'], - selectedResult: 's/18563', - isExactMatch: false, - }); - }); - }); - }); -}); diff --git a/src/client/react/reducers/search.test.ts b/src/client/react/reducers/search.test.ts new file mode 100644 index 0000000..5869b81 --- /dev/null +++ b/src/client/react/reducers/search.test.ts @@ -0,0 +1,193 @@ +(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 { inputChange, changeSelectedResult } = require('../actions/search'); + +describe('reducers', () => { + describe('search', () => { + describe('SEARCH/INPUT_CHANGE', () => { + it('Returns no results when nothing is typed in', () => { + expect(search(undefined, inputChange(''))).toEqual({ + results: [], + selectedResult: null, + isExactMatch: false, + }); + }); + + it('Returns no results when a space is typed in', () => { + expect(search(undefined, inputChange(' '))).toEqual({ + results: [], + selectedResult: null, + isExactMatch: false, + }); + }); + + it('Preforms a basic search, only returning four results', () => { + expect(search(undefined, inputChange('18'))).toEqual({ + results: [ + 's/18561', + 's/18562', + 's/18563', + 's/18564', + ], + selectedResult: null, + isExactMatch: false, + }); + }); + + it('Selects the first result and sets isExactMatch to true when there is an exact match', () => { + expect(search(undefined, inputChange('18561'))).toEqual({ + results: [ + 's/18561', + ], + selectedResult: 's/18561', + isExactMatch: true, + }); + }); + }); + + describe('SEARCH/CHANGE_SELECTED_RESULT', () => { + it('Does nothing when there are no results', () => { + const prevState = { + results: [], + selectedResult: null, + isExactMatch: false, + }; + + const actionPlus = changeSelectedResult(+1); + const actionMin = changeSelectedResult(-1); + + deepFreeze([prevState, actionPlus, actionMin]); + + const nextStatePlus = search(prevState, actionPlus); + const nextStateMin = search(prevState, actionMin); + expect(nextStatePlus).toEqual(prevState); + expect(nextStateMin).toEqual(prevState); + }); + + it('Does nothing when there is an exact match', () => { + const prevState = { + results: ['s/18561'], + selectedResult: 's/18561', + isExactMatch: true, + }; + + const actionPlus = changeSelectedResult(+1); + const actionMin = changeSelectedResult(-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'], + selectedResult: null, + isExactMatch: false, + }; + + const actionPlus = changeSelectedResult(+1); + const actionMin = changeSelectedResult(-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'], + selectedResult: 's/18562', + isExactMatch: false, + }; + + const actionPlus = changeSelectedResult(+1); + const actionMin = changeSelectedResult(-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 arround when incrementing', () => { + expect(search({ + results: ['s/18561', 's/18562', 's/18563'], + selectedResult: 's/18563', + isExactMatch: false, + }, changeSelectedResult(+1))).toEqual({ + results: ['s/18561', 's/18562', 's/18563'], + selectedResult: null, + isExactMatch: false, + }); + + expect(search({ + results: ['s/18561', 's/18562', 's/18563'], + selectedResult: null, + isExactMatch: false, + }, changeSelectedResult(+1))).toEqual({ + results: ['s/18561', 's/18562', 's/18563'], + selectedResult: 's/18561', + isExactMatch: false, + }); + }); + + it('Properly wraps arround when decrementing', () => { + expect(search({ + results: ['s/18561', 's/18562', 's/18563'], + selectedResult: 's/18561', + isExactMatch: false, + }, changeSelectedResult(-1))).toEqual({ + results: ['s/18561', 's/18562', 's/18563'], + selectedResult: null, + isExactMatch: false, + }); + + expect(search({ + results: ['s/18561', 's/18562', 's/18563'], + selectedResult: null, + isExactMatch: false, + }, changeSelectedResult(-1))).toEqual({ + results: ['s/18561', 's/18562', 's/18563'], + selectedResult: 's/18563', + isExactMatch: false, + }); + }); + }); + }); +}); diff --git a/src/client/react/reducers/search.ts b/src/client/react/reducers/search.ts new file mode 100644 index 0000000..658d3ca --- /dev/null +++ b/src/client/react/reducers/search.ts @@ -0,0 +1,90 @@ +import * as fuzzy from 'fuzzy'; +import users, { User } from '../users'; +import { InputChangeAction, ChangeSelectedResultAction } from '../actions/search'; + +export interface State { + results: string[], + selectedResult: string | null, + isExactMatch: boolean, +}; + +export type Action = InputChangeAction | ChangeSelectedResultAction; + +const DEFAULT_STATE: State = { + results: [ + 's/18562', + ], + selectedResult: null, + isExactMatch: false, +}; + +function getSearchResults(allUsers: User[], query: string) { + if (query.trim() === '') { + return []; + } + + const allResults = fuzzy.filter(query, allUsers, { + extract: (user: User) => user.value, + }); + + const firstResults = allResults.splice(0, 4); + const userIds = firstResults.map((result: { original: User }) => result.original.id); + + return userIds; +} + +const search = (state = DEFAULT_STATE, action: Action): State => { + switch (action.type) { + case 'SEARCH/INPUT_CHANGE': { + const results = getSearchResults(users.allUsers, action.typedValue); + let selectedResult = null; + let isExactMatch = false; + + // Is the typed value exactly the same as the first result? Then show the + // appropiate icon instead of the generic search icon. + if ((results.length === 1) && (action.typedValue === users.byId[results[0]].value)) { + [selectedResult] = results; + isExactMatch = true; + } + + return { + ...state, + results, + selectedResult, + isExactMatch, + }; + } + + case 'SEARCH/CHANGE_SELECTED_RESULT': { + const { results, isExactMatch } = state; + + if (isExactMatch) return 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; -- cgit v1.1 From 4ca30295d7d9f3dd7ba2e105952ff627f6b702a4 Mon Sep 17 00:00:00 2001 From: Noah Loomans Date: Thu, 21 Dec 2017 13:10:05 +0100 Subject: Add strict typing Except for functions because of https://github.com/reactjs/redux/issues/2709 --- src/client/react/reducers/search.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/client/react/reducers') diff --git a/src/client/react/reducers/search.ts b/src/client/react/reducers/search.ts index 658d3ca..470e650 100644 --- a/src/client/react/reducers/search.ts +++ b/src/client/react/reducers/search.ts @@ -61,7 +61,7 @@ const search = (state = DEFAULT_STATE, action: Action): State => { if (isExactMatch) return state; const prevSelectedResult = state.selectedResult; - const prevSelectedResultIndex = results.indexOf(prevSelectedResult); + const prevSelectedResultIndex = prevSelectedResult ? results.indexOf(prevSelectedResult) : -1; let nextSelectedResultIndex = prevSelectedResultIndex + action.relativeChange; -- cgit v1.1 From 95041dffbd23fe81802efd5fb25cffe492cdb551 Mon Sep 17 00:00:00 2001 From: Noah Loomans Date: Sat, 6 Jan 2018 12:11:05 +0100 Subject: Revert "Add strict typing" This reverts commit 4ca30295d7d9f3dd7ba2e105952ff627f6b702a4. --- src/client/react/reducers/search.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/client/react/reducers') diff --git a/src/client/react/reducers/search.ts b/src/client/react/reducers/search.ts index 470e650..658d3ca 100644 --- a/src/client/react/reducers/search.ts +++ b/src/client/react/reducers/search.ts @@ -61,7 +61,7 @@ const search = (state = DEFAULT_STATE, action: Action): State => { if (isExactMatch) return state; const prevSelectedResult = state.selectedResult; - const prevSelectedResultIndex = prevSelectedResult ? results.indexOf(prevSelectedResult) : -1; + const prevSelectedResultIndex = results.indexOf(prevSelectedResult); let nextSelectedResultIndex = prevSelectedResultIndex + action.relativeChange; -- cgit v1.1 From 77dccd31b32ee0a9a53b2186bae231069c5ab152 Mon Sep 17 00:00:00 2001 From: Noah Loomans Date: Sat, 6 Jan 2018 12:11:19 +0100 Subject: Revert "Move to typescript" This reverts commit f0c8cf0e79f003514fd65a70def5820205955a77. --- src/client/react/reducers/search.js | 81 +++++++++++++ src/client/react/reducers/search.test.js | 193 +++++++++++++++++++++++++++++++ src/client/react/reducers/search.test.ts | 193 ------------------------------- src/client/react/reducers/search.ts | 90 -------------- 4 files changed, 274 insertions(+), 283 deletions(-) create mode 100644 src/client/react/reducers/search.js create mode 100644 src/client/react/reducers/search.test.js delete mode 100644 src/client/react/reducers/search.test.ts delete mode 100644 src/client/react/reducers/search.ts (limited to 'src/client/react/reducers') diff --git a/src/client/react/reducers/search.js b/src/client/react/reducers/search.js new file mode 100644 index 0000000..2a7e7a5 --- /dev/null +++ b/src/client/react/reducers/search.js @@ -0,0 +1,81 @@ +import fuzzy from 'fuzzy'; +import users from '../users'; + +const DEFAULT_STATE = { + results: [ + 's/18562', + ], + selectedResult: null, + isExactMatch: false, +}; + +function getSearchResults(allUsers, query) { + if (query.trim() === '') { + return []; + } + + const allResults = fuzzy.filter(query, allUsers, { + extract: user => user.value, + }); + + const firstResults = allResults.splice(0, 4); + const userIds = firstResults.map(result => result.original.id); + + return userIds; +} + +const search = (state = DEFAULT_STATE, action) => { + switch (action.type) { + case 'SEARCH/INPUT_CHANGE': { + const results = getSearchResults(users.allUsers, action.typedValue); + let selectedResult = null; + let isExactMatch = false; + + // Is the typed value exactly the same as the first result? Then show the + // appropiate icon instead of the generic search icon. + if ((results.length === 1) && (action.typedValue === users.byId[results[0]].value)) { + [selectedResult] = results; + isExactMatch = true; + } + + return { + ...state, + results, + selectedResult, + isExactMatch, + }; + } + + case 'SEARCH/CHANGE_SELECTED_RESULT': { + const { results, isExactMatch } = state; + + if (isExactMatch) return 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; diff --git a/src/client/react/reducers/search.test.js b/src/client/react/reducers/search.test.js new file mode 100644 index 0000000..e0ca18e --- /dev/null +++ b/src/client/react/reducers/search.test.js @@ -0,0 +1,193 @@ +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 { inputChange, changeSelectedResult } = require('../actions/search'); + +describe('reducers', () => { + describe('search', () => { + describe('SEARCH/INPUT_CHANGE', () => { + it('Returns no results when nothing is typed in', () => { + expect(search(undefined, inputChange(''))).toEqual({ + results: [], + selectedResult: null, + isExactMatch: false, + }); + }); + + it('Returns no results when a space is typed in', () => { + expect(search(undefined, inputChange(' '))).toEqual({ + results: [], + selectedResult: null, + isExactMatch: false, + }); + }); + + it('Preforms a basic search, only returning four results', () => { + expect(search(undefined, inputChange('18'))).toEqual({ + results: [ + 's/18561', + 's/18562', + 's/18563', + 's/18564', + ], + selectedResult: null, + isExactMatch: false, + }); + }); + + it('Selects the first result and sets isExactMatch to true when there is an exact match', () => { + expect(search(undefined, inputChange('18561'))).toEqual({ + results: [ + 's/18561', + ], + selectedResult: 's/18561', + isExactMatch: true, + }); + }); + }); + + describe('SEARCH/CHANGE_SELECTED_RESULT', () => { + it('Does nothing when there are no results', () => { + const prevState = { + results: [], + selectedResult: null, + isExactMatch: false, + }; + + const actionPlus = changeSelectedResult(+1); + const actionMin = changeSelectedResult(-1); + + deepFreeze([prevState, actionPlus, actionMin]); + + const nextStatePlus = search(prevState, actionPlus); + const nextStateMin = search(prevState, actionMin); + expect(nextStatePlus).toEqual(prevState); + expect(nextStateMin).toEqual(prevState); + }); + + it('Does nothing when there is an exact match', () => { + const prevState = { + results: ['s/18561'], + selectedResult: 's/18561', + isExactMatch: true, + }; + + const actionPlus = changeSelectedResult(+1); + const actionMin = changeSelectedResult(-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'], + selectedResult: null, + isExactMatch: false, + }; + + const actionPlus = changeSelectedResult(+1); + const actionMin = changeSelectedResult(-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'], + selectedResult: 's/18562', + isExactMatch: false, + }; + + const actionPlus = changeSelectedResult(+1); + const actionMin = changeSelectedResult(-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 arround when incrementing', () => { + expect(search({ + results: ['s/18561', 's/18562', 's/18563'], + selectedResult: 's/18563', + isExactMatch: false, + }, changeSelectedResult(+1))).toEqual({ + results: ['s/18561', 's/18562', 's/18563'], + selectedResult: null, + isExactMatch: false, + }); + + expect(search({ + results: ['s/18561', 's/18562', 's/18563'], + selectedResult: null, + isExactMatch: false, + }, changeSelectedResult(+1))).toEqual({ + results: ['s/18561', 's/18562', 's/18563'], + selectedResult: 's/18561', + isExactMatch: false, + }); + }); + + it('Properly wraps arround when decrementing', () => { + expect(search({ + results: ['s/18561', 's/18562', 's/18563'], + selectedResult: 's/18561', + isExactMatch: false, + }, changeSelectedResult(-1))).toEqual({ + results: ['s/18561', 's/18562', 's/18563'], + selectedResult: null, + isExactMatch: false, + }); + + expect(search({ + results: ['s/18561', 's/18562', 's/18563'], + selectedResult: null, + isExactMatch: false, + }, changeSelectedResult(-1))).toEqual({ + results: ['s/18561', 's/18562', 's/18563'], + selectedResult: 's/18563', + isExactMatch: false, + }); + }); + }); + }); +}); diff --git a/src/client/react/reducers/search.test.ts b/src/client/react/reducers/search.test.ts deleted file mode 100644 index 5869b81..0000000 --- a/src/client/react/reducers/search.test.ts +++ /dev/null @@ -1,193 +0,0 @@ -(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 { inputChange, changeSelectedResult } = require('../actions/search'); - -describe('reducers', () => { - describe('search', () => { - describe('SEARCH/INPUT_CHANGE', () => { - it('Returns no results when nothing is typed in', () => { - expect(search(undefined, inputChange(''))).toEqual({ - results: [], - selectedResult: null, - isExactMatch: false, - }); - }); - - it('Returns no results when a space is typed in', () => { - expect(search(undefined, inputChange(' '))).toEqual({ - results: [], - selectedResult: null, - isExactMatch: false, - }); - }); - - it('Preforms a basic search, only returning four results', () => { - expect(search(undefined, inputChange('18'))).toEqual({ - results: [ - 's/18561', - 's/18562', - 's/18563', - 's/18564', - ], - selectedResult: null, - isExactMatch: false, - }); - }); - - it('Selects the first result and sets isExactMatch to true when there is an exact match', () => { - expect(search(undefined, inputChange('18561'))).toEqual({ - results: [ - 's/18561', - ], - selectedResult: 's/18561', - isExactMatch: true, - }); - }); - }); - - describe('SEARCH/CHANGE_SELECTED_RESULT', () => { - it('Does nothing when there are no results', () => { - const prevState = { - results: [], - selectedResult: null, - isExactMatch: false, - }; - - const actionPlus = changeSelectedResult(+1); - const actionMin = changeSelectedResult(-1); - - deepFreeze([prevState, actionPlus, actionMin]); - - const nextStatePlus = search(prevState, actionPlus); - const nextStateMin = search(prevState, actionMin); - expect(nextStatePlus).toEqual(prevState); - expect(nextStateMin).toEqual(prevState); - }); - - it('Does nothing when there is an exact match', () => { - const prevState = { - results: ['s/18561'], - selectedResult: 's/18561', - isExactMatch: true, - }; - - const actionPlus = changeSelectedResult(+1); - const actionMin = changeSelectedResult(-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'], - selectedResult: null, - isExactMatch: false, - }; - - const actionPlus = changeSelectedResult(+1); - const actionMin = changeSelectedResult(-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'], - selectedResult: 's/18562', - isExactMatch: false, - }; - - const actionPlus = changeSelectedResult(+1); - const actionMin = changeSelectedResult(-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 arround when incrementing', () => { - expect(search({ - results: ['s/18561', 's/18562', 's/18563'], - selectedResult: 's/18563', - isExactMatch: false, - }, changeSelectedResult(+1))).toEqual({ - results: ['s/18561', 's/18562', 's/18563'], - selectedResult: null, - isExactMatch: false, - }); - - expect(search({ - results: ['s/18561', 's/18562', 's/18563'], - selectedResult: null, - isExactMatch: false, - }, changeSelectedResult(+1))).toEqual({ - results: ['s/18561', 's/18562', 's/18563'], - selectedResult: 's/18561', - isExactMatch: false, - }); - }); - - it('Properly wraps arround when decrementing', () => { - expect(search({ - results: ['s/18561', 's/18562', 's/18563'], - selectedResult: 's/18561', - isExactMatch: false, - }, changeSelectedResult(-1))).toEqual({ - results: ['s/18561', 's/18562', 's/18563'], - selectedResult: null, - isExactMatch: false, - }); - - expect(search({ - results: ['s/18561', 's/18562', 's/18563'], - selectedResult: null, - isExactMatch: false, - }, changeSelectedResult(-1))).toEqual({ - results: ['s/18561', 's/18562', 's/18563'], - selectedResult: 's/18563', - isExactMatch: false, - }); - }); - }); - }); -}); diff --git a/src/client/react/reducers/search.ts b/src/client/react/reducers/search.ts deleted file mode 100644 index 658d3ca..0000000 --- a/src/client/react/reducers/search.ts +++ /dev/null @@ -1,90 +0,0 @@ -import * as fuzzy from 'fuzzy'; -import users, { User } from '../users'; -import { InputChangeAction, ChangeSelectedResultAction } from '../actions/search'; - -export interface State { - results: string[], - selectedResult: string | null, - isExactMatch: boolean, -}; - -export type Action = InputChangeAction | ChangeSelectedResultAction; - -const DEFAULT_STATE: State = { - results: [ - 's/18562', - ], - selectedResult: null, - isExactMatch: false, -}; - -function getSearchResults(allUsers: User[], query: string) { - if (query.trim() === '') { - return []; - } - - const allResults = fuzzy.filter(query, allUsers, { - extract: (user: User) => user.value, - }); - - const firstResults = allResults.splice(0, 4); - const userIds = firstResults.map((result: { original: User }) => result.original.id); - - return userIds; -} - -const search = (state = DEFAULT_STATE, action: Action): State => { - switch (action.type) { - case 'SEARCH/INPUT_CHANGE': { - const results = getSearchResults(users.allUsers, action.typedValue); - let selectedResult = null; - let isExactMatch = false; - - // Is the typed value exactly the same as the first result? Then show the - // appropiate icon instead of the generic search icon. - if ((results.length === 1) && (action.typedValue === users.byId[results[0]].value)) { - [selectedResult] = results; - isExactMatch = true; - } - - return { - ...state, - results, - selectedResult, - isExactMatch, - }; - } - - case 'SEARCH/CHANGE_SELECTED_RESULT': { - const { results, isExactMatch } = state; - - if (isExactMatch) return 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; -- cgit v1.1 From 70a9b0be3782122750388c24eb98b0d45e6fc6d1 Mon Sep 17 00:00:00 2001 From: Noah Loomans Date: Sat, 6 Jan 2018 13:12:11 +0100 Subject: Save searchText in redux store --- src/client/react/reducers/search.js | 7 +++++-- src/client/react/reducers/search.test.js | 16 ++++++++++++++++ 2 files changed, 21 insertions(+), 2 deletions(-) (limited to 'src/client/react/reducers') diff --git a/src/client/react/reducers/search.js b/src/client/react/reducers/search.js index 2a7e7a5..6027ed7 100644 --- a/src/client/react/reducers/search.js +++ b/src/client/react/reducers/search.js @@ -5,6 +5,7 @@ const DEFAULT_STATE = { results: [ 's/18562', ], + searchText: '', selectedResult: null, isExactMatch: false, }; @@ -27,13 +28,14 @@ function getSearchResults(allUsers, query) { const search = (state = DEFAULT_STATE, action) => { switch (action.type) { case 'SEARCH/INPUT_CHANGE': { - const results = getSearchResults(users.allUsers, action.typedValue); + const { searchText } = action; + const results = getSearchResults(users.allUsers, action.searchText); let selectedResult = null; let isExactMatch = false; // Is the typed value exactly the same as the first result? Then show the // appropiate icon instead of the generic search icon. - if ((results.length === 1) && (action.typedValue === users.byId[results[0]].value)) { + if ((results.length === 1) && (action.searchText === users.byId[results[0]].value)) { [selectedResult] = results; isExactMatch = true; } @@ -41,6 +43,7 @@ const search = (state = DEFAULT_STATE, action) => { return { ...state, results, + searchText, selectedResult, isExactMatch, }; diff --git a/src/client/react/reducers/search.test.js b/src/client/react/reducers/search.test.js index e0ca18e..ddd7f9b 100644 --- a/src/client/react/reducers/search.test.js +++ b/src/client/react/reducers/search.test.js @@ -20,6 +20,7 @@ describe('reducers', () => { it('Returns no results when nothing is typed in', () => { expect(search(undefined, inputChange(''))).toEqual({ results: [], + searchText: '', selectedResult: null, isExactMatch: false, }); @@ -28,6 +29,7 @@ describe('reducers', () => { it('Returns no results when a space is typed in', () => { expect(search(undefined, inputChange(' '))).toEqual({ results: [], + searchText: ' ', selectedResult: null, isExactMatch: false, }); @@ -41,6 +43,7 @@ describe('reducers', () => { 's/18563', 's/18564', ], + searchText: '18', selectedResult: null, isExactMatch: false, }); @@ -51,6 +54,7 @@ describe('reducers', () => { results: [ 's/18561', ], + searchText: '18561', selectedResult: 's/18561', isExactMatch: true, }); @@ -61,6 +65,7 @@ describe('reducers', () => { it('Does nothing when there are no results', () => { const prevState = { results: [], + searchText: '', selectedResult: null, isExactMatch: false, }; @@ -79,6 +84,7 @@ describe('reducers', () => { it('Does nothing when there is an exact match', () => { const prevState = { results: ['s/18561'], + searchText: '18561', selectedResult: 's/18561', isExactMatch: true, }; @@ -98,6 +104,7 @@ describe('reducers', () => { 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, isExactMatch: false, }; @@ -123,6 +130,7 @@ describe('reducers', () => { 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', isExactMatch: false, }; @@ -148,20 +156,24 @@ describe('reducers', () => { it('Properly wraps arround when incrementing', () => { expect(search({ results: ['s/18561', 's/18562', 's/18563'], + searchText: '1856', selectedResult: 's/18563', isExactMatch: false, }, changeSelectedResult(+1))).toEqual({ results: ['s/18561', 's/18562', 's/18563'], + searchText: '1856', selectedResult: null, isExactMatch: false, }); expect(search({ results: ['s/18561', 's/18562', 's/18563'], + searchText: '1856', selectedResult: null, isExactMatch: false, }, changeSelectedResult(+1))).toEqual({ results: ['s/18561', 's/18562', 's/18563'], + searchText: '1856', selectedResult: 's/18561', isExactMatch: false, }); @@ -170,20 +182,24 @@ describe('reducers', () => { it('Properly wraps arround when decrementing', () => { expect(search({ results: ['s/18561', 's/18562', 's/18563'], + searchText: '1856', selectedResult: 's/18561', isExactMatch: false, }, changeSelectedResult(-1))).toEqual({ results: ['s/18561', 's/18562', 's/18563'], + searchText: '1856', selectedResult: null, isExactMatch: false, }); expect(search({ results: ['s/18561', 's/18562', 's/18563'], + searchText: '1856', selectedResult: null, isExactMatch: false, }, changeSelectedResult(-1))).toEqual({ results: ['s/18561', 's/18562', 's/18563'], + searchText: '1856', selectedResult: 's/18563', isExactMatch: false, }); -- cgit v1.1 From c0aa588bc8f85b13b5a55ccd6cdf11bf99048a1c Mon Sep 17 00:00:00 2001 From: Noah Loomans Date: Sat, 6 Jan 2018 15:42:04 +0100 Subject: Add user page --- src/client/react/reducers/search.js | 20 ++++++++++++++++++++ src/client/react/reducers/search.test.js | 22 +++++++++++++++++++++- 2 files changed, 41 insertions(+), 1 deletion(-) (limited to 'src/client/react/reducers') diff --git a/src/client/react/reducers/search.js b/src/client/react/reducers/search.js index 6027ed7..7c7e917 100644 --- a/src/client/react/reducers/search.js +++ b/src/client/react/reducers/search.js @@ -27,6 +27,22 @@ function getSearchResults(allUsers, query) { 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, + isExactMatch: true, + }; + } + case 'SEARCH/INPUT_CHANGE': { const { searchText } = action; const results = getSearchResults(users.allUsers, action.searchText); @@ -82,3 +98,7 @@ const search = (state = DEFAULT_STATE, action) => { }; 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 index ddd7f9b..22d32e2 100644 --- a/src/client/react/reducers/search.test.js +++ b/src/client/react/reducers/search.test.js @@ -12,10 +12,30 @@ window.USERS = [ const deepFreeze = require('deep-freeze'); const search = require('./search').default; -const { inputChange, changeSelectedResult } = require('../actions/search'); +const { _test } = require('./search'); +const { + setUser, + inputChange, + changeSelectedResult, +} = require('../actions/search'); describe('reducers', () => { describe('search', () => { + describe('SEARCH/SET_USER', () => { + it('Resets to the default state if the user is null', () => { + expect(search({ foo: 'bar' }, setUser(null))).toEqual(_test.DEFAULT_STATE); + }); + + it('Sets all the values of that user properly', () => { + expect(search(undefined, setUser('s/18561'))).toEqual({ + results: [], + searchText: '18561', + selectedResult: 's/18561', + isExactMatch: true, + }); + }); + }); + describe('SEARCH/INPUT_CHANGE', () => { it('Returns no results when nothing is typed in', () => { expect(search(undefined, inputChange(''))).toEqual({ -- cgit v1.1 From 1b3f4ea79f947558573fbce5a2e2d0c2c5dd6a8d Mon Sep 17 00:00:00 2001 From: Noah Loomans Date: Wed, 17 Jan 2018 16:26:04 +0100 Subject: Add view code --- src/client/react/reducers/view.js | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 src/client/react/reducers/view.js (limited to 'src/client/react/reducers') diff --git a/src/client/react/reducers/view.js b/src/client/react/reducers/view.js new file mode 100644 index 0000000..276d8ae --- /dev/null +++ b/src/client/react/reducers/view.js @@ -0,0 +1,38 @@ +const DEFAULT_STATE = { + schedules: {}, +}; + +const view = (state = DEFAULT_STATE, action) => { + switch (action.type) { + case 'VIEW/FETCH_SCHEDULE_REQUEST': + return { + ...state, + schedules: { + ...state.schedules, + [action.user]: { + state: 'fetching', + }, + }, + }; + case 'VIEW/FETCH_SCHEDULE_SUCCESS': + return { + ...state, + schedules: { + ...state.schedules, + [action.user]: { + ...state.schedules[action.user], + state: 'finished', + htmlStr: action.htmlStr, + }, + }, + }; + default: + return state; + } +}; + +export default view; + +export const _test = { + DEFAULT_STATE, +}; -- cgit v1.1 From 71c95bb19be0446bab80abffd9d4fc563374def3 Mon Sep 17 00:00:00 2001 From: Noah Loomans Date: Wed, 17 Jan 2018 16:47:23 +0100 Subject: Fix typo --- src/client/react/reducers/search.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/client/react/reducers') diff --git a/src/client/react/reducers/search.js b/src/client/react/reducers/search.js index 7c7e917..2274a33 100644 --- a/src/client/react/reducers/search.js +++ b/src/client/react/reducers/search.js @@ -50,7 +50,7 @@ const search = (state = DEFAULT_STATE, action) => { let isExactMatch = false; // Is the typed value exactly the same as the first result? Then show the - // appropiate icon instead of the generic search icon. + // appropriate icon instead of the generic search icon. if ((results.length === 1) && (action.searchText === users.byId[results[0]].value)) { [selectedResult] = results; isExactMatch = true; -- cgit v1.1 From 0bddf7661d7ece709a18f2d167b928749638f318 Mon Sep 17 00:00:00 2001 From: Noah Loomans Date: Wed, 24 Jan 2018 15:44:31 +0100 Subject: Add animation to results --- src/client/react/reducers/search.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'src/client/react/reducers') diff --git a/src/client/react/reducers/search.js b/src/client/react/reducers/search.js index 2274a33..770cdcb 100644 --- a/src/client/react/reducers/search.js +++ b/src/client/react/reducers/search.js @@ -2,9 +2,10 @@ import fuzzy from 'fuzzy'; import users from '../users'; const DEFAULT_STATE = { - results: [ - 's/18562', - ], + // results: [ + // 's/18562', + // ], + results: [], searchText: '', selectedResult: null, isExactMatch: false, -- cgit v1.1 From 8670ada517bc8beb69d152c82f282322b9ea8d64 Mon Sep 17 00:00:00 2001 From: Noah Loomans Date: Sun, 28 Jan 2018 15:43:11 +0100 Subject: Implement week selector in the view --- src/client/react/reducers/view.js | 43 ++++++++++++++++++++++++++------------- 1 file changed, 29 insertions(+), 14 deletions(-) (limited to 'src/client/react/reducers') diff --git a/src/client/react/reducers/view.js b/src/client/react/reducers/view.js index 276d8ae..603f1d4 100644 --- a/src/client/react/reducers/view.js +++ b/src/client/react/reducers/view.js @@ -1,3 +1,21 @@ +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: {}, }; @@ -5,25 +23,22 @@ const DEFAULT_STATE = { const view = (state = DEFAULT_STATE, action) => { switch (action.type) { case 'VIEW/FETCH_SCHEDULE_REQUEST': - return { - ...state, - schedules: { - ...state.schedules, - [action.user]: { - state: 'fetching', - }, - }, - }; case 'VIEW/FETCH_SCHEDULE_SUCCESS': return { ...state, schedules: { ...state.schedules, - [action.user]: { - ...state.schedules[action.user], - state: 'finished', - htmlStr: action.htmlStr, - }, + [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: -- cgit v1.1 From 7dd214d57c7dab9626abef1516a862f46c1e02bd Mon Sep 17 00:00:00 2001 From: Noah Loomans Date: Sun, 28 Jan 2018 19:11:00 +0100 Subject: Refactor View.js --- src/client/react/reducers/view.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/client/react/reducers') diff --git a/src/client/react/reducers/view.js b/src/client/react/reducers/view.js index 603f1d4..301a1cf 100644 --- a/src/client/react/reducers/view.js +++ b/src/client/react/reducers/view.js @@ -3,12 +3,12 @@ const schedule = (state = {}, action) => { case 'VIEW/FETCH_SCHEDULE_REQUEST': return { ...state, - state: 'fetching', + state: 'FETCHING', }; case 'VIEW/FETCH_SCHEDULE_SUCCESS': return { ...state, - state: 'finished', + state: 'FINISHED', htmlStr: action.htmlStr, }; default: -- cgit v1.1