diff --git a/react-client/package.json b/react-client/package.json
index 57284b7..9c15d40 100644
--- a/react-client/package.json
+++ b/react-client/package.json
@@ -7,13 +7,16 @@
},
"dependencies": {
"immutable": "^3.8.1",
+ "promise-polyfill": "^6.0.2",
"react": "^15.4.1",
+ "react-autobind": "^1.0.6",
"react-dom": "^15.4.1",
"react-redux": "^4.4.6",
"react-simple-range": "^1.4.0",
"redux": "^3.6.0",
"semantic-ui-css": "^2.2.4",
- "semantic-ui-react": "^0.61.4"
+ "semantic-ui-react": "^0.61.4",
+ "whatwg-fetch": "^2.0.1"
},
"scripts": {
"start": "react-scripts start",
diff --git a/react-client/src/App.js b/react-client/src/App.js
index 6737166..0705681 100644
--- a/react-client/src/App.js
+++ b/react-client/src/App.js
@@ -5,6 +5,8 @@ import ParametersPannel from './ParametersPannel.js';
import CarSelector from './CarSelector.js';
import Geocoder from './Geocoder.js'
+const accessToken = '';
+
const carParameters = [
{ id: "battery",
label: "Battery capacity",
@@ -36,7 +38,10 @@ class App extends Component {
render() {
return (
-
+
{ console.log(event); }}
+ />
diff --git a/react-client/src/Geocoder.js b/react-client/src/Geocoder.js
index 049bcbb..b08d564 100644
--- a/react-client/src/Geocoder.js
+++ b/react-client/src/Geocoder.js
@@ -1,13 +1,36 @@
import React, { Component } from 'react'
import ReactDOM from 'react-dom'
-import { Input } from 'semantic-ui-react'
+import { List, Input } from 'semantic-ui-react'
+import autoBind from 'react-autobind';
class Geocoder extends Component {
constructor() {
super();
+ autoBind(this);
this.state = this.getDefaultState();
}
-
+
+ search(endpoint, source, accessToken, proximity, bbox, types, query, callback) {
+ var searchTime = new Date();
+ var uri = endpoint + '/geocoding/v5/' +
+ source + '/' + encodeURIComponent(query) + '.json' +
+ '?access_token=' + accessToken +
+ (proximity ? '&proximity=' + proximity : '') +
+ (bbox ? '&bbox=' + bbox : '') +
+ (types ? '&types=' + encodeURIComponent(types) : '');
+ fetch(uri, {
+ headers: {
+ Accept: 'application/json',
+ },
+ }).then(function(response) {
+ return response.json();
+ }).then(function(json) {
+ callback(json, searchTime);
+ }).catch(function(ex) {
+ console.log("mapbox geocoding search error", ex);
+ });
+ }
+
getDefaultState() {
return {
results: [],
@@ -22,20 +45,127 @@ class Geocoder extends Component {
ReactDOM.findDOMNode(this.refs.input).focus();
}
+ onInput(event) {
+ this.setState({loading: true});
+ var value = event.target.value;
+ if (value === '') {
+ this.setState(this.getDefaultState());
+ } else {
+ this.search(
+ this.props.endpoint,
+ this.props.source,
+ this.props.accessToken,
+ this.props.proximity,
+ this.props.bbox,
+ this.props.types,
+ value,
+ this.onResult);
+ }
+ }
+
+ moveFocus(dir) {
+ if (this.state.loading)
+ return;
+
+ var focus = 0;
+ if (this.state.focus !== null) {
+ focus = Math.max(0, Math.min(this.state.results.length - 1, this.state.focus + dir))
+ }
+ console.log("focus", focus);
+ this.setState({
+ focus: focus,
+ });
+ }
+
+ acceptFocus() {
+ if (this.state.focus !== null) {
+ this.props.onSelect(this.state.results[this.state.focus]);
+ }
+ }
+
+ onKeyDown(event) {
+ switch (event.which) {
+ // up
+ case 38:
+ event.preventDefault();
+ this.moveFocus(-1);
+ break;
+ // down
+ case 40:
+ this.moveFocus(1);
+ break;
+ // accept
+ case 13:
+ if (this.state.results.length > 0 && this.state.focus == null) {
+ this.clickOption(this.state.results[0], 0);
+ }
+ this.acceptFocus();
+ break;
+ default:
+ break;
+ }
+ }
+
+ onResult(body, searchTime) {
+ // searchTime is compared with the last search to set the state
+ // to ensure that a slow xhr response does not scramble the
+ // sequence of autocomplete display.
+ if (body && body.features && this.state.searchTime <= searchTime) {
+ this.setState({
+ searchTime: searchTime,
+ loading: false,
+ results: body.features,
+ focus: null
+ });
+ this.props.onSuggest(this.state.results);
+ }
+ }
+ clickOption(place, listLocation) {
+ this.props.onSelect(place);
+ this.setState({focus: listLocation});
+ // focus on the input after click to maintain key traversal
+ ReactDOM.findDOMNode(this.refs.input).focus();
+ return false;
+ }
render() {
+ var resultList = null;
+ if (this.state.results.length > 0) {
+ const items = this.state.results.map((result, i) => {
+ return (
+
+
+
+ {result.place_name}
+
+
+
+ );
+ });
+
+ resultList = (
+
+ {items}
+
+ );
+ }
+
return (
- {
- console.log(event.target.value);
- }}
- />
+
+
+ {resultList}
+
);
}
}
diff --git a/react-client/src/index.js b/react-client/src/index.js
index 54c5ef1..cc19ae0 100644
--- a/react-client/src/index.js
+++ b/react-client/src/index.js
@@ -1,8 +1,15 @@
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
+import 'whatwg-fetch'
+import Promise from 'promise-polyfill';
import './index.css';
+// To add to window
+if (!window.Promise) {
+ window.Promise = Promise;
+}
+
ReactDOM.render(
,
document.getElementById('root')
diff --git a/react-client/webpack.config.js b/react-client/webpack.config.js
new file mode 100644
index 0000000..e69de29