From 7787456fda5167e97210923e214eb815639ee099 Mon Sep 17 00:00:00 2001 From: Esko Ikkala <esko.ikkala@aalto.fi> Date: Wed, 16 May 2018 16:28:38 +0300 Subject: [PATCH] Add result fetching Co-authored-by Heino Erkki <erkki.heino@aalto.fi> --- src/actions/index.js | 6 +++++ src/components/IntegrationAutosuggest.js | 3 +++ src/containers/FullWidthGrid.js | 15 ++++++++--- src/epics/index.js | 34 +++++++++++++++++++++--- src/reducers/results.js | 17 ++++++++++++ src/reducers/search.js | 7 +++++ 6 files changed, 75 insertions(+), 7 deletions(-) create mode 100644 src/reducers/results.js diff --git a/src/actions/index.js b/src/actions/index.js index c5da0ac0..ebd7b777 100644 --- a/src/actions/index.js +++ b/src/actions/index.js @@ -6,6 +6,7 @@ export const FETCH_SUGGESTIONS_FAILED = 'FETCH_SUGGESTIONS_FAILED'; export const UPDATE_SUGGESTIONS = 'UPDATE_SUGGESTIONS'; export const CLEAR_SUGGESTIONS = 'CLEAR_SUGGESTIONS'; export const FETCH_RESULTS = 'FETCH_RESULTS'; +export const FETCH_RESULTS_FAILED = 'FETCH_RESULTS_FAILED'; export const UPDATE_RESULTS = 'UPDATE_RESULTS'; export const CLEAR_RESULTS = 'CLEAR_RESULTS'; export const CLEAR_ERROR = 'CLEAR_ERROR'; @@ -34,6 +35,11 @@ export const fetchSuggestionsFailed = (error) => ({ error }); +export const fetchResultsFailed = (error) => ({ + type: FETCH_RESULTS_FAILED, + error +}); + export const updateSuggestions = ({ results }) => ({ type: UPDATE_SUGGESTIONS, results diff --git a/src/components/IntegrationAutosuggest.js b/src/components/IntegrationAutosuggest.js index 09cc61d4..402ff33f 100644 --- a/src/components/IntegrationAutosuggest.js +++ b/src/components/IntegrationAutosuggest.js @@ -74,6 +74,7 @@ const styles = theme => ({ const IntegrationAutosuggest = (props) => { const handleOnChange = (event, { newValue }) => props.updateQuery(newValue); + const handleOnSuggestionSelected = (event, { suggestion }) => props.fetchResults(suggestion); const { classes } = props; @@ -96,6 +97,7 @@ const IntegrationAutosuggest = (props) => { renderSuggestionsContainer={renderSuggestionsContainer} getSuggestionValue={getSuggestionValue} renderSuggestion={renderSuggestion} + onSuggestionSelected={handleOnSuggestionSelected} inputProps={{ classes, placeholder: 'Search place names', @@ -112,6 +114,7 @@ IntegrationAutosuggest.propTypes = { updateQuery: PropTypes.func.isRequired, fetchSuggestions: PropTypes.func.isRequired, clearSuggestions: PropTypes.func.isRequired, + fetchResults: PropTypes.func.isRequired, }; export default withStyles(styles)(IntegrationAutosuggest); diff --git a/src/containers/FullWidthGrid.js b/src/containers/FullWidthGrid.js index a3e42616..3f1976d1 100644 --- a/src/containers/FullWidthGrid.js +++ b/src/containers/FullWidthGrid.js @@ -12,7 +12,7 @@ import IconButton from 'material-ui/IconButton'; import MenuIcon from '@material-ui/icons/Menu'; import IntegrationAutosuggest from '../components/IntegrationAutosuggest'; import LeafletMapContainer from '../components/LeafletMapContainer'; -import { updateQuery, updateDatasets, fetchSuggestions, clearSuggestions } from '../actions'; +import { updateQuery, updateDatasets, fetchSuggestions, clearSuggestions, fetchResults } from '../actions'; import Message from '../components/Message'; @@ -50,14 +50,19 @@ let FullWidthGrid = (props) => { <MenuIcon /> </IconButton> <Grid item xs={3}> - <IntegrationAutosuggest search={props.search} updateQuery={props.updateQuery} - fetchSuggestions={props.fetchSuggestions} clearSuggestions={props.clearSuggestions} /> + <IntegrationAutosuggest + search={props.search} + updateQuery={props.updateQuery} + fetchSuggestions={props.fetchSuggestions} + clearSuggestions={props.clearSuggestions} + fetchResults={props.fetchResults} + /> </Grid> </Toolbar> </AppBar> </Grid> <Grid item xs={12}> - <LeafletMapContainer /> + <LeafletMapContainer places={props.search.results} /> </Grid> </Grid> </div> @@ -74,6 +79,7 @@ const mapDispatchToProps = ({ updateDatasets, fetchSuggestions, clearSuggestions, + fetchResults, }); FullWidthGrid.propTypes = { @@ -83,6 +89,7 @@ FullWidthGrid.propTypes = { updateQuery: PropTypes.func.isRequired, fetchSuggestions: PropTypes.func.isRequired, clearSuggestions: PropTypes.func.isRequired, + fetchResults: PropTypes.func.isRequired, }; FullWidthGrid = connect( diff --git a/src/epics/index.js b/src/epics/index.js index c224289f..1c63e323 100644 --- a/src/epics/index.js +++ b/src/epics/index.js @@ -3,10 +3,17 @@ import _ from 'lodash'; import { ajax } from 'rxjs/observable/dom/ajax'; import { combineEpics } from 'redux-observable'; import { Observable } from 'rxjs/Observable'; -import { updateSuggestions, FETCH_SUGGESTIONS, FETCH_SUGGESTIONS_FAILED } from '../actions'; +import { + updateSuggestions, + updateResults, + FETCH_SUGGESTIONS, + FETCH_SUGGESTIONS_FAILED, + FETCH_RESULTS, + FETCH_RESULTS_FAILED, +} from '../actions'; const getSuggestionsEpic = (action$, store) => { - const searchUrl = 'http://localhost:3000/search'; + const searchUrl = 'http://localhost:3000/suggest'; return action$.ofType(FETCH_SUGGESTIONS) .debounceTime(500) @@ -27,6 +34,27 @@ const getSuggestionsEpic = (action$, store) => { }); }; -const rootEpic = combineEpics(getSuggestionsEpic); +const getResultsEpic = (action$, store) => { + const searchUrl = 'http://localhost:3000/search'; + + return action$.ofType(FETCH_RESULTS) + .switchMap(() => { + const { query, datasets } = store.getState().search; + if (query.length < 3) { + return []; + } + const dsParams = _.map(datasets, ds => `dataset=${ds}`).join('&'); + + const requestUrl = `${searchUrl}?q=${query}&${dsParams}`; + return ajax.getJSON(requestUrl) + .map(response => updateResults({ results: response })) + .catch(error => Observable.of({ + type: FETCH_RESULTS_FAILED, + error: error, + })); + }); +}; + +const rootEpic = combineEpics(getSuggestionsEpic, getResultsEpic); export default rootEpic; diff --git a/src/reducers/results.js b/src/reducers/results.js new file mode 100644 index 00000000..2732976c --- /dev/null +++ b/src/reducers/results.js @@ -0,0 +1,17 @@ +import { + UPDATE_RESULTS, + CLEAR_RESULTS, +} from '../actions'; + +const results = (state = [], action) => { + switch (action.type) { + case UPDATE_RESULTS: + return action.results; + case CLEAR_RESULTS: + return []; + default: + return state; + } +}; + +export default results; diff --git a/src/reducers/search.js b/src/reducers/search.js index 3f756a1b..45d6d810 100644 --- a/src/reducers/search.js +++ b/src/reducers/search.js @@ -3,13 +3,17 @@ import { UPDATE_DATASETS, UPDATE_SUGGESTIONS, CLEAR_SUGGESTIONS, + UPDATE_RESULTS, + CLEAR_RESULTS } from '../actions'; import suggestions from './suggestions'; +import results from './results'; export const INITIAL_STATE = { query: '', datasets: ['warsa_karelian_places', 'warsa_municipalities'], suggestions: [], + results: [] }; const search = (state = INITIAL_STATE, action) => { @@ -21,6 +25,9 @@ const search = (state = INITIAL_STATE, action) => { case CLEAR_SUGGESTIONS: case UPDATE_SUGGESTIONS: return { ...state, suggestions: suggestions(state.suggestions, action) }; + case CLEAR_RESULTS: + case UPDATE_RESULTS: + return { ...state, results: results(state.results, action) }; default: return state; } -- GitLab