diff options
Diffstat (limited to 'src/client/react')
-rw-r--r-- | src/client/react/components/container/Results.js | 76 | ||||
-rw-r--r-- | src/client/react/components/container/Search.js | 26 | ||||
-rw-r--r-- | src/client/react/components/container/View.js | 18 | ||||
-rw-r--r-- | src/client/react/components/container/WeekSelector.js | 17 | ||||
-rw-r--r-- | src/client/react/components/page/User.js | 22 | ||||
-rw-r--r-- | src/client/react/lib/url.js | 24 |
6 files changed, 115 insertions, 68 deletions
diff --git a/src/client/react/components/container/Results.js b/src/client/react/components/container/Results.js index c329c3c..0f70aa6 100644 --- a/src/client/react/components/container/Results.js +++ b/src/client/react/components/container/Results.js @@ -1,52 +1,63 @@ import React from 'react'; import PropTypes from 'prop-types'; -import { connect } from 'react-redux'; import classnames from 'classnames'; +import { connect } from 'react-redux'; import { withRouter } from 'react-router-dom'; -import Result from '../presentational/Result'; + import { setUser } from '../../actions/search'; +import { userFromMatch } from '../../lib/url'; +import Result from '../presentational/Result'; const Results = ({ results, isExactMatch, - urlUser, selectedResult, + match, history, dispatch, -}) => ( - <div - className={classnames('search__results', { - 'search__results--has-results': !isExactMatch && results.length > 0, - })} - style={{ - minHeight: isExactMatch ? 0 : results.length * 54, - }} - > - {!isExactMatch && results.map(userId => ( - <Result - key={userId} - userId={userId} - isSelected={userId === selectedResult} - onClick={() => { - if (userId === urlUser) { - // EDGE CASE: The user is set if the user changes, but it doesn't - // change if the result is already the one we are viewing. - // Therefor, we need to dispatch the SET_USER command manually. - dispatch(setUser(urlUser)); - } else { - history.push(`/${userId}`); - } - }} - /> - ))} - </div> -); +}) => { + const user = userFromMatch(match); + + return ( + <div + className={classnames('search__results', { + 'search__results--has-results': !isExactMatch && results.length > 0, + })} + style={{ + minHeight: isExactMatch ? 0 : results.length * 54, + }} + > + {!isExactMatch && results.map(userId => ( + <Result + key={userId} + userId={userId} + isSelected={userId === selectedResult} + onClick={() => { + if (userId === user) { + // EDGE CASE: The user is set if the user changes, but it doesn't + // change if the result is already the one we are viewing. + // Therefor, we need to dispatch the SET_USER command manually. + dispatch(setUser(user)); + } else { + history.push(`/${userId}`); + } + }} + /> + ))} + </div> + ); +}; Results.propTypes = { results: PropTypes.arrayOf(PropTypes.string).isRequired, isExactMatch: PropTypes.bool.isRequired, - urlUser: PropTypes.string, selectedResult: PropTypes.string, + match: PropTypes.shape({ + params: PropTypes.shape({ + type: PropTypes.string, + value: PropTypes.string, + }).isRequired, + }).isRequired, history: PropTypes.shape({ push: PropTypes.func.isRequired, }).isRequired, @@ -54,7 +65,6 @@ Results.propTypes = { }; Results.defaultProps = { - urlUser: null, selectedResult: null, }; diff --git a/src/client/react/components/container/Search.js b/src/client/react/components/container/Search.js index ad6f7f1..4f3c6ee 100644 --- a/src/client/react/components/container/Search.js +++ b/src/client/react/components/container/Search.js @@ -6,6 +6,7 @@ import { withRouter } from 'react-router-dom'; import SearchIcon from 'react-icons/lib/md/search'; +import { userFromMatch } from '../../lib/url'; import { setUser, inputChange, changeSelectedResult } from '../../actions/search'; import users from '../../users'; @@ -26,12 +27,14 @@ class Search extends React.Component { } componentDidMount() { - this.props.dispatch(setUser(this.props.urlUser)); + const urlUser = userFromMatch(this.props.match); + this.props.dispatch(setUser(urlUser)); } componentWillReceiveProps(nextProps) { - if (nextProps.urlUser !== this.props.urlUser) { - this.props.dispatch(setUser(nextProps.urlUser)); + if (nextProps.match !== this.props.match) { + const urlUser = userFromMatch(nextProps.match); + this.props.dispatch(setUser(urlUser)); } } @@ -59,12 +62,13 @@ class Search extends React.Component { break; case 'Enter': { const result = this.props.selectedResult || this.props.results[0]; + const urlUser = userFromMatch(this.props.match); - if (result === this.props.urlUser) { + if (result === urlUser) { // EDGE CASE: The user is set if the user changes, but it doesn't // change if the result is already the one we are viewing. // Therefor, we need to dispatch the SET_USER command manually. - this.props.dispatch(setUser(this.props.urlUser)); + this.props.dispatch(setUser(urlUser)); } else if (result) { this.props.history.push(`/${result}`); } @@ -109,7 +113,7 @@ class Search extends React.Component { autoComplete="off" /> </div> - <Results urlUser={this.props.urlUser} /> + <Results /> </div> </div> ); @@ -119,18 +123,22 @@ class Search extends React.Component { Search.propTypes = { results: PropTypes.arrayOf(PropTypes.string).isRequired, selectedResult: PropTypes.string, - urlUser: PropTypes.string, isExactMatch: PropTypes.bool.isRequired, searchText: PropTypes.string.isRequired, - dispatch: PropTypes.func.isRequired, + match: PropTypes.shape({ + params: PropTypes.shape({ + type: PropTypes.string, + value: PropTypes.string, + }).isRequired, + }).isRequired, history: PropTypes.shape({ push: PropTypes.func.isRequired, }).isRequired, + dispatch: PropTypes.func.isRequired, }; Search.defaultProps = { selectedResult: null, - urlUser: null, }; const mapStateToProps = state => ({ diff --git a/src/client/react/components/container/View.js b/src/client/react/components/container/View.js index 4f16100..052173f 100644 --- a/src/client/react/components/container/View.js +++ b/src/client/react/components/container/View.js @@ -3,6 +3,7 @@ import PropTypes from 'prop-types'; import { connect } from 'react-redux'; import { withRouter } from 'react-router-dom'; +import { userFromMatch, weekFromLocation } from '../../lib/url'; import { fetchSchedule } from '../../actions/view'; import extractSchedule from '../../lib/extractSchedule'; @@ -11,10 +12,12 @@ import Loading from '../presentational/Loading'; const View = ({ schedules, - user, - week, + match, + location, dispatch, }) => { + const user = userFromMatch(match); + const week = weekFromLocation(location); const schedule = extractSchedule(schedules, user, week); switch (schedule.state) { @@ -35,8 +38,15 @@ View.propTypes = { state: PropTypes.string.isRequired, htmlStr: PropTypes.string, }))).isRequired, - user: PropTypes.string.isRequired, - week: PropTypes.number.isRequired, + match: PropTypes.shape({ + params: PropTypes.shape({ + type: PropTypes.string.isRequired, + value: PropTypes.string.isRequired, + }).isRequired, + }).isRequired, + location: PropTypes.shape({ + search: PropTypes.string.isRequired, + }).isRequired, dispatch: PropTypes.func.isRequired, }; diff --git a/src/client/react/components/container/WeekSelector.js b/src/client/react/components/container/WeekSelector.js index d5ba752..a7ffa3a 100644 --- a/src/client/react/components/container/WeekSelector.js +++ b/src/client/react/components/container/WeekSelector.js @@ -8,10 +8,13 @@ import ArrowBackIcon from 'react-icons/lib/md/arrow-back'; import ArrowForwardIcon from 'react-icons/lib/md/arrow-forward'; import purifyWeek from '../../lib/purifyWeek'; +import { weekFromLocation } from '../../lib/url'; + +const WeekSelector = ({ location, history }) => { + const week = weekFromLocation(location); -const WeekSelector = ({ urlWeek, location, history }) => { const updateWeek = (change) => { - const newWeek = purifyWeek(urlWeek + change); + const newWeek = purifyWeek(week + change); const isCurrentWeek = moment().week() === newWeek; const query = queryString.stringify({ @@ -23,19 +26,19 @@ const WeekSelector = ({ urlWeek, location, history }) => { return ( <div className="week-selector"> <button onClick={() => updateWeek(-1)}><ArrowBackIcon /></button> - <div className="text">Week {urlWeek}</div> + <div className="text">Week {week}</div> <button onClick={() => updateWeek(+1)}><ArrowForwardIcon /></button> </div> ); }; WeekSelector.propTypes = { - urlWeek: PropTypes.number.isRequired, - history: PropTypes.shape({ - push: PropTypes.func.isRequired, - }).isRequired, location: PropTypes.shape({ pathname: PropTypes.string.isRequired, + search: PropTypes.string.isRequired, + }).isRequired, + history: PropTypes.shape({ + push: PropTypes.func.isRequired, }).isRequired, }; diff --git a/src/client/react/components/page/User.js b/src/client/react/components/page/User.js index 0c79a8b..1b7e1ce 100644 --- a/src/client/react/components/page/User.js +++ b/src/client/react/components/page/User.js @@ -1,20 +1,15 @@ import React from 'react'; import PropTypes from 'prop-types'; import { Redirect } from 'react-router-dom'; -import queryString from 'query-string'; -import moment from 'moment'; -import purifyWeek from '../../lib/purifyWeek'; import Search from '../container/Search'; import View from '../container/View'; -import users from '../../users'; +import { userFromMatch } from '../../lib/url'; import WeekSelector from '../container/WeekSelector'; -const UserPage = ({ match, location }) => { - const user = `${match.params.type}/${match.params.value}`; - const weekStr = queryString.parse(location.search).week; - const week = purifyWeek(weekStr ? parseInt(weekStr, 10) : moment().week()); +const UserPage = ({ match }) => { + const user = userFromMatch(match); - if (!users.allIds.includes(user)) { + if (!user) { // Invalid user, redirect to index. return <Redirect to="/" />; } @@ -23,15 +18,15 @@ const UserPage = ({ match, location }) => { <div className="page-user"> <div className="search-wrapper"> <div className="search-container"> - <Search urlUser={user} /> + <Search /> </div> </div> <div className="menu"> <div className="menu-container"> - <WeekSelector urlWeek={week} /> + <WeekSelector /> </div> </div> - <View user={user} week={week} /> + <View /> </div> ); }; @@ -43,9 +38,6 @@ UserPage.propTypes = { value: PropTypes.string.isRequired, }).isRequired, }).isRequired, - location: PropTypes.shape({ - search: PropTypes.string.isRequired, - }).isRequired, }; export default UserPage; diff --git a/src/client/react/lib/url.js b/src/client/react/lib/url.js new file mode 100644 index 0000000..3b7f6b4 --- /dev/null +++ b/src/client/react/lib/url.js @@ -0,0 +1,24 @@ +import moment from 'moment'; +import queryString from 'query-string'; +import users from '../users'; +import purifyWeek from './purifyWeek'; + +export function userFromMatch(match) { + const user = `${match.params.type}/${match.params.value}`; + + if (!users.allIds.includes(user)) { + return null; + } + + return user; +} + +export function weekFromLocation(location) { + const weekStr = queryString.parse(location.search).week; + + if (!weekStr) { + return moment().week(); + } + + return purifyWeek(parseInt(weekStr, 10)); +} |