@oneblink/apps-react 6.0.0 → 6.1.0-beta.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/dist/OneBlinkFormBase.js +3 -2
  2. package/dist/OneBlinkFormBase.js.map +1 -1
  3. package/dist/components/ArcGISWebMap.js +18 -14
  4. package/dist/components/ArcGISWebMap.js.map +1 -1
  5. package/dist/components/formStore/table/FormElementTableCell.js +9 -0
  6. package/dist/components/formStore/table/FormElementTableCell.js.map +1 -1
  7. package/dist/components/renderer/AutocompleteDropdown.d.ts +2 -1
  8. package/dist/components/renderer/AutocompleteDropdown.js +17 -15
  9. package/dist/components/renderer/AutocompleteDropdown.js.map +1 -1
  10. package/dist/components/renderer/OneBlinkFormElements.js +7 -1
  11. package/dist/components/renderer/OneBlinkFormElements.js.map +1 -1
  12. package/dist/components/renderer/PageFormElements.d.ts +1 -3
  13. package/dist/components/renderer/PageFormElements.js +1 -16
  14. package/dist/components/renderer/PageFormElements.js.map +1 -1
  15. package/dist/components/renderer/ReverseGeocode.d.ts +4 -4
  16. package/dist/components/renderer/ReverseGeocode.js +42 -56
  17. package/dist/components/renderer/ReverseGeocode.js.map +1 -1
  18. package/dist/form-elements/FormElementGeoscapeAddress.js +1 -0
  19. package/dist/form-elements/FormElementGeoscapeAddress.js.map +1 -1
  20. package/dist/form-elements/FormElementGoogleAddress.d.ts +15 -0
  21. package/dist/form-elements/FormElementGoogleAddress.js +146 -0
  22. package/dist/form-elements/FormElementGoogleAddress.js.map +1 -0
  23. package/dist/form-elements/FormElementLocation.js +5 -7
  24. package/dist/form-elements/FormElementLocation.js.map +1 -1
  25. package/dist/form-elements/FormElementPointAddress.js +1 -0
  26. package/dist/form-elements/FormElementPointAddress.js.map +1 -1
  27. package/dist/hooks/useGoogle.d.ts +4 -0
  28. package/dist/hooks/useGoogle.js +7 -0
  29. package/dist/hooks/useGoogle.js.map +1 -0
  30. package/dist/hooks/useGoogleJsApiLoader.d.ts +10 -0
  31. package/dist/hooks/useGoogleJsApiLoader.js +16 -0
  32. package/dist/hooks/useGoogleJsApiLoader.js.map +1 -0
  33. package/dist/hooks/useGoogleMapsApiKey.d.ts +1 -1
  34. package/dist/hooks/useGoogleMapsApiKey.js +1 -1
  35. package/dist/hooks/useGoogleMapsApiKey.js.map +1 -1
  36. package/dist/hooks/usePages.js +3 -0
  37. package/dist/hooks/usePages.js.map +1 -1
  38. package/dist/index.d.ts +1 -0
  39. package/dist/index.js +1 -0
  40. package/dist/index.js.map +1 -1
  41. package/dist/services/form-validation.js +1 -0
  42. package/dist/services/form-validation.js.map +1 -1
  43. package/dist/services/generate-default-data.js +8 -0
  44. package/dist/services/generate-default-data.js.map +1 -1
  45. package/dist/services/injectableOptions.d.ts +1 -0
  46. package/dist/services/injectableOptions.js +8 -2
  47. package/dist/services/injectableOptions.js.map +1 -1
  48. package/dist/styles/autocomplete.scss +10 -0
  49. package/dist/styles.css +8 -0
  50. package/package.json +3 -3
@@ -5,73 +5,58 @@ import { parseLocationValue } from '../../form-elements/FormElementLocation';
5
5
  import useFormSubmissionModel from '../../hooks/useFormSubmissionModelContext';
6
6
  import useFormDefinition from '../../hooks/useFormDefinition';
7
7
  import useFormIsReadOnly from '../../hooks/useFormIsReadOnly';
8
- import useIsOffline from '../../hooks/useIsOffline';
9
8
  const ReverseGeocodeContext = React.createContext({
10
9
  isReverseGeocoding: false,
11
10
  });
12
- export default function ReverseGeocode({ value, element, onLookup, children, }) {
11
+ export default function ReverseGeocode({ value, element, onChange, children, }) {
13
12
  var _a;
14
13
  const coords = React.useMemo(() => parseLocationValue(value), [value]);
15
14
  const [reverseGeocodingState, setReverseGeocodingState] = React.useState({
16
15
  isReverseGeocoding: false,
17
16
  });
18
- const isOffline = useIsOffline();
19
17
  const formDefinition = useFormDefinition();
20
18
  const formSubmissionModel = useFormSubmissionModel();
21
19
  const formIsReadOnly = useFormIsReadOnly();
22
20
  const formattedAddressElement = React.useMemo(() => {
23
21
  var _a;
24
22
  if ((_a = element.reverseGeocoding) === null || _a === void 0 ? void 0 : _a.formattedAddressElementId) {
25
- return formElementsService.findFormElement(formSubmissionModel.elements, (el) => { var _a; return el.id === ((_a = element.reverseGeocoding) === null || _a === void 0 ? void 0 : _a.formattedAddressElementId); });
23
+ return formElementsService
24
+ .flattenFormElements(formSubmissionModel.elements)
25
+ .find((el) => { var _a; return el.id === ((_a = element.reverseGeocoding) === null || _a === void 0 ? void 0 : _a.formattedAddressElementId); });
26
26
  }
27
27
  }, [
28
28
  (_a = element.reverseGeocoding) === null || _a === void 0 ? void 0 : _a.formattedAddressElementId,
29
29
  formSubmissionModel.elements,
30
30
  ]);
31
- const mergeReverseGeocodeData = React.useCallback((reverseGeocodeResult) => {
32
- onLookup(({ submission, elements, executedLookups }) => {
33
- return {
34
- elements,
35
- submission: {
36
- ...submission,
37
- ...reverseGeocodeResult,
38
- },
39
- executedLookups,
40
- };
41
- });
42
- }, [onLookup]);
43
31
  React.useEffect(() => {
32
+ if (formIsReadOnly || !coords || !formattedAddressElement) {
33
+ return;
34
+ }
44
35
  const abortController = new AbortController();
45
36
  const effect = async () => {
46
37
  var _a, _b;
47
- setReverseGeocodingState({ isReverseGeocoding: true });
48
38
  try {
49
- if (coords && formattedAddressElement) {
50
- if (element.reverseGeocoding && formattedAddressElement) {
51
- const mergeReverseGeocodeResult = {};
52
- const { reverseGeocodeResult } = await formService.getGeoscapeReverseGeocoding({
53
- lat: coords.latitude,
54
- lng: coords.longitude,
55
- formId: formDefinition.id,
56
- abortSignal: abortController.signal,
57
- });
58
- switch (formattedAddressElement.type) {
59
- case 'text': {
60
- if ((_a = reverseGeocodeResult.addressDetails) === null || _a === void 0 ? void 0 : _a.formattedAddress) {
61
- mergeReverseGeocodeResult[formattedAddressElement.name] =
62
- (_b = reverseGeocodeResult.addressDetails) === null || _b === void 0 ? void 0 : _b.formattedAddress;
63
- }
64
- break;
65
- }
66
- case 'geoscapeAddress': {
67
- mergeReverseGeocodeResult[formattedAddressElement.name] =
68
- reverseGeocodeResult;
69
- break;
70
- }
71
- }
72
- if (!abortController.signal.aborted) {
73
- mergeReverseGeocodeData(mergeReverseGeocodeResult);
39
+ setReverseGeocodingState({ isReverseGeocoding: true });
40
+ const { reverseGeocodeResult } = await formService.getGeoscapeReverseGeocoding({
41
+ lat: coords.latitude,
42
+ lng: coords.longitude,
43
+ formId: formDefinition.id,
44
+ abortSignal: abortController.signal,
45
+ });
46
+ switch (formattedAddressElement.type) {
47
+ case 'text': {
48
+ if ((_a = reverseGeocodeResult.addressDetails) === null || _a === void 0 ? void 0 : _a.formattedAddress) {
49
+ onChange(formattedAddressElement, {
50
+ value: (_b = reverseGeocodeResult.addressDetails) === null || _b === void 0 ? void 0 : _b.formattedAddress,
51
+ });
74
52
  }
53
+ break;
54
+ }
55
+ case 'geoscapeAddress': {
56
+ onChange(formattedAddressElement, {
57
+ value: reverseGeocodeResult,
58
+ });
59
+ break;
75
60
  }
76
61
  }
77
62
  setReverseGeocodingState({
@@ -79,13 +64,19 @@ export default function ReverseGeocode({ value, element, onLookup, children, })
79
64
  });
80
65
  }
81
66
  catch (e) {
82
- let errorMsg = 'Could not find your address.';
83
- if (e instanceof OneBlinkAppsError && e.httpStatusCode !== 404) {
84
- errorMsg = e.message;
67
+ if (abortController.signal.aborted) {
68
+ return;
85
69
  }
86
- if (isOffline) {
87
- errorMsg =
88
- 'It looks like you're offline. Please try again when connectivity is restored.';
70
+ console.warn('Error attempting to reverse geocode location', e);
71
+ let errorMsg = 'Could not find your address.';
72
+ if (e instanceof OneBlinkAppsError) {
73
+ if (e.httpStatusCode !== 404) {
74
+ errorMsg = e.message;
75
+ }
76
+ else if (e.isOffline) {
77
+ errorMsg =
78
+ 'It looks like you're offline. Please try again when connectivity is restored.';
79
+ }
89
80
  }
90
81
  setReverseGeocodingState({
91
82
  isReverseGeocoding: false,
@@ -93,19 +84,14 @@ export default function ReverseGeocode({ value, element, onLookup, children, })
93
84
  });
94
85
  }
95
86
  };
96
- if (!formIsReadOnly) {
97
- effect();
98
- }
87
+ effect();
99
88
  return () => abortController.abort();
100
89
  }, [
101
90
  coords,
102
- element.reverseGeocoding,
103
91
  formDefinition.id,
104
- formDefinition.organisationId,
105
- formattedAddressElement,
106
- mergeReverseGeocodeData,
107
- isOffline,
108
92
  formIsReadOnly,
93
+ formattedAddressElement,
94
+ onChange,
109
95
  ]);
110
96
  return (React.createElement(ReverseGeocodeContext.Provider, { value: reverseGeocodingState }, children));
111
97
  }
@@ -1 +1 @@
1
- {"version":3,"file":"ReverseGeocode.js","sourceRoot":"","sources":["../../../src/components/renderer/ReverseGeocode.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAG9B,OAAO,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAA;AAC/D,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAA;AAExD,OAAO,EAAE,kBAAkB,EAAE,MAAM,yCAAyC,CAAA;AAC5E,OAAO,sBAAsB,MAAM,2CAA2C,CAAA;AAC9E,OAAO,iBAAiB,MAAM,+BAA+B,CAAA;AAC7D,OAAO,iBAAiB,MAAM,+BAA+B,CAAA;AAE7D,OAAO,YAAY,MAAM,0BAA0B,CAAA;AAOnD,MAAM,qBAAqB,GAAG,KAAK,CAAC,aAAa,CAA6B;IAC5E,kBAAkB,EAAE,KAAK;CAC1B,CAAC,CAAA;AAEF,MAAM,CAAC,OAAO,UAAU,cAAc,CAAC,EACrC,KAAK,EACL,OAAO,EACP,QAAQ,EACR,QAAQ,GAKR;;IACA,MAAM,MAAM,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,kBAAkB,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAA;IACtE,MAAM,CAAC,qBAAqB,EAAE,wBAAwB,CAAC,GACrD,KAAK,CAAC,QAAQ,CAA6B;QACzC,kBAAkB,EAAE,KAAK;KAC1B,CAAC,CAAA;IACJ,MAAM,SAAS,GAAG,YAAY,EAAE,CAAA;IAEhC,MAAM,cAAc,GAAG,iBAAiB,EAAE,CAAA;IAC1C,MAAM,mBAAmB,GAAG,sBAAsB,EAAE,CAAA;IACpD,MAAM,cAAc,GAAG,iBAAiB,EAAE,CAAA;IAE1C,MAAM,uBAAuB,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,EAAE;;QACjD,IAAI,MAAA,OAAO,CAAC,gBAAgB,0CAAE,yBAAyB,EAAE;YACvD,OAAO,mBAAmB,CAAC,eAAe,CACxC,mBAAmB,CAAC,QAAQ,EAC5B,CAAC,EAAE,EAAE,EAAE,WAAC,OAAA,EAAE,CAAC,EAAE,MAAK,MAAA,OAAO,CAAC,gBAAgB,0CAAE,yBAAyB,CAAA,CAAA,EAAA,CACtE,CAAA;SACF;IACH,CAAC,EAAE;QACD,MAAA,OAAO,CAAC,gBAAgB,0CAAE,yBAAyB;QACnD,mBAAmB,CAAC,QAAQ;KAC7B,CAAC,CAAA;IAEF,MAAM,uBAAuB,GAAG,KAAK,CAAC,WAAW,CAC/C,CAAC,oBAAoE,EAAE,EAAE;QACvE,QAAQ,CAAC,CAAC,EAAE,UAAU,EAAE,QAAQ,EAAE,eAAe,EAAE,EAAE,EAAE;YACrD,OAAO;gBACL,QAAQ;gBACR,UAAU,EAAE;oBACV,GAAG,UAAU;oBACb,GAAG,oBAAoB;iBACxB;gBACD,eAAe;aAChB,CAAA;QACH,CAAC,CAAC,CAAA;IACJ,CAAC,EACD,CAAC,QAAQ,CAAC,CACX,CAAA;IAED,KAAK,CAAC,SAAS,CAAC,GAAG,EAAE;QACnB,MAAM,eAAe,GAAG,IAAI,eAAe,EAAE,CAAA;QAC7C,MAAM,MAAM,GAAG,KAAK,IAAI,EAAE;;YACxB,wBAAwB,CAAC,EAAE,kBAAkB,EAAE,IAAI,EAAE,CAAC,CAAA;YACtD,IAAI;gBACF,IAAI,MAAM,IAAI,uBAAuB,EAAE;oBACrC,IAAI,OAAO,CAAC,gBAAgB,IAAI,uBAAuB,EAAE;wBACvD,MAAM,yBAAyB,GAC7B,EAAE,CAAA;wBACJ,MAAM,EAAE,oBAAoB,EAAE,GAC5B,MAAM,WAAW,CAAC,2BAA2B,CAAC;4BAC5C,GAAG,EAAE,MAAM,CAAC,QAAQ;4BACpB,GAAG,EAAE,MAAM,CAAC,SAAS;4BACrB,MAAM,EAAE,cAAc,CAAC,EAAE;4BACzB,WAAW,EAAE,eAAe,CAAC,MAAM;yBACpC,CAAC,CAAA;wBACJ,QAAQ,uBAAuB,CAAC,IAAI,EAAE;4BACpC,KAAK,MAAM,CAAC,CAAC;gCACX,IAAI,MAAA,oBAAoB,CAAC,cAAc,0CAAE,gBAAgB,EAAE;oCACzD,yBAAyB,CAAC,uBAAuB,CAAC,IAAI,CAAC;wCACrD,MAAA,oBAAoB,CAAC,cAAc,0CAAE,gBAAgB,CAAA;iCACxD;gCACD,MAAK;6BACN;4BACD,KAAK,iBAAiB,CAAC,CAAC;gCACtB,yBAAyB,CAAC,uBAAuB,CAAC,IAAI,CAAC;oCACrD,oBAAoB,CAAA;gCACtB,MAAK;6BACN;yBACF;wBACD,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,OAAO,EAAE;4BACnC,uBAAuB,CAAC,yBAAyB,CAAC,CAAA;yBACnD;qBACF;iBACF;gBACD,wBAAwB,CAAC;oBACvB,kBAAkB,EAAE,KAAK;iBAC1B,CAAC,CAAA;aACH;YAAC,OAAO,CAAC,EAAE;gBACV,IAAI,QAAQ,GAAG,8BAA8B,CAAA;gBAC7C,IAAI,CAAC,YAAY,iBAAiB,IAAI,CAAC,CAAC,cAAc,KAAK,GAAG,EAAE;oBAC9D,QAAQ,GAAG,CAAC,CAAC,OAAO,CAAA;iBACrB;gBAED,IAAI,SAAS,EAAE;oBACb,QAAQ;wBACN,oFAAoF,CAAA;iBACvF;gBACD,wBAAwB,CAAC;oBACvB,kBAAkB,EAAE,KAAK;oBACzB,wBAAwB,EAAE,QAAQ;iBACnC,CAAC,CAAA;aACH;QACH,CAAC,CAAA;QAED,IAAI,CAAC,cAAc,EAAE;YACnB,MAAM,EAAE,CAAA;SACT;QAED,OAAO,GAAG,EAAE,CAAC,eAAe,CAAC,KAAK,EAAE,CAAA;IACtC,CAAC,EAAE;QACD,MAAM;QACN,OAAO,CAAC,gBAAgB;QACxB,cAAc,CAAC,EAAE;QACjB,cAAc,CAAC,cAAc;QAC7B,uBAAuB;QACvB,uBAAuB;QACvB,SAAS;QACT,cAAc;KACf,CAAC,CAAA;IAEF,OAAO,CACL,oBAAC,qBAAqB,CAAC,QAAQ,IAAC,KAAK,EAAE,qBAAqB,IACzD,QAAQ,CACsB,CAClC,CAAA;AACH,CAAC;AAED,MAAM,UAAU,wBAAwB;IACtC,MAAM,qBAAqB,GAAG,KAAK,CAAC,UAAU,CAAC,qBAAqB,CAAC,CAAA;IACrE,IAAI,CAAC,qBAAqB,EAAE;QAC1B,MAAM,IAAI,SAAS,CACjB,iHAAiH,CAClH,CAAA;KACF;IACD,OAAO,qBAAqB,CAAA;AAC9B,CAAC","sourcesContent":["import * as React from 'react'\n\nimport { FormTypes, SubmissionTypes } from '@oneblink/types'\nimport { formService, OneBlinkAppsError } from '@oneblink/apps'\nimport { formElementsService } from '@oneblink/sdk-core'\n\nimport { parseLocationValue } from '../../form-elements/FormElementLocation'\nimport useFormSubmissionModel from '../../hooks/useFormSubmissionModelContext'\nimport useFormDefinition from '../../hooks/useFormDefinition'\nimport useFormIsReadOnly from '../../hooks/useFormIsReadOnly'\nimport { FormElementLookupHandler } from '../../types/form'\nimport useIsOffline from '../../hooks/useIsOffline'\n\ntype ReverseGeocodeContextValue = {\n isReverseGeocoding: boolean\n reverseGeocodingErrorMsg?: string\n}\n\nconst ReverseGeocodeContext = React.createContext<ReverseGeocodeContextValue>({\n isReverseGeocoding: false,\n})\n\nexport default function ReverseGeocode({\n value,\n element,\n onLookup,\n children,\n}: React.PropsWithChildren<{\n value: unknown\n element: FormTypes.LocationElement\n onLookup: FormElementLookupHandler\n}>) {\n const coords = React.useMemo(() => parseLocationValue(value), [value])\n const [reverseGeocodingState, setReverseGeocodingState] =\n React.useState<ReverseGeocodeContextValue>({\n isReverseGeocoding: false,\n })\n const isOffline = useIsOffline()\n\n const formDefinition = useFormDefinition()\n const formSubmissionModel = useFormSubmissionModel()\n const formIsReadOnly = useFormIsReadOnly()\n\n const formattedAddressElement = React.useMemo(() => {\n if (element.reverseGeocoding?.formattedAddressElementId) {\n return formElementsService.findFormElement(\n formSubmissionModel.elements,\n (el) => el.id === element.reverseGeocoding?.formattedAddressElementId,\n )\n }\n }, [\n element.reverseGeocoding?.formattedAddressElementId,\n formSubmissionModel.elements,\n ])\n\n const mergeReverseGeocodeData = React.useCallback(\n (reverseGeocodeResult: SubmissionTypes.S3SubmissionData['submission']) => {\n onLookup(({ submission, elements, executedLookups }) => {\n return {\n elements,\n submission: {\n ...submission,\n ...reverseGeocodeResult,\n },\n executedLookups,\n }\n })\n },\n [onLookup],\n )\n\n React.useEffect(() => {\n const abortController = new AbortController()\n const effect = async () => {\n setReverseGeocodingState({ isReverseGeocoding: true })\n try {\n if (coords && formattedAddressElement) {\n if (element.reverseGeocoding && formattedAddressElement) {\n const mergeReverseGeocodeResult: SubmissionTypes.S3SubmissionData['submission'] =\n {}\n const { reverseGeocodeResult } =\n await formService.getGeoscapeReverseGeocoding({\n lat: coords.latitude,\n lng: coords.longitude,\n formId: formDefinition.id,\n abortSignal: abortController.signal,\n })\n switch (formattedAddressElement.type) {\n case 'text': {\n if (reverseGeocodeResult.addressDetails?.formattedAddress) {\n mergeReverseGeocodeResult[formattedAddressElement.name] =\n reverseGeocodeResult.addressDetails?.formattedAddress\n }\n break\n }\n case 'geoscapeAddress': {\n mergeReverseGeocodeResult[formattedAddressElement.name] =\n reverseGeocodeResult\n break\n }\n }\n if (!abortController.signal.aborted) {\n mergeReverseGeocodeData(mergeReverseGeocodeResult)\n }\n }\n }\n setReverseGeocodingState({\n isReverseGeocoding: false,\n })\n } catch (e) {\n let errorMsg = 'Could not find your address.'\n if (e instanceof OneBlinkAppsError && e.httpStatusCode !== 404) {\n errorMsg = e.message\n }\n\n if (isOffline) {\n errorMsg =\n 'It looks like you&apos;re offline. Please try again when connectivity is restored.'\n }\n setReverseGeocodingState({\n isReverseGeocoding: false,\n reverseGeocodingErrorMsg: errorMsg,\n })\n }\n }\n\n if (!formIsReadOnly) {\n effect()\n }\n\n return () => abortController.abort()\n }, [\n coords,\n element.reverseGeocoding,\n formDefinition.id,\n formDefinition.organisationId,\n formattedAddressElement,\n mergeReverseGeocodeData,\n isOffline,\n formIsReadOnly,\n ])\n\n return (\n <ReverseGeocodeContext.Provider value={reverseGeocodingState}>\n {children}\n </ReverseGeocodeContext.Provider>\n )\n}\n\nexport function useReverseGeocodeContext() {\n const reverseGeocodeContext = React.useContext(ReverseGeocodeContext)\n if (!reverseGeocodeContext) {\n throw new TypeError(\n 'You have attempted to run the hook \"useReverseGeocodeContext()\" outside of the \"ReverseGeocodeContext\" context.',\n )\n }\n return reverseGeocodeContext\n}\n"]}
1
+ {"version":3,"file":"ReverseGeocode.js","sourceRoot":"","sources":["../../../src/components/renderer/ReverseGeocode.tsx"],"names":[],"mappings":"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","sourcesContent":["import * as React from 'react'\n\nimport { FormTypes, GeoscapeTypes } from '@oneblink/types'\nimport { formService, OneBlinkAppsError } from '@oneblink/apps'\nimport { formElementsService } from '@oneblink/sdk-core'\n\nimport { parseLocationValue } from '../../form-elements/FormElementLocation'\nimport useFormSubmissionModel from '../../hooks/useFormSubmissionModelContext'\nimport useFormDefinition from '../../hooks/useFormDefinition'\nimport useFormIsReadOnly from '../../hooks/useFormIsReadOnly'\nimport { FormElementValueChangeHandler } from '../../types/form'\n\ntype ReverseGeocodeContextValue = {\n isReverseGeocoding: boolean\n reverseGeocodingErrorMsg?: string\n}\n\nconst ReverseGeocodeContext = React.createContext<ReverseGeocodeContextValue>({\n isReverseGeocoding: false,\n})\n\nexport default function ReverseGeocode({\n value,\n element,\n onChange,\n children,\n}: React.PropsWithChildren<{\n value: unknown\n element: FormTypes.LocationElement\n onChange: FormElementValueChangeHandler<\n GeoscapeTypes.GeoscapeAddress | string\n >\n}>) {\n const coords = React.useMemo(() => parseLocationValue(value), [value])\n const [reverseGeocodingState, setReverseGeocodingState] =\n React.useState<ReverseGeocodeContextValue>({\n isReverseGeocoding: false,\n })\n\n const formDefinition = useFormDefinition()\n const formSubmissionModel = useFormSubmissionModel()\n const formIsReadOnly = useFormIsReadOnly()\n\n const formattedAddressElement = React.useMemo(() => {\n if (element.reverseGeocoding?.formattedAddressElementId) {\n return formElementsService\n .flattenFormElements(formSubmissionModel.elements)\n .find(\n (el) => el.id === element.reverseGeocoding?.formattedAddressElementId,\n )\n }\n }, [\n element.reverseGeocoding?.formattedAddressElementId,\n formSubmissionModel.elements,\n ])\n\n React.useEffect(() => {\n if (formIsReadOnly || !coords || !formattedAddressElement) {\n return\n }\n\n const abortController = new AbortController()\n const effect = async () => {\n try {\n setReverseGeocodingState({ isReverseGeocoding: true })\n const { reverseGeocodeResult } =\n await formService.getGeoscapeReverseGeocoding({\n lat: coords.latitude,\n lng: coords.longitude,\n formId: formDefinition.id,\n abortSignal: abortController.signal,\n })\n switch (formattedAddressElement.type) {\n case 'text': {\n if (reverseGeocodeResult.addressDetails?.formattedAddress) {\n onChange(formattedAddressElement, {\n value: reverseGeocodeResult.addressDetails?.formattedAddress,\n })\n }\n break\n }\n case 'geoscapeAddress': {\n onChange(formattedAddressElement, {\n value: reverseGeocodeResult,\n })\n break\n }\n }\n setReverseGeocodingState({\n isReverseGeocoding: false,\n })\n } catch (e) {\n if (abortController.signal.aborted) {\n return\n }\n console.warn('Error attempting to reverse geocode location', e)\n let errorMsg = 'Could not find your address.'\n if (e instanceof OneBlinkAppsError) {\n if (e.httpStatusCode !== 404) {\n errorMsg = e.message\n } else if (e.isOffline) {\n errorMsg =\n 'It looks like you&apos;re offline. Please try again when connectivity is restored.'\n }\n }\n\n setReverseGeocodingState({\n isReverseGeocoding: false,\n reverseGeocodingErrorMsg: errorMsg,\n })\n }\n }\n\n effect()\n\n return () => abortController.abort()\n }, [\n coords,\n formDefinition.id,\n formIsReadOnly,\n formattedAddressElement,\n onChange,\n ])\n\n return (\n <ReverseGeocodeContext.Provider value={reverseGeocodingState}>\n {children}\n </ReverseGeocodeContext.Provider>\n )\n}\n\nexport function useReverseGeocodeContext() {\n const reverseGeocodeContext = React.useContext(ReverseGeocodeContext)\n if (!reverseGeocodeContext) {\n throw new TypeError(\n 'You have attempted to run the hook \"useReverseGeocodeContext()\" outside of the \"ReverseGeocodeContext\" context.',\n )\n }\n return reverseGeocodeContext\n}\n"]}
@@ -57,6 +57,7 @@ function FormElementGeoscapeAddress({ formId, id, element, value, displayValidat
57
57
  setLabel(newLabel || '');
58
58
  }
59
59
  }
60
+ // we don't need this to run again when the label changes
60
61
  // eslint-disable-next-line react-hooks/exhaustive-deps
61
62
  }, [value]);
62
63
  return (React.createElement("div", { className: "cypress-geoscape-address-element" },
@@ -1 +1 @@
1
- {"version":3,"file":"FormElementGeoscapeAddress.js","sourceRoot":"","sources":["../../src/form-elements/FormElementGeoscapeAddress.tsx"],"names":[],"mappings":"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","sourcesContent":["import * as React from 'react'\nimport { formService } from '@oneblink/apps'\n\nimport AutocompleteDropdown from '../components/renderer/AutocompleteDropdown'\nimport FormElementLabelContainer from '../components/renderer/FormElementLabelContainer'\nimport { FormTypes, GeoscapeTypes } from '@oneblink/types'\nimport useIsMounted from '../hooks/useIsMounted'\nimport { FormElementValueChangeHandler, IsDirtyProps } from '../types/form'\nimport useElementAriaDescribedby from '../hooks/useElementAriaDescribedby'\n\ntype Props = {\n formId: number\n id: string\n element: FormTypes.GeoscapeAddressElement\n value: GeoscapeTypes.GeoscapeAddress | undefined\n displayValidationMessage: boolean\n validationMessage: string | undefined\n onChange: FormElementValueChangeHandler<GeoscapeTypes.GeoscapeAddress>\n} & IsDirtyProps\n\nfunction FormElementGeoscapeAddress({\n formId,\n id,\n element,\n value,\n displayValidationMessage,\n validationMessage,\n onChange,\n isDirty,\n setIsDirty,\n}: Props) {\n const ariaDescribedby = useElementAriaDescribedby(id, element)\n const isMounted = useIsMounted()\n const [label, setLabel] = React.useState('')\n const [error, setError] = React.useState<Error | undefined>()\n const [isLoadingAddressDetails, setIsLoadingAddressDetails] =\n React.useState(false)\n\n const handleSearch = React.useCallback(\n async (query: string, abortSignal: AbortSignal) => {\n setError(undefined)\n\n const params: {\n query: string\n maxNumberOfResults?: number\n stateTerritory?: string\n } = {\n query,\n maxNumberOfResults: 10,\n }\n\n if (element.stateTerritoryFilter) {\n params.stateTerritory = element.stateTerritoryFilter.join(',')\n }\n\n const result = await formService.searchGeoscapeAddresses(\n formId,\n params,\n abortSignal,\n )\n\n return result.suggest.map((suggestion, index) => ({\n value: suggestion.id || index.toString(),\n label: suggestion.address || index.toString(),\n }))\n },\n [element.stateTerritoryFilter, formId],\n )\n\n const handleChange = React.useCallback(\n async (addressId: string | undefined) => {\n if (!addressId) {\n onChange(element, {\n value: undefined,\n })\n return\n }\n\n setIsLoadingAddressDetails(true)\n try {\n const result = await formService.getGeoscapeAddress(formId, addressId)\n onChange(element, {\n value: result,\n })\n } catch (newError) {\n if (isMounted.current) {\n setError(newError as Error)\n }\n }\n if (isMounted.current) {\n setIsLoadingAddressDetails(false)\n }\n },\n [isMounted, onChange, element, formId],\n )\n\n // Ensure the label is set if the value is set outside of this component\n React.useEffect(() => {\n if (value) {\n const newLabel = value.addressDetails?.formattedAddress || value.addressId\n if (label !== newLabel) {\n setLabel(newLabel || '')\n }\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [value])\n\n return (\n <div className=\"cypress-geoscape-address-element\">\n <FormElementLabelContainer\n className=\"ob-geoscape-address ob-autocomplete\"\n element={element}\n id={id}\n required={element.required}\n >\n <AutocompleteDropdown\n id={id}\n label={label}\n disabled={element.readOnly || isLoadingAddressDetails}\n placeholder={element.placeholderValue}\n required={element.required}\n value={value}\n validationMessage={validationMessage}\n displayValidationMessage={displayValidationMessage}\n onChangeValue={handleChange}\n isLoading={isLoadingAddressDetails}\n hasError={!!error}\n onChangeLabel={setLabel}\n searchDebounceMs={750}\n searchMinCharacters={4}\n onSearch={handleSearch}\n isDirty={isDirty}\n setIsDirty={setIsDirty}\n aria-describedby={ariaDescribedby}\n />\n </FormElementLabelContainer>\n\n {error && (\n <div role=\"alert\" className=\"has-margin-top-8\">\n <div className=\"has-text-danger ob-error__text cypress-geoscape-address-details-error-message\">\n {error.toString()}\n </div>\n </div>\n )}\n </div>\n )\n}\n\nexport default React.memo(FormElementGeoscapeAddress)\n"]}
1
+ {"version":3,"file":"FormElementGeoscapeAddress.js","sourceRoot":"","sources":["../../src/form-elements/FormElementGeoscapeAddress.tsx"],"names":[],"mappings":"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","sourcesContent":["import * as React from 'react'\nimport { formService } from '@oneblink/apps'\n\nimport AutocompleteDropdown from '../components/renderer/AutocompleteDropdown'\nimport FormElementLabelContainer from '../components/renderer/FormElementLabelContainer'\nimport { FormTypes, GeoscapeTypes } from '@oneblink/types'\nimport useIsMounted from '../hooks/useIsMounted'\nimport { FormElementValueChangeHandler, IsDirtyProps } from '../types/form'\nimport useElementAriaDescribedby from '../hooks/useElementAriaDescribedby'\n\ntype Props = {\n formId: number\n id: string\n element: FormTypes.GeoscapeAddressElement\n value: GeoscapeTypes.GeoscapeAddress | undefined\n displayValidationMessage: boolean\n validationMessage: string | undefined\n onChange: FormElementValueChangeHandler<GeoscapeTypes.GeoscapeAddress>\n} & IsDirtyProps\n\nfunction FormElementGeoscapeAddress({\n formId,\n id,\n element,\n value,\n displayValidationMessage,\n validationMessage,\n onChange,\n isDirty,\n setIsDirty,\n}: Props) {\n const ariaDescribedby = useElementAriaDescribedby(id, element)\n const isMounted = useIsMounted()\n const [label, setLabel] = React.useState('')\n const [error, setError] = React.useState<Error | undefined>()\n const [isLoadingAddressDetails, setIsLoadingAddressDetails] =\n React.useState(false)\n\n const handleSearch = React.useCallback(\n async (query: string, abortSignal: AbortSignal) => {\n setError(undefined)\n\n const params: {\n query: string\n maxNumberOfResults?: number\n stateTerritory?: string\n } = {\n query,\n maxNumberOfResults: 10,\n }\n\n if (element.stateTerritoryFilter) {\n params.stateTerritory = element.stateTerritoryFilter.join(',')\n }\n\n const result = await formService.searchGeoscapeAddresses(\n formId,\n params,\n abortSignal,\n )\n\n return result.suggest.map((suggestion, index) => ({\n value: suggestion.id || index.toString(),\n label: suggestion.address || index.toString(),\n }))\n },\n [element.stateTerritoryFilter, formId],\n )\n\n const handleChange = React.useCallback(\n async (addressId: string | undefined) => {\n if (!addressId) {\n onChange(element, {\n value: undefined,\n })\n return\n }\n\n setIsLoadingAddressDetails(true)\n try {\n const result = await formService.getGeoscapeAddress(formId, addressId)\n onChange(element, {\n value: result,\n })\n } catch (newError) {\n if (isMounted.current) {\n setError(newError as Error)\n }\n }\n if (isMounted.current) {\n setIsLoadingAddressDetails(false)\n }\n },\n [isMounted, onChange, element, formId],\n )\n\n // Ensure the label is set if the value is set outside of this component\n React.useEffect(() => {\n if (value) {\n const newLabel = value.addressDetails?.formattedAddress || value.addressId\n if (label !== newLabel) {\n setLabel(newLabel || '')\n }\n }\n // we don't need this to run again when the label changes\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [value])\n\n return (\n <div className=\"cypress-geoscape-address-element\">\n <FormElementLabelContainer\n className=\"ob-geoscape-address ob-autocomplete\"\n element={element}\n id={id}\n required={element.required}\n >\n <AutocompleteDropdown\n id={id}\n label={label}\n disabled={element.readOnly || isLoadingAddressDetails}\n placeholder={element.placeholderValue}\n required={element.required}\n value={value}\n validationMessage={validationMessage}\n displayValidationMessage={displayValidationMessage}\n onChangeValue={handleChange}\n isLoading={isLoadingAddressDetails}\n hasError={!!error}\n onChangeLabel={setLabel}\n searchDebounceMs={750}\n searchMinCharacters={4}\n onSearch={handleSearch}\n isDirty={isDirty}\n setIsDirty={setIsDirty}\n aria-describedby={ariaDescribedby}\n />\n </FormElementLabelContainer>\n\n {error && (\n <div role=\"alert\" className=\"has-margin-top-8\">\n <div className=\"has-text-danger ob-error__text cypress-geoscape-address-details-error-message\">\n {error.toString()}\n </div>\n </div>\n )}\n </div>\n )\n}\n\nexport default React.memo(FormElementGeoscapeAddress)\n"]}
@@ -0,0 +1,15 @@
1
+ import * as React from 'react';
2
+ import { FormTypes, GoogleTypes } from '@oneblink/types';
3
+ import { FormElementValueChangeHandler, IsDirtyProps } from '../types/form';
4
+ type Props = {
5
+ formId: number;
6
+ id: string;
7
+ element: FormTypes.GoogleAddressElement;
8
+ value: GoogleTypes.GoogleMapsAddress | undefined;
9
+ displayValidationMessage: boolean;
10
+ validationMessage: string | undefined;
11
+ onChange: FormElementValueChangeHandler<GoogleTypes.GoogleMapsAddress>;
12
+ } & IsDirtyProps;
13
+ declare function FormElementGoogleAddress({ id, element, value, displayValidationMessage, validationMessage, onChange, isDirty, setIsDirty, }: Props): React.JSX.Element;
14
+ declare const _default: React.MemoExoticComponent<typeof FormElementGoogleAddress>;
15
+ export default _default;
@@ -0,0 +1,146 @@
1
+ import * as React from 'react';
2
+ import { OneBlinkAppsError, Sentry } from '@oneblink/apps';
3
+ import AutocompleteDropdown from '../components/renderer/AutocompleteDropdown';
4
+ import FormElementLabelContainer from '../components/renderer/FormElementLabelContainer';
5
+ import useGoogle from '../hooks/useGoogle';
6
+ import useIsMounted from '../hooks/useIsMounted';
7
+ import useElementAriaDescribedby from '../hooks/useElementAriaDescribedby';
8
+ function FormElementGoogleAddress({ id, element, value, displayValidationMessage, validationMessage, onChange, isDirty, setIsDirty, }) {
9
+ const ariaDescribedby = useElementAriaDescribedby(id, element);
10
+ const isMounted = useIsMounted();
11
+ const [label, setLabel] = React.useState('');
12
+ const [error, setError] = React.useState();
13
+ const [isLoadingAddressDetails, setIsLoadingAddressDetails] = React.useState(false);
14
+ const { isLoaded } = useGoogle();
15
+ const autocompleteService = React.useMemo(() => {
16
+ if (isLoaded) {
17
+ return new google.maps.places.AutocompleteService();
18
+ }
19
+ }, [isLoaded]);
20
+ const dummyMap = React.useMemo(() => {
21
+ if (isLoaded) {
22
+ return new google.maps.Map(document.createElement('div'));
23
+ }
24
+ }, [isLoaded]);
25
+ const handleSearch = React.useCallback(async (input, abortSignal) => {
26
+ setError(undefined);
27
+ if (autocompleteService) {
28
+ const predictions = await new Promise((resolve, reject) => {
29
+ autocompleteService.getQueryPredictions({
30
+ input,
31
+ }, (predictions, status) => {
32
+ switch (status) {
33
+ case google.maps.places.PlacesServiceStatus.OK:
34
+ case google.maps.places.PlacesServiceStatus.ZERO_RESULTS: {
35
+ resolve(predictions !== null && predictions !== void 0 ? predictions : []);
36
+ break;
37
+ }
38
+ case google.maps.places.PlacesServiceStatus.OVER_QUERY_LIMIT: {
39
+ reject(new OneBlinkAppsError('This application has gone over its Google Address querying quota. Please contact an administrator to rectify the issue or try again later.'));
40
+ break;
41
+ }
42
+ case google.maps.places.PlacesServiceStatus.INVALID_REQUEST: {
43
+ reject(new OneBlinkAppsError('Google Maps API key may not have been configured correctly, the request to retrieve address suggestions is invalid. Please contact an administrator to rectify the issue.'));
44
+ break;
45
+ }
46
+ case google.maps.places.PlacesServiceStatus.REQUEST_DENIED: {
47
+ reject(new OneBlinkAppsError('Google Maps API key has not been configured correctly. Please contact an administrator to rectify the issue.'));
48
+ break;
49
+ }
50
+ default: {
51
+ reject(new OneBlinkAppsError('An unknown error has occurred. Please try again and contact support if the problem persists.'));
52
+ }
53
+ }
54
+ });
55
+ }).catch((e) => {
56
+ if (!abortSignal.aborted) {
57
+ Sentry.captureException(e);
58
+ }
59
+ throw e;
60
+ });
61
+ if (!abortSignal.aborted) {
62
+ return predictions.reduce((results, prediction) => {
63
+ if (prediction.place_id) {
64
+ results.push({
65
+ value: prediction.place_id,
66
+ label: prediction.description,
67
+ });
68
+ }
69
+ return results;
70
+ }, []);
71
+ }
72
+ }
73
+ throw new OneBlinkAppsError('An unknown error has occurred. Please contact support if the problem persists.');
74
+ }, [autocompleteService]);
75
+ const handleChange = React.useCallback(async (placeId) => {
76
+ var _a, _b, _c, _d;
77
+ if (!placeId) {
78
+ onChange(element, { value: undefined });
79
+ return;
80
+ }
81
+ setIsLoadingAddressDetails(true);
82
+ try {
83
+ //this should not happen, we can't get a place Id without google being present
84
+ if (!isLoaded || !dummyMap) {
85
+ throw new OneBlinkAppsError('An unknown error has occurred. Please contact support if the problem persists.', {
86
+ originalError: new Error('Google Places library has not be initialised'),
87
+ });
88
+ }
89
+ const placeService = new google.maps.places.PlacesService(dummyMap);
90
+ const place = await new Promise((resolve, reject) => {
91
+ placeService.getDetails({
92
+ placeId,
93
+ fields: [
94
+ 'place_id',
95
+ 'formatted_address',
96
+ 'geometry',
97
+ 'address_components',
98
+ ],
99
+ }, (place, status) => {
100
+ if (status !== google.maps.places.PlacesServiceStatus.OK ||
101
+ !place) {
102
+ reject(new OneBlinkAppsError(`Could not find address details for place with id: ${placeId}`));
103
+ return;
104
+ }
105
+ resolve(place);
106
+ });
107
+ });
108
+ onChange(element, {
109
+ value: {
110
+ place_id: place.place_id,
111
+ formatted_address: place.formatted_address,
112
+ address_components: place.address_components,
113
+ geometry: {
114
+ location: (_b = (_a = place.geometry) === null || _a === void 0 ? void 0 : _a.location) === null || _b === void 0 ? void 0 : _b.toJSON(),
115
+ viewport: (_d = (_c = place.geometry) === null || _c === void 0 ? void 0 : _c.viewport) === null || _d === void 0 ? void 0 : _d.toJSON(),
116
+ },
117
+ },
118
+ });
119
+ }
120
+ catch (newError) {
121
+ if (isMounted.current) {
122
+ setError(newError);
123
+ }
124
+ }
125
+ if (isMounted.current) {
126
+ setIsLoadingAddressDetails(false);
127
+ }
128
+ }, [isMounted, onChange, element, isLoaded, dummyMap]);
129
+ // Ensure the label is set if the value is set outside of this component
130
+ React.useEffect(() => {
131
+ if (value) {
132
+ const newLabel = value.formatted_address || value.place_id;
133
+ setLabel(newLabel !== null && newLabel !== void 0 ? newLabel : '');
134
+ }
135
+ }, [value]);
136
+ return (React.createElement("div", { className: "cypress-google-address-element" },
137
+ React.createElement(FormElementLabelContainer, { className: "ob-google-address ob-autocomplete", element: element, id: id, required: element.required },
138
+ React.createElement(AutocompleteDropdown, { id: id, label: label, disabled: element.readOnly || isLoadingAddressDetails, placeholder: element.placeholderValue, required: element.required, value: value, validationMessage: validationMessage, displayValidationMessage: displayValidationMessage, onChangeValue: handleChange, isLoading: isLoadingAddressDetails, hasError: !!error, onChangeLabel: setLabel, searchDebounceMs: 750, searchMinCharacters: 4, onSearch: handleSearch, isDirty: isDirty, setIsDirty: setIsDirty, "aria-describedby": ariaDescribedby, branding: React.createElement("a", { className: "dropdown-item cypress-powered-by-google ob-autocomplete__drop-down-item-powered-by-google" },
139
+ "powered by",
140
+ ' ',
141
+ React.createElement("img", { src: "https://developers.google.com/static/maps/documentation/images/google_on_white.png" })) })),
142
+ error && (React.createElement("div", { role: "alert", className: "has-margin-top-8" },
143
+ React.createElement("div", { className: "has-text-danger ob-error__text cypress-google-address-details-error-message" }, error.message)))));
144
+ }
145
+ export default React.memo(FormElementGoogleAddress);
146
+ //# sourceMappingURL=FormElementGoogleAddress.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FormElementGoogleAddress.js","sourceRoot":"","sources":["../../src/form-elements/FormElementGoogleAddress.tsx"],"names":[],"mappings":"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","sourcesContent":["import * as React from 'react'\nimport { FormTypes, GoogleTypes } from '@oneblink/types'\nimport { OneBlinkAppsError, Sentry } from '@oneblink/apps'\n\nimport AutocompleteDropdown from '../components/renderer/AutocompleteDropdown'\nimport FormElementLabelContainer from '../components/renderer/FormElementLabelContainer'\nimport useGoogle from '../hooks/useGoogle'\nimport useIsMounted from '../hooks/useIsMounted'\nimport useElementAriaDescribedby from '../hooks/useElementAriaDescribedby'\nimport { FormElementValueChangeHandler, IsDirtyProps } from '../types/form'\n\ntype Props = {\n formId: number\n id: string\n element: FormTypes.GoogleAddressElement\n value: GoogleTypes.GoogleMapsAddress | undefined\n displayValidationMessage: boolean\n validationMessage: string | undefined\n onChange: FormElementValueChangeHandler<GoogleTypes.GoogleMapsAddress>\n} & IsDirtyProps\n\nfunction FormElementGoogleAddress({\n id,\n element,\n value,\n displayValidationMessage,\n validationMessage,\n onChange,\n isDirty,\n setIsDirty,\n}: Props) {\n const ariaDescribedby = useElementAriaDescribedby(id, element)\n const isMounted = useIsMounted()\n const [label, setLabel] = React.useState('')\n const [error, setError] = React.useState<Error | undefined>()\n const [isLoadingAddressDetails, setIsLoadingAddressDetails] =\n React.useState(false)\n\n const { isLoaded } = useGoogle()\n\n const autocompleteService = React.useMemo(() => {\n if (isLoaded) {\n return new google.maps.places.AutocompleteService()\n }\n }, [isLoaded])\n\n const dummyMap = React.useMemo(() => {\n if (isLoaded) {\n return new google.maps.Map(document.createElement('div'))\n }\n }, [isLoaded])\n\n const handleSearch = React.useCallback(\n async (input: string, abortSignal: AbortSignal) => {\n setError(undefined)\n if (autocompleteService) {\n const predictions = await new Promise<\n google.maps.places.QueryAutocompletePrediction[]\n >((resolve, reject) => {\n autocompleteService.getQueryPredictions(\n {\n input,\n },\n (predictions, status) => {\n switch (status) {\n case google.maps.places.PlacesServiceStatus.OK:\n case google.maps.places.PlacesServiceStatus.ZERO_RESULTS: {\n resolve(predictions ?? [])\n break\n }\n case google.maps.places.PlacesServiceStatus.OVER_QUERY_LIMIT: {\n reject(\n new OneBlinkAppsError(\n 'This application has gone over its Google Address querying quota. Please contact an administrator to rectify the issue or try again later.',\n ),\n )\n break\n }\n case google.maps.places.PlacesServiceStatus.INVALID_REQUEST: {\n reject(\n new OneBlinkAppsError(\n 'Google Maps API key may not have been configured correctly, the request to retrieve address suggestions is invalid. Please contact an administrator to rectify the issue.',\n ),\n )\n break\n }\n case google.maps.places.PlacesServiceStatus.REQUEST_DENIED: {\n reject(\n new OneBlinkAppsError(\n 'Google Maps API key has not been configured correctly. Please contact an administrator to rectify the issue.',\n ),\n )\n break\n }\n default: {\n reject(\n new OneBlinkAppsError(\n 'An unknown error has occurred. Please try again and contact support if the problem persists.',\n ),\n )\n }\n }\n },\n )\n }).catch((e) => {\n if (!abortSignal.aborted) {\n Sentry.captureException(e)\n }\n throw e\n })\n\n if (!abortSignal.aborted) {\n return predictions.reduce<Array<{ value: string; label: string }>>(\n (results, prediction) => {\n if (prediction.place_id) {\n results.push({\n value: prediction.place_id,\n label: prediction.description,\n })\n }\n return results\n },\n [],\n )\n }\n }\n throw new OneBlinkAppsError(\n 'An unknown error has occurred. Please contact support if the problem persists.',\n )\n },\n [autocompleteService],\n )\n\n const handleChange = React.useCallback(\n async (placeId: string | undefined) => {\n if (!placeId) {\n onChange(element, { value: undefined })\n return\n }\n\n setIsLoadingAddressDetails(true)\n try {\n //this should not happen, we can't get a place Id without google being present\n if (!isLoaded || !dummyMap) {\n throw new OneBlinkAppsError(\n 'An unknown error has occurred. Please contact support if the problem persists.',\n {\n originalError: new Error(\n 'Google Places library has not be initialised',\n ),\n },\n )\n }\n\n const placeService = new google.maps.places.PlacesService(dummyMap)\n const place = await new Promise<google.maps.places.PlaceResult>(\n (resolve, reject) => {\n placeService.getDetails(\n {\n placeId,\n fields: [\n 'place_id',\n 'formatted_address',\n 'geometry',\n 'address_components',\n ],\n },\n (place, status) => {\n if (\n status !== google.maps.places.PlacesServiceStatus.OK ||\n !place\n ) {\n reject(\n new OneBlinkAppsError(\n `Could not find address details for place with id: ${placeId}`,\n ),\n )\n return\n }\n resolve(place)\n },\n )\n },\n )\n onChange(element, {\n value: {\n place_id: place.place_id,\n formatted_address: place.formatted_address,\n address_components: place.address_components,\n geometry: {\n location: place.geometry?.location?.toJSON(),\n viewport: place.geometry?.viewport?.toJSON(),\n },\n },\n })\n } catch (newError) {\n if (isMounted.current) {\n setError(newError as Error)\n }\n }\n if (isMounted.current) {\n setIsLoadingAddressDetails(false)\n }\n },\n [isMounted, onChange, element, isLoaded, dummyMap],\n )\n\n // Ensure the label is set if the value is set outside of this component\n React.useEffect(() => {\n if (value) {\n const newLabel = value.formatted_address || value.place_id\n setLabel(newLabel ?? '')\n }\n }, [value])\n\n return (\n <div className=\"cypress-google-address-element\">\n <FormElementLabelContainer\n className=\"ob-google-address ob-autocomplete\"\n element={element}\n id={id}\n required={element.required}\n >\n <AutocompleteDropdown\n id={id}\n label={label}\n disabled={element.readOnly || isLoadingAddressDetails}\n placeholder={element.placeholderValue}\n required={element.required}\n value={value}\n validationMessage={validationMessage}\n displayValidationMessage={displayValidationMessage}\n onChangeValue={handleChange}\n isLoading={isLoadingAddressDetails}\n hasError={!!error}\n onChangeLabel={setLabel}\n searchDebounceMs={750}\n searchMinCharacters={4}\n onSearch={handleSearch}\n isDirty={isDirty}\n setIsDirty={setIsDirty}\n aria-describedby={ariaDescribedby}\n branding={\n <a className=\"dropdown-item cypress-powered-by-google ob-autocomplete__drop-down-item-powered-by-google\">\n powered by{' '}\n <img src=\"https://developers.google.com/static/maps/documentation/images/google_on_white.png\" />\n </a>\n }\n />\n </FormElementLabelContainer>\n\n {error && (\n <div role=\"alert\" className=\"has-margin-top-8\">\n <div className=\"has-text-danger ob-error__text cypress-google-address-details-error-message\">\n {error.message}\n </div>\n </div>\n )}\n </div>\n )\n}\n\nexport default React.memo(FormElementGoogleAddress)\n"]}
@@ -1,14 +1,15 @@
1
1
  import * as React from 'react';
2
2
  import { Sentry } from '@oneblink/apps';
3
3
  import clsx from 'clsx';
4
- import { GoogleMap, Marker, useJsApiLoader } from '@react-google-maps/api';
4
+ import { GoogleMap, Marker } from '@react-google-maps/api';
5
5
  import queryString from 'query-string';
6
6
  import useBooleanState from '../hooks/useBooleanState';
7
7
  import useIsOffline from '../hooks/useIsOffline';
8
8
  import * as geolocation from '../services/geolocation';
9
9
  import OnLoading from '../components/renderer/OnLoading';
10
10
  import defaultCoords from '../services/defaultCoordinates';
11
- import useGoogleMapsApiKeyKey from '../hooks/useGoogleMapsApiKey';
11
+ import useGoogle from '../hooks/useGoogle';
12
+ import useGoogleMapsApiKey from '../hooks/useGoogleMapsApiKey';
12
13
  import FormElementLabelContainer from '../components/renderer/FormElementLabelContainer';
13
14
  import { LookupNotificationContext } from '../hooks/useLookupNotification';
14
15
  import { useReverseGeocodeContext } from '../components/renderer/ReverseGeocode';
@@ -163,7 +164,7 @@ const LocationIsOffline = React.memo(function LocationIsOffline({ location, isOp
163
164
  return null;
164
165
  });
165
166
  const LocationImage = React.memo(function LocationImage({ location, }) {
166
- const googleMapsApiKey = useGoogleMapsApiKeyKey();
167
+ const googleMapsApiKey = useGoogleMapsApiKey();
167
168
  const staticUrl = React.useMemo(() => {
168
169
  const center = `${location.latitude},${location.longitude}`;
169
170
  const queries = {
@@ -179,10 +180,7 @@ const LocationImage = React.memo(function LocationImage({ location, }) {
179
180
  React.createElement("img", { className: "ob-location__map", alt: `map with center at ${location.latitude} latitude, ${location.longitude} longitude`, src: staticUrl, height: mapHeight, width: mapHeight })));
180
181
  });
181
182
  const LocationPicker = React.memo(function LocationPicker({ location, onChange, }) {
182
- const googleMapsApiKey = useGoogleMapsApiKeyKey();
183
- const { isLoaded } = useJsApiLoader({
184
- googleMapsApiKey: googleMapsApiKey !== null && googleMapsApiKey !== void 0 ? googleMapsApiKey : '',
185
- });
183
+ const { isLoaded } = useGoogle();
186
184
  return (React.createElement("figure", { className: "ob-figure" }, isLoaded && (React.createElement(GoogleLocationPicker, { location: location, onChange: onChange }))));
187
185
  });
188
186
  const GoogleLocationPicker = React.memo(function GoogleLocationPicker({ location, onChange, }) {
@@ -1 +1 @@
1
- {"version":3,"file":"FormElementLocation.js","sourceRoot":"","sources":["../../src/form-elements/FormElementLocation.tsx"],"names":[],"mappings":"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","sourcesContent":["import * as React from 'react'\nimport { FormTypes } from '@oneblink/types'\nimport { Sentry } from '@oneblink/apps'\nimport clsx from 'clsx'\nimport { GoogleMap, Marker, useJsApiLoader } from '@react-google-maps/api'\nimport queryString from 'query-string'\n\nimport useBooleanState from '../hooks/useBooleanState'\nimport useIsOffline from '../hooks/useIsOffline'\nimport * as geolocation from '../services/geolocation'\nimport OnLoading from '../components/renderer/OnLoading'\nimport defaultCoords from '../services/defaultCoordinates'\nimport useGoogleMapsApiKeyKey from '../hooks/useGoogleMapsApiKey'\nimport FormElementLabelContainer from '../components/renderer/FormElementLabelContainer'\nimport { FormElementValueChangeHandler, IsDirtyProps } from '../types/form'\nimport { LookupNotificationContext } from '../hooks/useLookupNotification'\nimport { useReverseGeocodeContext } from '../components/renderer/ReverseGeocode'\n\ntype Props = {\n id: string\n element: FormTypes.LocationElement\n value: unknown | undefined\n onChange: FormElementValueChangeHandler<Coords>\n displayValidationMessage: boolean\n validationMessage: string | undefined\n} & IsDirtyProps\n\ntype Coords = {\n latitude: number\n longitude: number\n zoom?: number\n}\n\nexport const stringifyLocation = (location: Coords | undefined) => {\n if (location) {\n return `${location.latitude},${location.longitude}`\n }\n}\n\nexport function parseLocationValue(value: unknown): Coords | undefined {\n if (!value || typeof value !== 'object') {\n return\n }\n\n const { latitude, longitude, zoom } = value as Record<string, unknown>\n if (typeof latitude !== 'number' || typeof longitude !== 'number') {\n return\n }\n\n return {\n latitude,\n longitude,\n zoom: typeof zoom === 'number' ? zoom : initialMapZoom,\n }\n}\n\nconst mapHeight = 300\nconst initialMapZoom = 15\nconst apiUrl = 'https://maps.googleapis.com/maps/api/staticmap'\n\nfunction FormElementLocation({\n id,\n element,\n value,\n onChange,\n validationMessage,\n displayValidationMessage,\n isDirty,\n setIsDirty,\n}: Props) {\n const [isLocationPickerOpen, showLocationPicker, hideLocationPicker] =\n useBooleanState(false)\n\n const [location, setLocation] = React.useState<Coords | undefined>(undefined)\n const onClear = React.useCallback(() => {\n hideLocationPicker()\n onChange(element, {\n value: undefined,\n })\n setLocation(undefined)\n }, [element, hideLocationPicker, onChange])\n\n const onCancel = React.useCallback(() => {\n hideLocationPicker()\n setLocation(parseLocationValue(value))\n }, [hideLocationPicker, value])\n\n const onLocate = React.useCallback(async () => {\n showLocationPicker()\n\n if (location) {\n return\n }\n\n let currentLocation = null\n try {\n const result = await geolocation.getCurrentPosition()\n currentLocation = result.coords\n } catch (err) {\n console.error(\n 'Error while attempting to find the users current location',\n err,\n )\n Sentry.captureException(err)\n } finally {\n setLocation(parseLocationValue(currentLocation || defaultCoords()))\n }\n }, [location, showLocationPicker])\n\n const isLoadingLocation = !location && isLocationPickerOpen\n\n const onConfirm = React.useCallback(() => {\n setIsDirty()\n hideLocationPicker()\n onChange(element, {\n value: location,\n })\n }, [element, hideLocationPicker, location, onChange, setIsDirty])\n\n // SET DEFAULT/PREFILL DATA\n React.useEffect(() => {\n const newValue = parseLocationValue(value)\n if (newValue) {\n setLocation(newValue)\n }\n }, [value])\n\n const { isLookingUp } = React.useContext(LookupNotificationContext)\n const isDisplayingValidationMessage =\n (isDirty || displayValidationMessage) && !!validationMessage && !isLookingUp\n\n const { isReverseGeocoding, reverseGeocodingErrorMsg } =\n useReverseGeocodeContext()\n\n return (\n <div className=\"cypress-location-element\">\n <FormElementLabelContainer\n className=\"ob-location\"\n id={id}\n element={element}\n required={element.required}\n >\n <div className=\"control\">\n <LocationDisplay\n isOpen={isLocationPickerOpen}\n isLoading={isLoadingLocation}\n location={location}\n onChange={setLocation}\n />\n\n <div className=\"buttons ob-buttons ob-location__buttons\">\n {isLocationPickerOpen || isReverseGeocoding ? (\n <>\n <button\n type=\"button\"\n className=\"is-light button ob-button ob-button__cancel ob-location__button ob-location__button-cancel cypress-cancel-location-button\"\n onClick={onCancel}\n disabled={element.readOnly || isReverseGeocoding}\n >\n Cancel\n </button>\n <button\n type=\"button\"\n className={clsx(\n 'is-primary button ob-button ob-button__confirm ob-location__button ob-location__button-confirm cypress-confirm-location-button',\n {\n 'is-loading': isReverseGeocoding,\n },\n )}\n onClick={onConfirm}\n disabled={element.readOnly || !location || isReverseGeocoding}\n >\n Confirm\n </button>\n </>\n ) : (\n <>\n <button\n type=\"button\"\n className=\"is-light button ob-button ob-button__clear ob-button-clear ob-location__button ob-location__button-clear cypress-clear-location-button\"\n onClick={onClear}\n disabled={element.readOnly}\n >\n Clear\n </button>\n <button\n type=\"button\"\n className=\"is-primary button ob-button ob-button__edit ob-location__button ob-location__button-edit cypress-locate-button\"\n onClick={onLocate}\n disabled={element.readOnly}\n >\n Locate\n </button>\n </>\n )}\n </div>\n </div>\n\n {isDisplayingValidationMessage && (\n <div role=\"alert\" className=\"has-margin-top-8\">\n <div className=\"has-text-danger ob-error__text cypress-validation-message\">\n {validationMessage}\n </div>\n </div>\n )}\n {reverseGeocodingErrorMsg && (\n <div role=\"alert\" className=\"has-margin-top-8\">\n <div className=\"has-text-danger ob-error__text cypress-validation-message\">\n {reverseGeocodingErrorMsg}\n </div>\n </div>\n )}\n </FormElementLabelContainer>\n </div>\n )\n}\n\nconst LocationDisplay = React.memo(function LocationDisplay({\n isLoading,\n isOpen,\n location,\n onChange,\n}: {\n isLoading: boolean\n isOpen: boolean\n location: Coords | undefined\n onChange: (location: Coords) => void\n}) {\n const isOffline = useIsOffline()\n\n if (isLoading) {\n return (\n <figure className=\"ob-figure\">\n <div className=\"figure-content\">\n <OnLoading small></OnLoading>\n </div>\n </figure>\n )\n }\n\n if (isOffline) {\n return <LocationIsOffline location={location} isOpen={isOpen} />\n }\n\n if (isOpen) {\n if (!location) {\n // There is no location to display while user is attempting to pick a location.\n // This should never happen, if loading has finished a default should be set.\n // Fail fast!!!\n // https://en.wikipedia.org/wiki/Fail-fast\n throw new Error(\n 'Default location was not set for \"location\" form element',\n )\n }\n\n return <LocationPicker location={location} onChange={onChange} />\n }\n\n if (location) {\n return <LocationImage location={location} />\n }\n\n return null\n})\n\nfunction LocationIsOfflineFigureContent({\n children,\n}: {\n children: React.ReactNode\n}) {\n return (\n <figure className=\"ob-figure\">\n <div className=\"figure-content has-text-centered\">\n <h4 className=\"title is-4\">You are currently offline</h4>\n {children}\n </div>\n </figure>\n )\n}\n\nconst LocationIsOffline = React.memo(function LocationIsOffline({\n location,\n isOpen,\n}: {\n location: Coords | undefined\n isOpen: boolean\n}) {\n if (isOpen) {\n if (location) {\n // If user is offline and attempting to pick a location and there is one set already\n return (\n <LocationIsOfflineFigureContent>\n <p>\n Click the <b>Confirm</b> button below to set the location to your\n current position.\n </p>\n </LocationIsOfflineFigureContent>\n )\n }\n\n // If user is offline and attempting to pick a location and there is one nothing set yet\n return (\n <LocationIsOfflineFigureContent>\n <p>\n We could not find your current location. Click the <b>Cancel</b>{' '}\n button below to try again.\n </p>\n </LocationIsOfflineFigureContent>\n )\n }\n\n // If user is offline and has confirmed a location\n if (location) {\n return (\n <LocationIsOfflineFigureContent>\n <h3 className=\"title is-3 ob-location__latitude\">Latitude</h3>\n <p>\n <b>{location.latitude}</b>\n </p>\n <h3 className=\"title is-3 ob-location__longitude\">Longitude</h3>\n <p>\n <b>{location.longitude}</b>\n </p>\n </LocationIsOfflineFigureContent>\n )\n }\n\n // User is offline with no location set and not attempting to pick a location\n return null\n})\n\nconst LocationImage = React.memo(function LocationImage({\n location,\n}: {\n location: Coords\n}) {\n const googleMapsApiKey = useGoogleMapsApiKeyKey()\n\n const staticUrl = React.useMemo(() => {\n const center = `${location.latitude},${location.longitude}`\n const queries = {\n key: googleMapsApiKey,\n size: `${mapHeight}x${mapHeight}`,\n zoom: location.zoom,\n center,\n markers: `color:red|${center}`,\n }\n return `${apiUrl}?${queryString.stringify(queries)}`\n }, [googleMapsApiKey, location])\n\n return (\n <figure className=\"ob-figure\">\n <img\n className=\"ob-location__map\"\n alt={`map with center at ${location.latitude} latitude, ${location.longitude} longitude`}\n src={staticUrl}\n height={mapHeight}\n width={mapHeight}\n />\n </figure>\n )\n})\n\nconst LocationPicker = React.memo(function LocationPicker({\n location,\n onChange,\n}: {\n location: Coords\n onChange: (newLocation: Coords) => void\n}) {\n const googleMapsApiKey = useGoogleMapsApiKeyKey()\n\n const { isLoaded } = useJsApiLoader({\n googleMapsApiKey: googleMapsApiKey ?? '',\n })\n\n return (\n <figure className=\"ob-figure\">\n {isLoaded && (\n <GoogleLocationPicker location={location} onChange={onChange} />\n )}\n </figure>\n )\n})\n\nconst GoogleLocationPicker = React.memo(function GoogleLocationPicker({\n location,\n onChange,\n}: {\n location: Coords\n onChange: (newLocation: Coords) => void\n}) {\n const [map, setMap] = React.useState<google.maps.Map | null>(null)\n const [marker, setMarker] = React.useState<google.maps.Marker | null>(null)\n\n const originalCenter = React.useRef<{ lat: number; lng: number }>({\n lat: location.latitude,\n lng: location.longitude,\n })\n\n const markerAnimation = React.useMemo(() => google.maps.Animation.DROP, [])\n\n const onZoomChanged = React.useCallback(() => {\n if (!map) {\n return\n }\n\n onChange({\n latitude: location.latitude,\n longitude: location.longitude,\n zoom: map.getZoom(),\n })\n }, [location.latitude, location.longitude, map, onChange])\n\n const handleDragEnd = React.useCallback(\n (e: google.maps.MapMouseEvent) => {\n if (!e.latLng) {\n return\n }\n const { lat, lng } = e.latLng.toJSON()\n onChange({\n latitude: lat,\n longitude: lng,\n zoom: location.zoom,\n })\n if (map) {\n map.panTo(e.latLng)\n }\n },\n [location.zoom, map, onChange],\n )\n\n const handleClick = React.useCallback(\n (e: google.maps.MapMouseEvent) => {\n handleDragEnd(e)\n\n if (!e.latLng || !marker) {\n return\n }\n\n marker.setPosition(e.latLng)\n // this enables the marker to animate after moving it\n marker.setMap(null)\n marker.setAnimation(markerAnimation)\n marker.setMap(map)\n },\n [handleDragEnd, map, marker, markerAnimation],\n )\n\n return (\n <GoogleMap\n onLoad={(map) => setMap(map)}\n onUnmount={() => setMap(null)}\n mapContainerStyle={{\n height: 300,\n }}\n center={originalCenter.current}\n zoom={location.zoom}\n onZoomChanged={onZoomChanged}\n onClick={handleClick}\n options={{ draggableCursor: 'pointer' }}\n >\n <Marker\n onLoad={(marker) => setMarker(marker)}\n onUnmount={() => setMarker(null)}\n animation={markerAnimation}\n position={originalCenter.current}\n draggable\n onDragEnd={handleDragEnd}\n ></Marker>\n </GoogleMap>\n )\n})\n\nexport default React.memo(FormElementLocation)\n"]}
1
+ {"version":3,"file":"FormElementLocation.js","sourceRoot":"","sources":["../../src/form-elements/FormElementLocation.tsx"],"names":[],"mappings":"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","sourcesContent":["import * as React from 'react'\nimport { FormTypes } from '@oneblink/types'\nimport { Sentry } from '@oneblink/apps'\nimport clsx from 'clsx'\nimport { GoogleMap, Marker } from '@react-google-maps/api'\nimport queryString from 'query-string'\n\nimport useBooleanState from '../hooks/useBooleanState'\nimport useIsOffline from '../hooks/useIsOffline'\nimport * as geolocation from '../services/geolocation'\nimport OnLoading from '../components/renderer/OnLoading'\nimport defaultCoords from '../services/defaultCoordinates'\nimport useGoogle from '../hooks/useGoogle'\nimport useGoogleMapsApiKey from '../hooks/useGoogleMapsApiKey'\nimport FormElementLabelContainer from '../components/renderer/FormElementLabelContainer'\nimport { FormElementValueChangeHandler, IsDirtyProps } from '../types/form'\nimport { LookupNotificationContext } from '../hooks/useLookupNotification'\nimport { useReverseGeocodeContext } from '../components/renderer/ReverseGeocode'\n\ntype Props = {\n id: string\n element: FormTypes.LocationElement\n value: unknown | undefined\n onChange: FormElementValueChangeHandler<Coords>\n displayValidationMessage: boolean\n validationMessage: string | undefined\n} & IsDirtyProps\n\ntype Coords = {\n latitude: number\n longitude: number\n zoom?: number\n}\n\nexport const stringifyLocation = (location: Coords | undefined) => {\n if (location) {\n return `${location.latitude},${location.longitude}`\n }\n}\n\nexport function parseLocationValue(value: unknown): Coords | undefined {\n if (!value || typeof value !== 'object') {\n return\n }\n\n const { latitude, longitude, zoom } = value as Record<string, unknown>\n if (typeof latitude !== 'number' || typeof longitude !== 'number') {\n return\n }\n\n return {\n latitude,\n longitude,\n zoom: typeof zoom === 'number' ? zoom : initialMapZoom,\n }\n}\n\nconst mapHeight = 300\nconst initialMapZoom = 15\nconst apiUrl = 'https://maps.googleapis.com/maps/api/staticmap'\n\nfunction FormElementLocation({\n id,\n element,\n value,\n onChange,\n validationMessage,\n displayValidationMessage,\n isDirty,\n setIsDirty,\n}: Props) {\n const [isLocationPickerOpen, showLocationPicker, hideLocationPicker] =\n useBooleanState(false)\n\n const [location, setLocation] = React.useState<Coords | undefined>(undefined)\n const onClear = React.useCallback(() => {\n hideLocationPicker()\n onChange(element, {\n value: undefined,\n })\n setLocation(undefined)\n }, [element, hideLocationPicker, onChange])\n\n const onCancel = React.useCallback(() => {\n hideLocationPicker()\n setLocation(parseLocationValue(value))\n }, [hideLocationPicker, value])\n\n const onLocate = React.useCallback(async () => {\n showLocationPicker()\n\n if (location) {\n return\n }\n\n let currentLocation = null\n try {\n const result = await geolocation.getCurrentPosition()\n currentLocation = result.coords\n } catch (err) {\n console.error(\n 'Error while attempting to find the users current location',\n err,\n )\n Sentry.captureException(err)\n } finally {\n setLocation(parseLocationValue(currentLocation || defaultCoords()))\n }\n }, [location, showLocationPicker])\n\n const isLoadingLocation = !location && isLocationPickerOpen\n\n const onConfirm = React.useCallback(() => {\n setIsDirty()\n hideLocationPicker()\n onChange(element, {\n value: location,\n })\n }, [element, hideLocationPicker, location, onChange, setIsDirty])\n\n // SET DEFAULT/PREFILL DATA\n React.useEffect(() => {\n const newValue = parseLocationValue(value)\n if (newValue) {\n setLocation(newValue)\n }\n }, [value])\n\n const { isLookingUp } = React.useContext(LookupNotificationContext)\n const isDisplayingValidationMessage =\n (isDirty || displayValidationMessage) && !!validationMessage && !isLookingUp\n\n const { isReverseGeocoding, reverseGeocodingErrorMsg } =\n useReverseGeocodeContext()\n\n return (\n <div className=\"cypress-location-element\">\n <FormElementLabelContainer\n className=\"ob-location\"\n id={id}\n element={element}\n required={element.required}\n >\n <div className=\"control\">\n <LocationDisplay\n isOpen={isLocationPickerOpen}\n isLoading={isLoadingLocation}\n location={location}\n onChange={setLocation}\n />\n\n <div className=\"buttons ob-buttons ob-location__buttons\">\n {isLocationPickerOpen || isReverseGeocoding ? (\n <>\n <button\n type=\"button\"\n className=\"is-light button ob-button ob-button__cancel ob-location__button ob-location__button-cancel cypress-cancel-location-button\"\n onClick={onCancel}\n disabled={element.readOnly || isReverseGeocoding}\n >\n Cancel\n </button>\n <button\n type=\"button\"\n className={clsx(\n 'is-primary button ob-button ob-button__confirm ob-location__button ob-location__button-confirm cypress-confirm-location-button',\n {\n 'is-loading': isReverseGeocoding,\n },\n )}\n onClick={onConfirm}\n disabled={element.readOnly || !location || isReverseGeocoding}\n >\n Confirm\n </button>\n </>\n ) : (\n <>\n <button\n type=\"button\"\n className=\"is-light button ob-button ob-button__clear ob-button-clear ob-location__button ob-location__button-clear cypress-clear-location-button\"\n onClick={onClear}\n disabled={element.readOnly}\n >\n Clear\n </button>\n <button\n type=\"button\"\n className=\"is-primary button ob-button ob-button__edit ob-location__button ob-location__button-edit cypress-locate-button\"\n onClick={onLocate}\n disabled={element.readOnly}\n >\n Locate\n </button>\n </>\n )}\n </div>\n </div>\n\n {isDisplayingValidationMessage && (\n <div role=\"alert\" className=\"has-margin-top-8\">\n <div className=\"has-text-danger ob-error__text cypress-validation-message\">\n {validationMessage}\n </div>\n </div>\n )}\n {reverseGeocodingErrorMsg && (\n <div role=\"alert\" className=\"has-margin-top-8\">\n <div className=\"has-text-danger ob-error__text cypress-validation-message\">\n {reverseGeocodingErrorMsg}\n </div>\n </div>\n )}\n </FormElementLabelContainer>\n </div>\n )\n}\n\nconst LocationDisplay = React.memo(function LocationDisplay({\n isLoading,\n isOpen,\n location,\n onChange,\n}: {\n isLoading: boolean\n isOpen: boolean\n location: Coords | undefined\n onChange: (location: Coords) => void\n}) {\n const isOffline = useIsOffline()\n\n if (isLoading) {\n return (\n <figure className=\"ob-figure\">\n <div className=\"figure-content\">\n <OnLoading small></OnLoading>\n </div>\n </figure>\n )\n }\n\n if (isOffline) {\n return <LocationIsOffline location={location} isOpen={isOpen} />\n }\n\n if (isOpen) {\n if (!location) {\n // There is no location to display while user is attempting to pick a location.\n // This should never happen, if loading has finished a default should be set.\n // Fail fast!!!\n // https://en.wikipedia.org/wiki/Fail-fast\n throw new Error(\n 'Default location was not set for \"location\" form element',\n )\n }\n\n return <LocationPicker location={location} onChange={onChange} />\n }\n\n if (location) {\n return <LocationImage location={location} />\n }\n\n return null\n})\n\nfunction LocationIsOfflineFigureContent({\n children,\n}: {\n children: React.ReactNode\n}) {\n return (\n <figure className=\"ob-figure\">\n <div className=\"figure-content has-text-centered\">\n <h4 className=\"title is-4\">You are currently offline</h4>\n {children}\n </div>\n </figure>\n )\n}\n\nconst LocationIsOffline = React.memo(function LocationIsOffline({\n location,\n isOpen,\n}: {\n location: Coords | undefined\n isOpen: boolean\n}) {\n if (isOpen) {\n if (location) {\n // If user is offline and attempting to pick a location and there is one set already\n return (\n <LocationIsOfflineFigureContent>\n <p>\n Click the <b>Confirm</b> button below to set the location to your\n current position.\n </p>\n </LocationIsOfflineFigureContent>\n )\n }\n\n // If user is offline and attempting to pick a location and there is one nothing set yet\n return (\n <LocationIsOfflineFigureContent>\n <p>\n We could not find your current location. Click the <b>Cancel</b>{' '}\n button below to try again.\n </p>\n </LocationIsOfflineFigureContent>\n )\n }\n\n // If user is offline and has confirmed a location\n if (location) {\n return (\n <LocationIsOfflineFigureContent>\n <h3 className=\"title is-3 ob-location__latitude\">Latitude</h3>\n <p>\n <b>{location.latitude}</b>\n </p>\n <h3 className=\"title is-3 ob-location__longitude\">Longitude</h3>\n <p>\n <b>{location.longitude}</b>\n </p>\n </LocationIsOfflineFigureContent>\n )\n }\n\n // User is offline with no location set and not attempting to pick a location\n return null\n})\n\nconst LocationImage = React.memo(function LocationImage({\n location,\n}: {\n location: Coords\n}) {\n const googleMapsApiKey = useGoogleMapsApiKey()\n\n const staticUrl = React.useMemo(() => {\n const center = `${location.latitude},${location.longitude}`\n const queries = {\n key: googleMapsApiKey,\n size: `${mapHeight}x${mapHeight}`,\n zoom: location.zoom,\n center,\n markers: `color:red|${center}`,\n }\n return `${apiUrl}?${queryString.stringify(queries)}`\n }, [googleMapsApiKey, location])\n\n return (\n <figure className=\"ob-figure\">\n <img\n className=\"ob-location__map\"\n alt={`map with center at ${location.latitude} latitude, ${location.longitude} longitude`}\n src={staticUrl}\n height={mapHeight}\n width={mapHeight}\n />\n </figure>\n )\n})\n\nconst LocationPicker = React.memo(function LocationPicker({\n location,\n onChange,\n}: {\n location: Coords\n onChange: (newLocation: Coords) => void\n}) {\n const { isLoaded } = useGoogle()\n\n return (\n <figure className=\"ob-figure\">\n {isLoaded && (\n <GoogleLocationPicker location={location} onChange={onChange} />\n )}\n </figure>\n )\n})\n\nconst GoogleLocationPicker = React.memo(function GoogleLocationPicker({\n location,\n onChange,\n}: {\n location: Coords\n onChange: (newLocation: Coords) => void\n}) {\n const [map, setMap] = React.useState<google.maps.Map | null>(null)\n const [marker, setMarker] = React.useState<google.maps.Marker | null>(null)\n\n const originalCenter = React.useRef<{ lat: number; lng: number }>({\n lat: location.latitude,\n lng: location.longitude,\n })\n\n const markerAnimation = React.useMemo(() => google.maps.Animation.DROP, [])\n\n const onZoomChanged = React.useCallback(() => {\n if (!map) {\n return\n }\n\n onChange({\n latitude: location.latitude,\n longitude: location.longitude,\n zoom: map.getZoom(),\n })\n }, [location.latitude, location.longitude, map, onChange])\n\n const handleDragEnd = React.useCallback(\n (e: google.maps.MapMouseEvent) => {\n if (!e.latLng) {\n return\n }\n const { lat, lng } = e.latLng.toJSON()\n onChange({\n latitude: lat,\n longitude: lng,\n zoom: location.zoom,\n })\n if (map) {\n map.panTo(e.latLng)\n }\n },\n [location.zoom, map, onChange],\n )\n\n const handleClick = React.useCallback(\n (e: google.maps.MapMouseEvent) => {\n handleDragEnd(e)\n\n if (!e.latLng || !marker) {\n return\n }\n\n marker.setPosition(e.latLng)\n // this enables the marker to animate after moving it\n marker.setMap(null)\n marker.setAnimation(markerAnimation)\n marker.setMap(map)\n },\n [handleDragEnd, map, marker, markerAnimation],\n )\n\n return (\n <GoogleMap\n onLoad={(map) => setMap(map)}\n onUnmount={() => setMap(null)}\n mapContainerStyle={{\n height: 300,\n }}\n center={originalCenter.current}\n zoom={location.zoom}\n onZoomChanged={onZoomChanged}\n onClick={handleClick}\n options={{ draggableCursor: 'pointer' }}\n >\n <Marker\n onLoad={(marker) => setMarker(marker)}\n onUnmount={() => setMarker(null)}\n animation={markerAnimation}\n position={originalCenter.current}\n draggable\n onDragEnd={handleDragEnd}\n ></Marker>\n </GoogleMap>\n )\n})\n\nexport default React.memo(FormElementLocation)\n"]}
@@ -60,6 +60,7 @@ function FormElementPointAddress({ formId, id, element, value, displayValidation
60
60
  setLabel(newLabel || '');
61
61
  }
62
62
  }
63
+ // we don't need this to run again when the label changes
63
64
  // eslint-disable-next-line react-hooks/exhaustive-deps
64
65
  }, [value]);
65
66
  return (React.createElement("div", { className: "cypress-point-address-element" },