diff options
-rw-r--r-- | .eslintrc.js | 3 | ||||
-rw-r--r-- | package.json | 2 | ||||
-rw-r--r-- | src/client/react/actions/search.js | 5 | ||||
-rw-r--r-- | src/client/react/components/container/Search.js | 10 | ||||
-rw-r--r-- | src/client/react/components/page/Index.js | 10 | ||||
-rw-r--r-- | src/client/react/components/page/User.js | 31 | ||||
-rw-r--r-- | src/client/react/index.js | 2 | ||||
-rw-r--r-- | src/client/react/reducers/search.js | 20 | ||||
-rw-r--r-- | src/client/react/reducers/search.test.js | 22 | ||||
-rw-r--r-- | yarn.lock | 16 |
10 files changed, 102 insertions, 19 deletions
diff --git a/.eslintrc.js b/.eslintrc.js index b418fd4..376aa38 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -6,6 +6,7 @@ module.exports = { "jest": true, }, "rules": { - "react/jsx-filename-extension": [1, { "extensions": [".js"] }] + "react/jsx-filename-extension": ["error", { "extensions": [".js"] }], + "no-underscore-dangle": ["error", { "allow": ["_test"] }], } }; diff --git a/package.json b/package.json index fdc7374..0363675 100644 --- a/package.json +++ b/package.json @@ -31,7 +31,7 @@ "debug": "^2.6.0", "diacritics": "^1.2.3", "encoding": "^0.1.12", - "eslint": "^4.13.0", + "eslint": "^4.14.0", "express": "^4.13.4", "extract-text-webpack-plugin": "^3.0.2", "flexibility": "^2.0.1", diff --git a/src/client/react/actions/search.js b/src/client/react/actions/search.js index d903e64..22daeca 100644 --- a/src/client/react/actions/search.js +++ b/src/client/react/actions/search.js @@ -1,3 +1,8 @@ +export const setUser = user => ({ + type: 'SEARCH/SET_USER', + user, +}); + export const inputChange = searchText => ({ type: 'SEARCH/INPUT_CHANGE', searchText, diff --git a/src/client/react/components/container/Search.js b/src/client/react/components/container/Search.js index 06523be..27b0563 100644 --- a/src/client/react/components/container/Search.js +++ b/src/client/react/components/container/Search.js @@ -6,7 +6,7 @@ import { withRouter } from 'react-router-dom'; import SearchIcon from 'react-icons/lib/md/search'; -import { inputChange, changeSelectedResult } from '../../actions/search'; +import { setUser, inputChange, changeSelectedResult } from '../../actions/search'; import users from '../../users'; import Results from './Results'; @@ -25,6 +25,10 @@ class Search extends React.Component { this.onKeyDown = this.onKeyDown.bind(this); } + componentDidMount() { + this.props.dispatch(setUser(this.props.urlUser)); + } + onFocus() { this.setState({ hasFocus: true, @@ -97,6 +101,7 @@ class Search extends React.Component { Search.propTypes = { selectedResult: PropTypes.string, + urlUser: PropTypes.string, isExactMatch: PropTypes.bool.isRequired, searchText: PropTypes.string.isRequired, dispatch: PropTypes.func.isRequired, @@ -107,6 +112,7 @@ Search.propTypes = { Search.defaultProps = { selectedResult: null, + urlUser: null, }; const mapStateToProps = state => ({ @@ -116,4 +122,4 @@ const mapStateToProps = state => ({ isExactMatch: state.search.isExactMatch, }); -export default connect(mapStateToProps)(withRouter(Search)); +export default withRouter(connect(mapStateToProps)(Search)); diff --git a/src/client/react/components/page/Index.js b/src/client/react/components/page/Index.js index dcc521d..a91d7a9 100644 --- a/src/client/react/components/page/Index.js +++ b/src/client/react/components/page/Index.js @@ -1,16 +1,10 @@ import React from 'react'; -import PropTypes from 'prop-types'; import Search from '../container/Search'; -const App = ({ location }) => ( +const App = () => ( <div> - <Search location={location} /> + <Search /> </div> ); -App.propTypes = { - // eslint-disable-next-line react/forbid-prop-types - location: PropTypes.object.isRequired, -}; - export default App; diff --git a/src/client/react/components/page/User.js b/src/client/react/components/page/User.js new file mode 100644 index 0000000..2ad65a6 --- /dev/null +++ b/src/client/react/components/page/User.js @@ -0,0 +1,31 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { Redirect } from 'react-router-dom'; +import Search from '../container/Search'; +import users from '../../users'; + +const App = ({ match }) => { + const user = `${match.params.type}/${match.params.value}`; + + if (!users.allIds.includes(user)) { + // Invalid user, redirect to index. + return <Redirect to="/" />; + } + + return ( + <div> + <Search urlUser={user} /> + </div> + ); +}; + +App.propTypes = { + match: PropTypes.shape({ + params: PropTypes.shape({ + type: PropTypes.string.isRequired, + value: PropTypes.string.isRequired, + }).isRequired, + }).isRequired, +}; + +export default App; diff --git a/src/client/react/index.js b/src/client/react/index.js index 18dacf5..ffa5403 100644 --- a/src/client/react/index.js +++ b/src/client/react/index.js @@ -7,6 +7,7 @@ import logger from 'redux-logger'; import thunk from 'redux-thunk'; import reducer from './reducers'; import Index from './components/page/Index'; +import User from './components/page/User'; // eslint-disable-next-line no-underscore-dangle const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose; @@ -20,6 +21,7 @@ ReactDOM.render( <Router> <div> <Route exact path="/" component={Index} /> + <Route path="/:type/:value" component={User} /> </div> </Router> </Provider>, 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({ @@ -1935,7 +1935,7 @@ debug@2.6.8, debug@^2.2.0, debug@^2.6.0, debug@^2.6.8: dependencies: ms "2.0.0" -debug@^3.0.1, debug@^3.1.0: +debug@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" dependencies: @@ -2395,21 +2395,25 @@ eslint-scope@^3.7.1: esrecurse "^4.1.0" estraverse "^4.1.1" -eslint@^4.13.0: - version "4.13.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-4.13.0.tgz#1991aa359586af83877bde59de9d41f53e20826d" +eslint-visitor-keys@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#3f3180fb2e291017716acb4c9d6d5b5c34a6a81d" + +eslint@^4.14.0: + version "4.14.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-4.14.0.tgz#96609768d1dd23304faba2d94b7fefe5a5447a82" dependencies: ajv "^5.3.0" babel-code-frame "^6.22.0" chalk "^2.1.0" concat-stream "^1.6.0" cross-spawn "^5.1.0" - debug "^3.0.1" + debug "^3.1.0" doctrine "^2.0.2" eslint-scope "^3.7.1" + eslint-visitor-keys "^1.0.0" espree "^3.5.2" esquery "^1.0.0" - estraverse "^4.2.0" esutils "^2.0.2" file-entry-cache "^2.0.0" functional-red-black-tree "^1.0.1" |