Home Reference Source

src/helpers/geocodeAPI/geocodeAPI.js

import config from '../../constants/config';

const GOOGLE_API = 'https://maps.google.com/maps/api/geocode/json';

/**
 * [filterPostalCode description]
 * @param  {[type]} e [description]
 * @return {[type]}   [description]
 */
const filterPostalCode = e => e.types.includes('postal_code') && !!e.long_name;

const GeocodeAPI = {
  /**
   * [getPostalCodeFromAddressComponents description]
   * @param  {[type]} addressComponents [description]
   * @return {[type]}                   [description]
   */
  getPostalCodeFromAddressComponents(addressComponents) {
    const elemFind = addressComponents.filter(filterPostalCode);
    if (elemFind && elemFind.length) {
      return elemFind[0].long_name;
    }
    return null;
  },

  /**
   * [getCountryIdFromAddressComponents description]
   * @param  {[type]} addressComponents [description]
   * @return {[type]}                   [description]
   */
  getCountryIdFromAddressComponents(addressComponents) {
    const elemFind = addressComponents.filter(
      e => e.types.includes('country') && !!e.short_name,
    );
    if (elemFind && elemFind.length) {
      return elemFind[0].short_name;
    }
    return null;
  },

  /**
   * @param {Object} lat and lng
   * @returns {Promise} the postal code of the lat and lng
   */
  async postalCode({ lat, lng }) {
    const results = await this.reverseGeocode({ lat, lng });

    for (let i = 0; i < results.length; i += 1) {
      const elemFind = this.getPostalCodeFromAddressComponents(
        results[i].address_components,
      );
      if (elemFind) {
        return elemFind;
      }
    }
    return null;
  },

  /**
   * @param {Object} lat and lng
   * @returns {Promise}
   */
  async reverseGeocode({ lat, lng }) {
    if (!lat || !lng) {
      return Promise.reject(new Error('Provided coordinates are invalid'));
    }

    const latLng = `${lat},${lng}`;
    const url = `${GOOGLE_API}?key=${config.googleMapKey}&latlng=${encodeURI(
      latLng,
    )}`;
    const { results } = await this.handleUrl(url);
    if (!results || results.length <= 0) {
      return Promise.reject(new Error('Enable to reverse lat lng'));
    }

    return results;
  },

  /**
   * [positionToAddress description]
   * @param  {[type]}  position [description]
   * @return {Promise}          [description]
   */
  async positionToAddress(position) {
    return (await this.reverseGeocode(position))[0].formatted_address;
  },

  /**
   * [handleUrl description]
   * @param  {[type]}  url [description]
   * @return {Promise}     [description]
   */
  async handleUrl(url) {
    const response = await fetch(url).catch(() =>
      Promise.reject(new Error('Error fetching data')),
    );

    const json = await response
      .json()
      .catch(() => Promise.reject(new Error('Error parsing server response')));

    if (json.status === 'OK') {
      return json;
    }
    return Promise.reject(
      new Error(`Server returned status code ${json.status}`),
    );
  },
};

export default GeocodeAPI;