Add sessionToken for Autocomplete and place details calls

This commit is contained in:
Vesa Luusua 2018-07-12 22:00:09 +03:00
parent 32d995500e
commit dc9821f558
2 changed files with 27 additions and 6 deletions

View file

@ -152,6 +152,10 @@ class LocationAutocompleteInput extends Component {
// Ref to the input element.
this.input = null;
// Current sessionToken used to combine autocomplete calls with place details call
// This reduces Google Maps pricing.
this.autocompleteSessionToken = null;
this.changeHighlight = this.changeHighlight.bind(this);
this.selectItem = this.selectItem.bind(this);
this.selectItemIfNoneSelected = this.selectItemIfNoneSelected.bind(this);
@ -213,6 +217,7 @@ class LocationAutocompleteInput extends Component {
this.setState({ highlightedIndex: -1 });
if (!newValue) {
this.autocompleteSessionToken = null;
// No need to fetch predictions on empty input
return;
}
@ -266,7 +271,11 @@ class LocationAutocompleteInput extends Component {
selectedPlace: null,
});
getPlaceDetails(placeId)
this.autocompleteSessionToken =
this.autocompleteSessionToken || new window.google.maps.places.AutocompleteSessionToken();
const sessionToken = this.autocompleteSessionToken;
getPlaceDetails(placeId, sessionToken)
.then(place => {
this.props.input.onChange({
search: prediction.description,
@ -274,6 +283,7 @@ class LocationAutocompleteInput extends Component {
selectedPlaceId: placeId,
selectedPlace: place,
});
this.autocompleteSessionToken = null;
})
.catch(e => {
// eslint-disable-next-line no-console
@ -298,7 +308,12 @@ class LocationAutocompleteInput extends Component {
throw new Error('Google Maps API must be loaded for LocationAutocompleteInput');
}
const onChange = this.props.input.onChange;
getPlacePredictions(search)
this.autocompleteSessionToken =
this.autocompleteSessionToken || new window.google.maps.places.AutocompleteSessionToken();
const sessionToken = this.autocompleteSessionToken;
getPlacePredictions(search, sessionToken)
.then(results => {
const { search: currentSearch } = currentValue(this.props);

View file

@ -36,17 +36,20 @@ const placeCountry = place => {
*
* @param {String} placeId - ID for a place received from the
* autocomplete service
* @param {String} sessionToken - token to tie different autocomplete character searches together
* with getPlaceDetails call
*
* @return {Promise<util.propTypes.place>} Promise that
* resolves to the detailed place, rejects if the request failed
*/
export const getPlaceDetails = placeId =>
export const getPlaceDetails = (placeId, sessionToken) =>
new Promise((resolve, reject) => {
const serviceStatus = window.google.maps.places.PlacesServiceStatus;
const el = document.createElement('div');
const service = new window.google.maps.places.PlacesService(el);
const sessionTokenMaybe = sessionToken ? { sessionToken } : {};
service.getDetails({ placeId }, (place, status) => {
service.getDetails({ placeId, ...sessionTokenMaybe }, (place, status) => {
if (status !== serviceStatus.OK) {
reject(
new Error(`Could not get details for place id "${placeId}", error status was "${status}"`)
@ -71,16 +74,19 @@ const predictionSuccessful = status => {
* Get place predictions for the given search
*
* @param {String} search - place name or address to search
* @param {String} sessionToken - token to tie different autocomplete character searches together
* with getPlaceDetails call
*
* @return {Promise<{ search, predictions[] }>} - Promise of an object
* with the original search query and an array of
* `google.maps.places.AutocompletePrediction` objects
*/
export const getPlacePredictions = search =>
export const getPlacePredictions = (search, sessionToken) =>
new Promise((resolve, reject) => {
const service = new window.google.maps.places.AutocompleteService();
const sessionTokenMaybe = sessionToken ? { sessionToken } : {};
service.getPlacePredictions({ input: search }, (predictions, status) => {
service.getPlacePredictions({ input: search, ...sessionTokenMaybe }, (predictions, status) => {
if (!predictionSuccessful(status)) {
reject(new Error(`Prediction service status not OK: ${status}`));
} else {