diff options
| author | Noah Loomans <noahloomans@gmail.com> | 2018-01-06 12:11:19 +0100 | 
|---|---|---|
| committer | Noah Loomans <noahloomans@gmail.com> | 2018-01-06 12:11:19 +0100 | 
| commit | 77dccd31b32ee0a9a53b2186bae231069c5ab152 (patch) | |
| tree | f90c5c524f1d3536a1f6ab665a7350739f590b7a /src/client/react | |
| parent | 95041dffbd23fe81802efd5fb25cffe492cdb551 (diff) | |
Revert "Move to typescript"
This reverts commit f0c8cf0e79f003514fd65a70def5820205955a77.
Diffstat (limited to 'src/client/react')
15 files changed, 144 insertions, 194 deletions
| diff --git a/src/client/react/LandingPage.tsx b/src/client/react/LandingPage.js index f8bb58c..d79826e 100644 --- a/src/client/react/LandingPage.tsx +++ b/src/client/react/LandingPage.js @@ -1,4 +1,4 @@ -import * as React from 'react'; +import React from 'react';  import Search from './components/container/Search';  const App = () => ( diff --git a/src/client/react/actions/search.js b/src/client/react/actions/search.js new file mode 100644 index 0000000..1b6847d --- /dev/null +++ b/src/client/react/actions/search.js @@ -0,0 +1,14 @@ +export const inputChange = typedValue => ({ +  type: 'SEARCH/INPUT_CHANGE', +  typedValue, +}); + +/** + * Change the selected result. + * @param {+1/-1} relativeChange usually +1 or -1, the change relative to the + *     current result. + */ +export const changeSelectedResult = relativeChange => ({ +  type: 'SEARCH/CHANGE_SELECTED_RESULT', +  relativeChange, +}); diff --git a/src/client/react/actions/search.ts b/src/client/react/actions/search.ts deleted file mode 100644 index 45c31fb..0000000 --- a/src/client/react/actions/search.ts +++ /dev/null @@ -1,24 +0,0 @@ -export interface InputChangeAction { -  type: 'SEARCH/INPUT_CHANGE', -  typedValue: string, -} - -export const inputChange = (typedValue: string): InputChangeAction => ({ -  type: 'SEARCH/INPUT_CHANGE', -  typedValue, -}); - -export interface ChangeSelectedResultAction { -  type: 'SEARCH/CHANGE_SELECTED_RESULT', -  relativeChange: 1 | -1, -} - -/** - * Change the selected result. - * @param {+1/-1} relativeChange usually +1 or -1, the change relative to the - *     current result. - */ -export const changeSelectedResult = (relativeChange: 1 | -1): ChangeSelectedResultAction => ({ -  type: 'SEARCH/CHANGE_SELECTED_RESULT', -  relativeChange, -}); diff --git a/src/client/react/components/container/Results.js b/src/client/react/components/container/Results.js new file mode 100644 index 0000000..911ea27 --- /dev/null +++ b/src/client/react/components/container/Results.js @@ -0,0 +1,35 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { connect } from 'react-redux'; +import classnames from 'classnames'; +import Result from '../presentational/Result'; + +const Results = (({ results, isExactMatch, selectedResult }) => ( +  <div +    className={classnames('search__results', { +      'search__results--has-results': !isExactMatch && results.length > 0, +    })} +  > +    {!isExactMatch && results.map(userId => ( +      <Result key={userId} userId={userId} isSelected={userId === selectedResult} /> +    ))} +  </div> +)); + +Results.propTypes = { +  results: PropTypes.arrayOf(PropTypes.string).isRequired, +  isExactMatch: PropTypes.bool.isRequired, +  selectedResult: PropTypes.string, +}; + +Results.defaultProps = { +  selectedResult: null, +}; + +const mapStateToProps = state => ({ +  results: state.search.results, +  isExactMatch: state.search.isExactMatch, +  selectedResult: state.search.selectedResult, +}); + +export default connect(mapStateToProps)(Results); diff --git a/src/client/react/components/container/Results.tsx b/src/client/react/components/container/Results.tsx deleted file mode 100644 index 21d3378..0000000 --- a/src/client/react/components/container/Results.tsx +++ /dev/null @@ -1,26 +0,0 @@ -import * as React from 'react'; -import { connect } from 'react-redux'; -import * as classnames from 'classnames'; -import Result from '../presentational/Result'; -import { User } from '../../users'; -import { State } from '../../reducers'; - -const Results: React.StatelessComponent<{ results: string[], isExactMatch: boolean, selectedResult: string }> = (props) => ( -  <div -    className={classnames('search__results', { -      'search__results--has-results': !props.isExactMatch && props.results.length > 0, -    })} -  > -    {!props.isExactMatch && props.results.map(userId => ( -      <Result key={userId} userId={userId} isSelected={userId === props.selectedResult} /> -    ))} -  </div> -); - -const mapStateToProps = (state: State) => ({ -  results: state.search.results, -  isExactMatch: state.search.isExactMatch, -  selectedResult: state.search.selectedResult, -}); - -export default connect(mapStateToProps)(Results); diff --git a/src/client/react/components/container/Search.tsx b/src/client/react/components/container/Search.js index fdd6c83..e49e6a7 100644 --- a/src/client/react/components/container/Search.tsx +++ b/src/client/react/components/container/Search.js @@ -1,30 +1,18 @@ -import * as React from 'react'; -import { Dispatch } from 'redux'; +import React from 'react'; +import PropTypes from 'prop-types';  import { connect } from 'react-redux'; -import * as classnames from 'classnames'; +import classnames from 'classnames'; -import SearchIcon = require('react-icons/lib/md/search'); +import SearchIcon from 'react-icons/lib/md/search';  import { inputChange, changeSelectedResult } from '../../actions/search'; -import { Action } from '../../reducers/search'; -import { State } from '../../reducers';  import users from '../../users';  import Results from './Results';  import IconFromUserType from '../presentational/IconFromUserType'; -interface SearchStatehProps { -  selectedResult: string, -  isExactMatch: boolean, -} - -interface SearchDispatchProps { -  changeSelectedResult(relativeChange: 1 | -1): void, -  inputChange(typedValue: string): void, -} - -class Search extends React.Component<SearchStatehProps & SearchDispatchProps, any> { -  constructor(props: SearchStatehProps & SearchDispatchProps) { +class Search extends React.Component { +  constructor(props) {      super(props);      this.state = { @@ -48,15 +36,15 @@ class Search extends React.Component<SearchStatehProps & SearchDispatchProps, an      });    } -  onKeyDown(event: React.KeyboardEvent<any>) { +  onKeyDown(event) {      if (event.key === 'ArrowUp' || event.key === 'ArrowDown') {        event.preventDefault();        switch (event.key) {          case 'ArrowUp': -          this.props.changeSelectedResult(-1); +          this.props.dispatch(changeSelectedResult(-1));            break;          case 'ArrowDown': -          this.props.changeSelectedResult(+1); +          this.props.dispatch(changeSelectedResult(+1));            break;          default:            throw new Error('This should never happen... pls?'); @@ -68,7 +56,7 @@ class Search extends React.Component<SearchStatehProps & SearchDispatchProps, an      const {        selectedResult,        isExactMatch, -      inputChange, +      dispatch,      } = this.props;      const { @@ -86,7 +74,7 @@ class Search extends React.Component<SearchStatehProps & SearchDispatchProps, an            </div>            <input              id="search__input" -            onChange={event => inputChange(event.target.value)} +            onChange={event => dispatch(inputChange(event.target.value))}              onKeyDown={this.onKeyDown}              placeholder="Zoeken"              onFocus={this.onFocus} @@ -99,33 +87,20 @@ class Search extends React.Component<SearchStatehProps & SearchDispatchProps, an    }  } -// Search.propTypes = { -//   selectedResult: PropTypes.string, -//   isExactMatch: PropTypes.bool.isRequired, -//   dispatch: PropTypes.func.isRequired, -// }; +Search.propTypes = { +  selectedResult: PropTypes.string, +  isExactMatch: PropTypes.bool.isRequired, +  dispatch: PropTypes.func.isRequired, +}; -// Search.defaultProps = { -//   selectedResult: null, -// }; +Search.defaultProps = { +  selectedResult: null, +}; -const mapStateToProps = (state: State):SearchStatehProps => ({ +const mapStateToProps = state => ({ +  results: state.search.results,    selectedResult: state.search.selectedResult,    isExactMatch: state.search.isExactMatch,  }); -// const mapDispatchToProps = { -//   inputChange, -//   changeSelectedResult, -// }; - -const mapDispatchToProps = (dispatch: any): SearchDispatchProps => ({ -  inputChange(typedValue) { -    dispatch(inputChange(typedValue)); -  }, -  changeSelectedResult(relativeChange) { -    dispatch(changeSelectedResult(relativeChange)) -  } -}); - -export default connect(mapStateToProps, mapDispatchToProps)(Search); +export default connect(mapStateToProps)(Search); diff --git a/src/client/react/components/presentational/IconFromUserType.js b/src/client/react/components/presentational/IconFromUserType.js new file mode 100644 index 0000000..ee0e04b --- /dev/null +++ b/src/client/react/components/presentational/IconFromUserType.js @@ -0,0 +1,37 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import StudentIcon from 'react-icons/lib/md/person'; +import RoomIcon from 'react-icons/lib/md/room'; +import ClassIcon from 'react-icons/lib/md/group'; +import TeacherIcon from 'react-icons/lib/md/account-circle'; + +const IconFromUserType = ({ userType, defaultIcon }) => { +  switch (userType) { +    case 'c': +      return <ClassIcon />; +    case 't': +      return <TeacherIcon />; +    case 's': +      return <StudentIcon />; +    case 'r': +      return <RoomIcon />; +    default: +      if (defaultIcon) { +        return defaultIcon; +      } + +      throw new Error('`userType` was invalid or not given, but `defaultIcon` is not defined.'); +  } +}; + +IconFromUserType.propTypes = { +  userType: PropTypes.string, +  defaultIcon: PropTypes.element, +}; + +IconFromUserType.defaultProps = { +  userType: null, +  defaultIcon: null, +}; + +export default IconFromUserType; diff --git a/src/client/react/components/presentational/IconFromUserType.tsx b/src/client/react/components/presentational/IconFromUserType.tsx deleted file mode 100644 index d77ea1b..0000000 --- a/src/client/react/components/presentational/IconFromUserType.tsx +++ /dev/null @@ -1,31 +0,0 @@ -import * as React from 'react'; -import StudentIcon = require('react-icons/lib/md/person'); -import RoomIcon = require('react-icons/lib/md/room'); -import ClassIcon = require('react-icons/lib/md/group'); -import TeacherIcon = require('react-icons/lib/md/account-circle'); - -// interface IconFromUserTypeProps { -//   userType: string, -//   defaultIcon?: JSX.Element, -// } - -const IconFromUserType: React.StatelessComponent<{ userType: string, defaultIcon?: JSX.Element }> = (props) => { -  switch (props.userType) { -    case 'c': -      return <ClassIcon />; -    case 't': -      return <TeacherIcon />; -    case 's': -      return <StudentIcon />; -    case 'r': -      return <RoomIcon />; -    default: -      if (props.defaultIcon) { -        return props.defaultIcon; -      } - -      throw new Error('`userType` was invalid or not given, but `defaultIcon` is not defined.'); -  } -}; - -export default IconFromUserType; diff --git a/src/client/react/components/presentational/Result.tsx b/src/client/react/components/presentational/Result.js index b33a365..0b9e024 100644 --- a/src/client/react/components/presentational/Result.tsx +++ b/src/client/react/components/presentational/Result.js @@ -1,10 +1,11 @@ -import * as React from 'react'; -import * as classnames from 'classnames'; +import React from 'react'; +import PropTypes from 'prop-types'; +import classnames from 'classnames';  import users from '../../users';  import IconFromUserType from './IconFromUserType'; -const Result: React.StatelessComponent<{ userId: string, isSelected: boolean }> = ({ userId, isSelected }) => ( +const Result = ({ userId, isSelected }) => (    <div      className={classnames('search__result', {        'search__result--selected': isSelected, @@ -15,4 +16,9 @@ const Result: React.StatelessComponent<{ userId: string, isSelected: boolean }>    </div>  ); +Result.propTypes = { +  userId: PropTypes.string.isRequired, +  isSelected: PropTypes.bool.isRequired, +}; +  export default Result; diff --git a/src/client/react/index.tsx b/src/client/react/index.js index f0c3226..5279bf4 100644 --- a/src/client/react/index.tsx +++ b/src/client/react/index.js @@ -1,5 +1,5 @@ -import * as React from 'react'; -import * as ReactDOM from 'react-dom'; +import React from 'react'; +import ReactDOM from 'react-dom';  import { Provider } from 'react-redux';  import { BrowserRouter as Router, Route } from 'react-router-dom';  import { createStore, applyMiddleware, compose } from 'redux'; @@ -9,10 +9,10 @@ import reducer from './reducers';  import LandingPage from './LandingPage';  // eslint-disable-next-line no-underscore-dangle -// const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose; +const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;  const store = createStore(    reducer, -  compose(applyMiddleware(logger, thunk)), +  composeEnhancers(applyMiddleware(logger, thunk)),  );  ReactDOM.render( diff --git a/src/client/react/reducers.js b/src/client/react/reducers.js new file mode 100644 index 0000000..9fdf2c4 --- /dev/null +++ b/src/client/react/reducers.js @@ -0,0 +1,8 @@ +import { combineReducers } from 'redux'; +import search from './reducers/search'; + +const rootReducer = combineReducers({ +  search, +}); + +export default rootReducer; diff --git a/src/client/react/reducers.ts b/src/client/react/reducers.ts deleted file mode 100644 index 254fe76..0000000 --- a/src/client/react/reducers.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { combineReducers } from 'redux'; -import search, { State as SearchState } from './reducers/search'; - -export interface State { -  search: SearchState, -} - -const rootReducer = combineReducers<State>({ -  search, -}); - -export default rootReducer; diff --git a/src/client/react/reducers/search.ts b/src/client/react/reducers/search.js index 658d3ca..2a7e7a5 100644 --- a/src/client/react/reducers/search.ts +++ b/src/client/react/reducers/search.js @@ -1,16 +1,7 @@ -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; +import fuzzy from 'fuzzy'; +import users from '../users'; -const DEFAULT_STATE: State = { +const DEFAULT_STATE = {    results: [      's/18562',    ], @@ -18,22 +9,22 @@ const DEFAULT_STATE: State = {    isExactMatch: false,  }; -function getSearchResults(allUsers: User[], query: string) { +function getSearchResults(allUsers, query) {    if (query.trim() === '') {      return [];    }    const allResults = fuzzy.filter(query, allUsers, { -    extract: (user: User) => user.value, +    extract: user => user.value,    });    const firstResults = allResults.splice(0, 4); -  const userIds = firstResults.map((result: { original: User }) => result.original.id); +  const userIds = firstResults.map(result => result.original.id);    return userIds;  } -const search = (state = DEFAULT_STATE, action: Action): State => { +const search = (state = DEFAULT_STATE, action) => {    switch (action.type) {      case 'SEARCH/INPUT_CHANGE': {        const results = getSearchResults(users.allUsers, action.typedValue); diff --git a/src/client/react/reducers/search.test.ts b/src/client/react/reducers/search.test.js index 5869b81..e0ca18e 100644 --- a/src/client/react/reducers/search.test.ts +++ b/src/client/react/reducers/search.test.js @@ -1,4 +1,4 @@ -(<any>window).USERS = [ +window.USERS = [    { type: 's', value: '18561' },    { type: 's', value: '18562' },    { type: 's', value: '18563' }, diff --git a/src/client/react/users.ts b/src/client/react/users.js index a80a1c5..01ff093 100644 --- a/src/client/react/users.ts +++ b/src/client/react/users.js @@ -2,26 +2,9 @@  import { combineReducers, createStore } from 'redux'; -export interface User { -  type: string, -  value: string, -  id: string, -} +const getId = ({ type, value }) => `${type}/${value}`; -type Action = { -  type: 'USERS/ADD_USER', -  user: User, -} - -declare global { -  interface Window { -    USERS: User[]; -  } -} - -const getId = ({ type, value }: User) => `${type}/${value}`; - -const byId = (state = {}, action: Action) => { +const byId = (state = {}, action) => {    switch (action.type) {      case 'USERS/ADD_USER':        return { @@ -35,7 +18,7 @@ const byId = (state = {}, action: Action) => {    }  }; -const allIds = (state : any[] = [], action : Action) => { +const allIds = (state = [], action) => {    switch (action.type) {      case 'USERS/ADD_USER':        return [ @@ -47,7 +30,7 @@ const allIds = (state : any[] = [], action : Action) => {    }  }; -const allUsers = (state : any[] = [], action : Action) => { +const allUsers = (state = [], action) => {    switch (action.type) {      case 'USERS/ADD_USER':        return [ @@ -61,19 +44,13 @@ const allUsers = (state : any[] = [], action : Action) => {    }  }; -interface State { -  byId: any, -  allIds: string[], -  allUsers: User[] -} - -const store = createStore(combineReducers<State>({ +const store = createStore(combineReducers({    byId,    allIds,    allUsers,  })); -window.USERS.forEach((user) => { +USERS.forEach((user) => {    store.dispatch({      type: 'USERS/ADD_USER',      user: { | 
