From a0127138c73ee8061309d740408f4a5634f2d0a7 Mon Sep 17 00:00:00 2001 From: khusbuchandra Date: Thu, 1 Mar 2018 16:05:52 -0800 Subject: [PATCH 1/2] Search Feature: Update map on prediction selection Integrate geolocation api and update map with a marker on the location based on user's selction for search prediction. --- client/src/components/Search/index.js | 25 +++++++--------- client/src/components/SearchResults/index.js | 30 +++++++++++++++++++- controllers/google-api-controller.js | 3 +- 3 files changed, 42 insertions(+), 16 deletions(-) diff --git a/client/src/components/Search/index.js b/client/src/components/Search/index.js index 40eaca1..f94277e 100644 --- a/client/src/components/Search/index.js +++ b/client/src/components/Search/index.js @@ -3,7 +3,7 @@ import style from './style'; import axios from 'axios'; import {API_SERVER} from '../../../config'; const OK_Status = 'OK'; - +let marker; export default class Search extends Component { constructor(props) { super(props); @@ -44,12 +44,11 @@ export default class Search extends Component { }).then((response) => { if(response.data.status == OK_Status) { - let [searchResult] = response.data.results; + const [searchResult] = response.data.results; this.onPlaceFound(searchResult); } else - alert(response.data.status); - + alert(response.data.status); }); } @@ -59,29 +58,27 @@ export default class Search extends Component { * * @param {*} placeDetail */ + onPlaceFound(placeDetail) { this.props.map.setZoom(16); const location = placeDetail.geometry.location; - const userMarker = L.marker(location).addTo(this.props.map) + + if (marker) + this.props.map.removeLayer(marker); + + marker = L.marker(location).addTo(this.props.map) .bindPopup(`${placeDetail.name} ${placeDetail.formatted_address}`); this.props.map.setView(location, 16); - //ToDO : add to state , this location should be separate to user location + //ToDO : add to parent state , this location should be separate to user location } - handleSelection(data,event) { - // TODO - hookup to map instance and add marker for given location - // - get geolocation details based on prediction - console.log(data); - - } - render() { // pass props to children components const childWithProps = this.props.children.map((child) => { return cloneElement(child, { predictions: this.state.predictions, - onClicked: this.handleSelection + onClicked: this.onPlaceFound }); }); diff --git a/client/src/components/SearchResults/index.js b/client/src/components/SearchResults/index.js index a140ee7..a03cf22 100644 --- a/client/src/components/SearchResults/index.js +++ b/client/src/components/SearchResults/index.js @@ -1,16 +1,44 @@ import { h, Component } from 'preact'; import style from './style.css'; +import axios from 'axios'; +import {API_SERVER} from '../../../config'; +const OK_Status = 'OK' export default class UnorderedList extends Component { constructor(props) { super(props); + this.handleClick = this.handleClick.bind(this); } + /** + * On search prediction selection , fetch the geolocation details and + * update the map with a marker on that location + * + * @param {*} prediction + */ + handleClick(prediction) { + event.preventDefault(); + axios.post(`${API_SERVER}/map/geocode`, { + input: prediction + }).then((response) => { + console.log(response); + if(response.data.status == OK_Status) + { + const [searchResult] = response.data.results; + this.props.onClicked(searchResult); + } + else + alert(response.data.status); + + }); + } + + render() { return ( ) diff --git a/controllers/google-api-controller.js b/controllers/google-api-controller.js index ec6cc19..495e8a7 100644 --- a/controllers/google-api-controller.js +++ b/controllers/google-api-controller.js @@ -415,7 +415,8 @@ exports.geocode = (appReq, appRes) => { * @api {POST} /search/textSearch * @apiSuccess 200 {JSON} With two root elements: * - status: a string identifier of the request outcome -* - predictions: an array query predictions +* - results: An array, each element of the results array +* contains a single result from the specified area (location and radius) * @apiError 400 {request error} Google api request error. * * @param {string} appReq.body.input - The text string on which to search. From e9ae23a99ef9681bfec9348710f63d783a4ef9fc Mon Sep 17 00:00:00 2001 From: khusbuchandra Date: Fri, 2 Mar 2018 17:45:11 -0800 Subject: [PATCH 2/2] Incorporated review comments Modified Search & SearchResult component to incorporate the review comments. --- client/src/components/Search/index.js | 35 ++++++++++++-------- client/src/components/SearchResults/index.js | 4 +-- 2 files changed, 23 insertions(+), 16 deletions(-) diff --git a/client/src/components/Search/index.js b/client/src/components/Search/index.js index f94277e..f7ee79a 100644 --- a/client/src/components/Search/index.js +++ b/client/src/components/Search/index.js @@ -2,7 +2,7 @@ import { h , Component, cloneElement } from 'preact'; import style from './style'; import axios from 'axios'; import {API_SERVER} from '../../../config'; -const OK_Status = 'OK'; +const OK_STATUS = 'OK'; let marker; export default class Search extends Component { constructor(props) { @@ -11,11 +11,13 @@ export default class Search extends Component { value: '', predictions: [], placeIDs: [], + marker: null, + position: null, }; this.handleChange = this.handleChange.bind(this); this.handleSubmit = this.handleSubmit.bind(this); - this.onPlaceFound = this.onPlaceFound.bind(this); + this.handleSelectedPlace = this.handleSelectedPlace.bind(this); } handleChange(event) { @@ -42,10 +44,10 @@ export default class Search extends Component { lat: this.props.position.lat, lng: this.props.position.lng, }).then((response) => { - if(response.data.status == OK_Status) + if(response.data.status == OK_STATUS) { const [searchResult] = response.data.results; - this.onPlaceFound(searchResult); + this.handleSelectedPlace(searchResult); } else alert(response.data.status); @@ -59,26 +61,31 @@ export default class Search extends Component { * @param {*} placeDetail */ - onPlaceFound(placeDetail) { + handleSelectedPlace(placeDetail) { this.props.map.setZoom(16); - const location = placeDetail.geometry.location; + console.log(placeDetail) + if (this.state.marker) + this.props.map.removeLayer(this.state.marker); + this.setState({ + marker : L.marker(placeDetail.geometry.location).addTo(this.props.map), + position: placeDetail.geometry.location + }) - if (marker) - this.props.map.removeLayer(marker); - - marker = L.marker(location).addTo(this.props.map) - .bindPopup(`${placeDetail.name} ${placeDetail.formatted_address}`); - this.props.map.setView(location, 16); - //ToDO : add to parent state , this location should be separate to user location + //TO DO: Customize the marker popup + this.state.marker.bindPopup(`${placeDetail.name || ''} ${placeDetail.formatted_address}`) + + this.props.map.setView(this.state.position, 16); } + handleMarkerPopupContent + render() { // pass props to children components const childWithProps = this.props.children.map((child) => { return cloneElement(child, { predictions: this.state.predictions, - onClicked: this.onPlaceFound + onClicked: this.handleSelectedPlace }); }); diff --git a/client/src/components/SearchResults/index.js b/client/src/components/SearchResults/index.js index a03cf22..0b91a17 100644 --- a/client/src/components/SearchResults/index.js +++ b/client/src/components/SearchResults/index.js @@ -2,7 +2,7 @@ import { h, Component } from 'preact'; import style from './style.css'; import axios from 'axios'; import {API_SERVER} from '../../../config'; -const OK_Status = 'OK' +const OK_STATUS = 'OK' export default class UnorderedList extends Component { constructor(props) { @@ -22,7 +22,7 @@ export default class UnorderedList extends Component { input: prediction }).then((response) => { console.log(response); - if(response.data.status == OK_Status) + if(response.data.status == OK_STATUS) { const [searchResult] = response.data.results; this.props.onClicked(searchResult);