@loadsmart/react-location-select
TypeScript icon, indicating that this package has built-in type declarations

4.1.2 • Public • Published

LocationSelect

This project belongs to Loadsmart's front-end team.

This is a spin-off of Miranda [React] Select powered with Google Autocomplete, Places, and Geocoder capabilities.

Getting started

To install it, run:

npm i @loadsmart/react-location-select

or

yarn add @loadsmart/react-location-select

Please, make sure that you also have all the peer dependencies installed.

Peer dependencies

  • @loadsmart/loadsmart-ui: Provides the basic Select component.
  • @loadsmart/utils-function: Helps with internal functions.
  • @loadsmart/utils-string: Helps with internal functions.
  • react and react-dom: Base UI library.
  • react-helmet: Provided dynamic insertion of Google Maps API script (if not available).

How to use

Important:

  • You need to provide the googleMapsAPIKey prop for the Select to be visible and ready for location selection.
  • If you add a custom datasource, make sure its reference is stable (i.e., you won't generate a new reference unnecessarily) so the Select can appropriately optimize its data source management.
  • If you add a custom config for the Google Maps datasource, make sure its reference is stable (i.e., you won't generate a new reference unnecessarily) so the Select can appropriately optimize its data source management.
import LocationSelect from '@loadsmart/react-location-select';

<LocationSelect {...props} googleMapsAPIKey={'<Your Google Maps API key>'} />;

The Google Maps datasource will always be included. You can customize how it fetches locations, if needed, by providing the config prop. This is the default config:

const DEFAULT_CONFIG = {
	// Source: https://developers.google.com/maps/documentation/places/web-service/supported_types#table3
	types: 'cities',
	// Source: https://developers.google.com/maps/documentation/javascript/reference/places-autocomplete-service#ComponentRestrictions
	restrictions: { country: ['us', 'ca'] },
	// Source: https://developers.google.com/maps/documentation/javascript/reference/3.45/places-service#PlaceResult
	fields: ['address_components', 'place_id'],
};

Mocking the returned locations

You most certainly will need unit tests around the code that will use the LocationSelect component. We export a mock factory to help returning the locations you want to work on your tests.

import {
	GoogleMapsMock,
	GoogleMapsMockFactory,
} from '@loadsmart/react-location-select/dist/testing';

// Save the original google reference to reset it after the test is completed
const originalWindowGoogle = window.google;

// Generate mock data using a default info.
// e.g. { "address": "New York, NY, United States" }
window.google = GoogleMapsMock();

// Or generate mock data with an overridden info.
window.google = GoogleMapsMockFactory({
	predictionStub(query) {
		return new Promise((resolve) => {
			resolve({
				predictions: [
					{
						description: 'New York, NY, United States',
						id: '7eae6a016a9c6f58e2044573fb8f14227b6e1f96',
						matched_substrings: [
							{
								length: 2,
								offset: 0,
							},
						],
						place_id: 'ChIJOwg_06VPwokRYv534QaPC8g',
						reference: '...',
						structured_formatting: {
							main_text: 'New York, NY, United States',
							main_text_matched_substrings: [
								{
									length: 2,
									offset: 0,
								},
							],
							secondary_text: '',
						},
						terms: [
							{
								offset: 0,
								value: 'New York',
							},
							{
								offset: 10,
								value: 'NY',
							},
							{
								offset: 14,
								value: 'United States',
							},
						],
						types: ['locality', 'political', 'geocode'],
					},
				],
			});
		});
	},
	geocodeStub(query, callback) {
		if (query.address === '' || query.placeId === '') {
			callback([], 'ZERO_RESULTS');
			return;
		}

		callback(
			[
				{
					address_components: [
						{
							long_name: 'New York',
							short_name: 'New York',
							types: ['locality', 'political'],
						},
						{
							long_name: 'New York',
							short_name: 'NY',
							types: ['administrative_area_level_1', 'political'],
						},
						{
							long_name: 'United States',
							short_name: 'US',
							types: ['country', 'political'],
						},
					],
					formatted_address: 'New York, NY, USA',
					geometry: {
						bounds: {
							south: 40.4773991,
							west: -74.25908989999999,
							north: 40.9175771,
							east: -73.70027209999999,
						},
						location: { lat: 40.7127753, lng: -74.0059728 },
						location_type: 'APPROXIMATE',
						viewport: {
							south: 40.4773991,
							west: -74.25908989999999,
							north: 40.9175771,
							east: -73.70027209999999,
						},
					},
					place_id: 'ChIJOwg_06VPwokRYv534QaPC8g',
					types: ['locality', 'political'],
				},
			],
			'OK',
		);
	},
	placesStub(query, callback) {
		callback(
			{
				address_components: [
					{
						long_name: 'Newark',
						short_name: 'Newark',
						types: ['locality', 'political'],
					},
					{
						long_name: 'Essex County',
						short_name: 'Essex County',
						types: ['administrative_area_level_2', 'political'],
					},
					{
						long_name: 'New Jersey',
						short_name: 'NJ',
						types: ['administrative_area_level_1', 'political'],
					},
					{
						long_name: 'United States',
						short_name: 'US',
						types: ['country', 'political'],
					},
				],
				place_id: 'ChIJHQ6aMnBTwokRc-T-3CrcvOE',
				geometry: {
					location: {
						lat: () => 0,
						lng: () => 0,
					},
				},
				html_attributions: [],
			},
			'OK',
		);
	},
});

// Reset the mock after the test is completed.
afterAll(() => {
	window.google = originalWindowGoogle;
});

Using a custom parser

You can pass one or more custom parsers and manipulate the returned data if you need a different result than the default LocationSelect config.

const customParser = (query, location) => {
	return location;
};

<LocationSelect {...args} config={{ parsers: [customParser] }} />;

Using a custom adapter

If you need a different adapter to display the select options, you can pass a custom adapter and change the data that is returned.

const customAdapter = {
	getKey(location) {
		return location?.address;
	},
	getLabel(location) {
		return location?.address;
	},
};

<LocationSelect {...args} config={{ adapter: customAdapter }} />;

Using on a TypeScript project

You can import the types from this package.

import { LocationSelect } from '@loadsmart/react-location-select';
import type {
	Location,
	LocationParser,
	// ... Any other type
} from '@loadsmart/react-location-select';

The @types/google.maps is installed by this package, don't worry about it. You can use it without importing or installing anything.

Contribute

First, make sure you have your env set to Node >= 16.

Readme

Keywords

none

Package Sidebar

Install

npm i @loadsmart/react-location-select

Weekly Downloads

202

Version

4.1.2

License

MIT

Unpacked Size

576 kB

Total Files

30

Last publish

Collaborators

  • bruno.manzo
  • felipe.asantos
  • giovannitoledo
  • douglasklein2
  • luiz.loadsmart
  • mwconceicao
  • yidi0912
  • lenoir.zamboni
  • diogomafra
  • oliver.tso
  • loadsmart-frontend
  • brennervaz
  • raittes
  • welingtonms-loadsmart
  • gutofoletto