From 94d2fb313b8285aa336f13d8c5e8a6a2ac72c6ea Mon Sep 17 00:00:00 2001 From: Ashley Teo Date: Mon, 11 May 2026 09:59:54 +0800 Subject: [PATCH] [MOL-20692][AT] introduce recaptcha ready props to indicate the availability of recaptcha if any --- .../location-search/location-search.tsx | 20 ++++++++++++------- .../recaptcha/recaptcha-hook.tsx | 3 ++- .../recaptcha/recaptcha-provider.tsx | 6 +++++- src/context-providers/recaptcha/types.ts | 1 + 4 files changed, 21 insertions(+), 9 deletions(-) diff --git a/src/components/fields/location-field/location-modal/location-search/location-search.tsx b/src/components/fields/location-field/location-modal/location-search/location-search.tsx index d4519c00c..35285e1f4 100644 --- a/src/components/fields/location-field/location-modal/location-search/location-search.tsx +++ b/src/components/fields/location-field/location-modal/location-search/location-search.tsx @@ -82,7 +82,7 @@ export const LocationSearch = ({ // CONST, STATE, REFS // ============================================================================= const { addFieldEventListener, removeFieldEventListener, dispatchFieldEvent } = useFieldEvent(); - const { getToken } = useRecaptcha(); + const { isRecaptchaReady, getToken } = useRecaptcha(); const reverseGeocodeUrl = mapApi?.reverseGeocode; const convertLatLngToXYUrl = mapApi?.convertLatLngToXY; const searchUrl = mapApi?.search; @@ -130,7 +130,7 @@ export const LocationSearch = ({ // ============================================================================= // check if any of the services is working useEffect(() => { - if (!showLocationModal) return; + if (!showLocationModal || !isRecaptchaReady) return; // check if one map or reverse code is working // - get location error // - first load @@ -155,7 +155,7 @@ export const LocationSearch = ({ debounceFetchAddress("singapore", 1, undefined, handleApiErrors, searchUrl, getToken, mapApiHeaders), reverseGeoCodeCheck(), ]); - }, []); + }, [isRecaptchaReady]); useEffect(() => { if (!navigator.onLine) return; @@ -199,6 +199,8 @@ export const LocationSearch = ({ * Prefill based on lat lng or address with the appropriate api */ useEffect(() => { + if (!isRecaptchaReady) return; + const handleResult = ({ displayAddressText, ...locationFieldValue }: IResultListItem) => { const validPostalCode = !mustHavePostalCode || LocationHelper.hasGotAddressValue(locationFieldValue.postalCode); @@ -267,7 +269,7 @@ export const LocationSearch = ({ mapApiHeaders ); } - }, []); + }, [isRecaptchaReady]); /** * Gets the address of the location with lat lng when user clicks on the map @@ -281,7 +283,7 @@ export const LocationSearch = ({ * Handles query searching and search results display */ useEffect(() => { - if (resultState === "found") return; + if (resultState === "found" || !isRecaptchaReady) return; const parsedString = validateQueryString(queryString); if (!parsedString) return resetResultsList(); @@ -332,7 +334,7 @@ export const LocationSearch = ({ getToken, mapApiHeaders ); - }, [PAGE_SIZE, queryString]); + }, [PAGE_SIZE, queryString, isRecaptchaReady]); // Determine if there are more items to be fetched useEffect(() => { @@ -460,6 +462,10 @@ export const LocationSearch = ({ * all the data will be fetched */ const getMoreLocationResults = () => { + if (!isRecaptchaReady) { + return; + } + setLoading(true); if (searchBuildingResults.length < apiResults.length) { @@ -505,7 +511,7 @@ export const LocationSearch = ({ * - map picked latlng */ const displayResultsFromLatLng = async (addressLat: number, addressLng: number) => { - if (!reverseGeocodeUrl) return; + if (!isRecaptchaReady || !reverseGeocodeUrl) return; const onError = (error: any) => { setQueryString(""); handleApiErrors(error); diff --git a/src/context-providers/recaptcha/recaptcha-hook.tsx b/src/context-providers/recaptcha/recaptcha-hook.tsx index 6e7cfaee1..36bc2d6d1 100644 --- a/src/context-providers/recaptcha/recaptcha-hook.tsx +++ b/src/context-providers/recaptcha/recaptcha-hook.tsx @@ -2,9 +2,10 @@ import { useContext } from "react"; import { RecaptchaContext } from "./recaptcha-provider"; export const useRecaptcha = () => { - const { recaptchaState, getToken } = useContext(RecaptchaContext); + const { recaptchaState, isRecaptchaReady, getToken } = useContext(RecaptchaContext); return { loaded: recaptchaState.loaded, + isRecaptchaReady, getToken, }; }; diff --git a/src/context-providers/recaptcha/recaptcha-provider.tsx b/src/context-providers/recaptcha/recaptcha-provider.tsx index 64967e1de..324a02125 100644 --- a/src/context-providers/recaptcha/recaptcha-provider.tsx +++ b/src/context-providers/recaptcha/recaptcha-provider.tsx @@ -11,6 +11,7 @@ const DEFAULT_STATE: IRecaptchaState = { const DEFAULT_CONTEXT_VALUES: IRecaptchaContext = { dispatch: () => undefined, recaptchaState: DEFAULT_STATE, + isRecaptchaReady: false, getToken: async () => undefined, }; @@ -42,6 +43,7 @@ interface IRecaptchaProviderProps { // ============================================================================= export const RecaptchaProvider = ({ children, recaptchaSiteKey }: IRecaptchaProviderProps) => { const [recaptchaState, dispatch] = useReducer(recaptchaStateReducer, DEFAULT_STATE); + const isRecaptchaReady = !recaptchaSiteKey || recaptchaState.loaded; // ========================================================================= // EFFECTS // ========================================================================= @@ -103,6 +105,8 @@ export const RecaptchaProvider = ({ children, recaptchaSiteKey }: IRecaptchaProv // RENDER // ============================================================================= return ( - {children} + + {children} + ); }; diff --git a/src/context-providers/recaptcha/types.ts b/src/context-providers/recaptcha/types.ts index b50e3471f..a868a6bf9 100644 --- a/src/context-providers/recaptcha/types.ts +++ b/src/context-providers/recaptcha/types.ts @@ -9,6 +9,7 @@ export interface IRecaptchaState { export interface IRecaptchaContext { recaptchaState: IRecaptchaState; + isRecaptchaReady: boolean; dispatch: Dispatch; getToken: (action?: string) => Promise; }