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.
To install it, run:
npm add @loadsmart/react-location-select
or
yarn add @loadsmart/react-location-select
Please, make sure that you also have all the peer dependencies listed in the package.json installed.
Important:
- You need to provide the
googleMapsAPIKey
prop for theSelect
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 theSelect
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'],
};
If you are using Jest, you need to add this library to transformIgnorePatterns
in your Jest configuration to ensure it is properly transformed. Example:
{
"transformIgnorePatterns": [
"node_modules/(?!@loadsmart/react-location-select)"
]
}
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;
});
If you need to debug any behavior related to the LocationSelect when consuming the @loadsmart/react-location-select
library,
you can enable component logging by setting the global variable window.__LOCATION_SELECT_ENABLE_LOGGING__
.
In the browser console, run the following command:
window.__LOCATION_SELECT_ENABLE_LOGGING__ = true;
During development inside the library, to log from within the components, please use the utils/logger.ts
file.
Logging is disabled (not shown) by default. To enable it, set the STORYBOOK_ENABLE_LOGGING
environment variable to true
in your .env
file.
STORYBOOK_ENABLE_LOGGING=true
You can pass a custom parser and manipulate the returned data if you need a different result than the default LocationSelect
config.
const customParser = (query: string, result: GeocodedLocation) => {
return result;
};
<LocationSelect {...args} config={{ parser: customParser }} />;
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 }} />;
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.
This project is open to contributions. If you want to contribute, please follow the steps below:
-
Node (See the required version at .nvmrc).
-
Yarn Berry From the Installation Yarn docs
The preferred way to manage Yarn is by-project and through Corepack, a tool shipped by default with Node.js. Modern releases of Yarn aren't meant to be installed globally, or from npm.
- Start by enabling Corepack, if it isn't already; this will add the yarn binary to your PATH:
corepack enable
or if you use Volta. Run the following.
npm install -g corepack # Specifying an explicit install-directory makes corepack overwrite volta's yarn shims, which is what we want corepack enable --install-directory ~/.volta/bin
The "packageManager" field defines which package manager is expected to be used when working on the current project. It can be set to any of the supported package managers, and will ensure that your teams use the exact same package manager versions without having to install anything else other than Node.js.
To successfully run this project on your local environment and obtain data from Compass, please adhere to the following steps:
- Change the component stories by adding the
compassConfig.APIKey
insrc/location-select/location-select.stories.tsx
.- You can learn how to get a key here
export const Demo: Story = {
args: {
name: 'location',
googleMapsAPIKey: '<YOUR GOOGLE MAPS API KEY GOES HERE>',
multiple: true,
disableMapsLoading: false,
googleMapsAPIVersion: '3.51',
+ compassConfig: {
+ baseURL: 'https://api.staging.loadsmart.com',
+ APIKey: '<API_KEY>',
+ },
},
render: DemoRenderer,
};
The
dev
command runs on port 8080, which has the necessary permissions to establish requests to Compass in stating.