Skip to content

Instantly share code, notes, and snippets.

@quentin-decre
Last active April 11, 2024 08:35
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save quentin-decre/ed6ed417637edf7c4e4570b3f6954321 to your computer and use it in GitHub Desktop.
Save quentin-decre/ed6ed417637edf7c4e4570b3f6954321 to your computer and use it in GitHub Desktop.
/**
* Extend a dataProvider to add a Google Maps API Geocoding Places resource.
* Then you will be able to add location autocomplete using ReferenceInput and AutocompleteInput
* @example
*
* const dataProvider = withGoogleMapsPlacesResource(
* jsonServerProvider("http://localhost:3000"),
* [....]
* );
*
* <ReferenceInput
* reference="google_maps_places"
* source={source}
* enableGetChoices={({ q }) => q && q.length >= 2} // minimum 2 characters to trigger search
* >
* <AutocompleteInput optionText="formatted_address" {...props} />
* </ReferenceInput>
*/
import { Client, GeocodeResult } from '@googlemaps/google-maps-services-js'
import { DataProvider, GetListParams } from 'react-admin'
const client = new Client({
config: {
adapter: ['xhr', 'http'],
},
})
export const searchGoogleMapsPlaces = async (search: string): Promise<GeocodeResult[]> => {
const response = await client.geocode({
params: {
address: search.trim(),
key: import.meta.env.REACT_APP_GOOGLE_MAPS_PWA_APIKEY ?? '',
},
})
return (response.data?.results ?? []).map((place) => ({
id: place.formatted_address,
...place,
}))
}
export const withGoogleMapsPlacesResource = (dataProvider: DataProvider) => ({
...dataProvider,
getList: async (resource: string, params: GetListParams) => {
if (resource === 'google_maps_places') {
// search parameter is mandatory
if (!params.filter?.q) {
return {
data: [],
total: 0,
}
}
const response = await searchGoogleMapsPlaces(params.filter.q)
return {
data: response,
total: response.length,
}
}
return dataProvider.getList(resource, params)
},
getOne: async (resource: string, params: any) => {
if (resource === 'google_maps_places') {
const response = await searchGoogleMapsPlaces(params.id)
return {
data: response[0],
}
}
return dataProvider.getOne(resource, params)
},
getMany: async (resource: string, params: any) => {
if (resource === 'google_maps_places') {
const response = await Promise.all(params.ids.map((id: string) => searchGoogleMapsPlaces(id)))
return {
data: response?.flat() ?? [],
}
}
return dataProvider.getMany(resource, params)
},
update: async (resource: string, params: any) => {
if (resource === 'google_maps_places') {
throw new Error('google_maps_places resource is read-only')
}
return dataProvider.update(resource, params)
},
updateMany: async (resource: string, params: any) => {
if (resource === 'google_maps_places') {
throw new Error('google_maps_places resource is read-only')
}
return dataProvider.updateMany(resource, params)
},
create: async (resource: string, params: any) => {
if (resource === 'google_maps_places') {
throw new Error('google_maps_places resource is read-only')
}
return dataProvider.create(resource, params)
},
delete: async (resource: string, params: any) => {
if (resource === 'google_maps_places') {
throw new Error('google_maps_places resource is read-only')
}
return dataProvider.delete(resource, params)
},
})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment