From 82b7a1e784c101b8524f534c8d62aa2f324063b6 Mon Sep 17 00:00:00 2001 From: David Porter Date: Wed, 22 May 2024 23:09:25 +1000 Subject: [PATCH] ON-40405 # configure FormElementGoogleAddress to work with legacy PlacesService --- package-lock.json | 2 +- .../renderer/OneBlinkFormElements.tsx | 27 +++++++ .../FormElementGoogleAddress.tsx | 70 ++++++++++++++----- src/hooks/useGoogle.ts | 10 ++- src/services/form-validation.ts | 1 + src/services/generate-default-data.ts | 8 +++ 6 files changed, 98 insertions(+), 20 deletions(-) diff --git a/package-lock.json b/package-lock.json index ec3e66c9..dfc18b01 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8107,7 +8107,7 @@ }, "node_modules/@oneblink/types": { "version": "1.0.0", - "resolved": "git+ssh://git@github.com/oneblink/types.git#c08a0237ec63b79deeda8abb503d79c58e29eb04", + "resolved": "git+ssh://git@github.com/oneblink/types.git#79d9b22b0c234fed9763f8fd0c7b686070064d23", "dev": true, "license": "GPL-3.0-only", "dependencies": { diff --git a/src/components/renderer/OneBlinkFormElements.tsx b/src/components/renderer/OneBlinkFormElements.tsx index fc0d2643..4a0d6ed3 100644 --- a/src/components/renderer/OneBlinkFormElements.tsx +++ b/src/components/renderer/OneBlinkFormElements.tsx @@ -39,6 +39,7 @@ import FormElementLocation, { import FormElementGeoscapeAddress from '../../form-elements/FormElementGeoscapeAddress' import FormElementCompliance from '../../form-elements/FormElementCompliance' import FormElementPointAddress from '../../form-elements/FormElementPointAddress' +import FormElementGoogleAddress from '../../form-elements/FormElementGoogleAddress' import FormElementBoolean from '../../form-elements/FormElementBoolean' import FormElementCivicaStreetName from '../../form-elements/FormElementCivicaStreetName' import FormElementCivicaNameRecord from '../../form-elements/FormElementCivicaNameRecord' @@ -50,6 +51,7 @@ import { CivicaTypes, FormTypes, GeoscapeTypes, + GoogleTypes, MiscTypes, PointTypes, SubmissionTypes, @@ -846,6 +848,31 @@ const FormElementSwitch = React.memo(function OneBlinkFormElement({ ) } + case 'googleAddress': { + const v = value as GoogleTypes.GoogleMapsAddress | undefined + return ( + + ['onChange'] + } + validationMessage={validationMessage} + displayValidationMessage={displayValidationMessage} + {...dirtyProps} + /> + + ) + } case 'boolean': { return ( { + if (isLoaded) { + return new google.maps.Map(document.createElement('div')) + } + }, [isLoaded]) + const handleSearch = React.useCallback( async (input: string, abortSignal: AbortSignal) => { setError(undefined) @@ -56,6 +62,12 @@ function FormElementGoogleAddress({ input, }, (predictions, status) => { + if ( + status === google.maps.places.PlacesServiceStatus.ZERO_RESULTS + ) { + resolve([]) + return + } if (status !== google.maps.places.PlacesServiceStatus.OK) { reject('Google Places service not available') return @@ -106,46 +118,70 @@ function FormElementGoogleAddress({ setIsLoadingAddressDetails(true) try { //this should not happen, we can't get a place Id without google being present - if (!isLoaded) { + if (!isLoaded || !dummyMap) { throw new OneBlinkAppsError( 'An unknown error has occurred. Please contact support if the problem persists.', { originalError: new Error( - 'google places library has not be initialised', + 'Google Places library has not be initialised', ), }, ) } - const placeService = new google.maps.places.Place({ id: placeId }) - const { place } = await placeService.fetchFields({ - fields: [ - 'id', - 'displayName', - 'formattedAddress', - 'location', - 'addressComponents', - 'servesBeer', - ], - }) + const placeService = new google.maps.places.PlacesService(dummyMap) + const place = await new Promise( + (resolve, reject) => { + placeService.getDetails( + { + placeId, + fields: [ + 'place_id', + 'formatted_address', + 'geometry', + 'address_components', + ], + }, + (place, status) => { + if ( + status !== google.maps.places.PlacesServiceStatus.OK || + !place + ) { + reject( + `Could not find address details for place with id: ${placeId}`, + ) + return + } + resolve(place) + }, + ) + }, + ) onChange(element, { value: place }) } catch (newError) { if (isMounted.current) { - setError(newError as Error) + setError( + new OneBlinkAppsError( + 'An unknown error has occurred. Please contact support if the problem persists.', + { + originalError: newError as Error, + }, + ), + ) } } if (isMounted.current) { setIsLoadingAddressDetails(false) } }, - [isMounted, onChange, element, isLoaded], + [isMounted, onChange, element, isLoaded, dummyMap], ) // Ensure the label is set if the value is set outside of this component React.useEffect(() => { if (value) { - const newLabel = value.formattedAddress || value.id - setLabel(newLabel) + const newLabel = value.formatted_address || value.place_id + setLabel(newLabel ?? '') } }, [value]) diff --git a/src/hooks/useGoogle.ts b/src/hooks/useGoogle.ts index 484ebc3f..af215e5a 100644 --- a/src/hooks/useGoogle.ts +++ b/src/hooks/useGoogle.ts @@ -1,12 +1,18 @@ -import { useJsApiLoader } from '@react-google-maps/api' +import * as React from 'react' +import { useJsApiLoader, Libraries } from '@react-google-maps/api' import useGoogleMapsApiKey from './useGoogleMapsApiKey' export default function useGoogle() { const key = useGoogleMapsApiKey() + const libraries = React.useMemo( + () => ['maps', 'marker', 'places'], + [], + ) + const { isLoaded } = useJsApiLoader({ googleMapsApiKey: key ?? '', - libraries: ['maps', 'marker', 'places'], + libraries, }) return { isLoaded } diff --git a/src/services/form-validation.ts b/src/services/form-validation.ts index e73dfb1d..f7553719 100644 --- a/src/services/form-validation.ts +++ b/src/services/form-validation.ts @@ -387,6 +387,7 @@ export function generateValidationSchema( case 'abn': case 'geoscapeAddress': case 'pointAddress': + case 'googleAddress': case 'civicaStreetName': case 'autocomplete': case 'radio': diff --git a/src/services/generate-default-data.ts b/src/services/generate-default-data.ts index 01d48eca..bc99f801 100644 --- a/src/services/generate-default-data.ts +++ b/src/services/generate-default-data.ts @@ -289,6 +289,13 @@ function parsePreFillData( } }) } + case 'googleAddress': { + return parseUnknownAsRecord(value, (record) => { + if (parseStringValue(record.place_id)) { + return record + } + }) + } case 'freshdeskDependentField': { return parseUnknownAsRecord(value, (record) => { if ( @@ -470,6 +477,7 @@ export default function generateDefaultData( case 'freshdeskDependentField': case 'geoscapeAddress': case 'pointAddress': + case 'googleAddress': case 'civicaStreetName': case 'abn': case 'bsb':