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