From c5eba2a12b3bc0a68c721d6c489e68ad4d8c227f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ant=C3=B3nio=20Ferreira?= Date: Mon, 28 Oct 2024 18:23:44 +0100 Subject: [PATCH] Fix address lookup reseting state after country (#2926) * fixes address lookup reseting state after country * changeset --- .changeset/cold-jeans-yawn.md | 5 ++++ .../components/internal/Address/Address.tsx | 24 ++++++++++++++----- packages/lib/src/utils/useForm/reducer.ts | 5 +++- packages/lib/src/utils/useForm/types.ts | 1 + packages/lib/src/utils/useForm/useForm.ts | 2 ++ 5 files changed, 30 insertions(+), 7 deletions(-) create mode 100644 .changeset/cold-jeans-yawn.md diff --git a/.changeset/cold-jeans-yawn.md b/.changeset/cold-jeans-yawn.md new file mode 100644 index 0000000000..0aabaac2fa --- /dev/null +++ b/.changeset/cold-jeans-yawn.md @@ -0,0 +1,5 @@ +--- +"@adyen/adyen-web": patch +--- + +Fix address lookup reseting state field after country change diff --git a/packages/lib/src/components/internal/Address/Address.tsx b/packages/lib/src/components/internal/Address/Address.tsx index 88294b480f..fbf571329d 100644 --- a/packages/lib/src/components/internal/Address/Address.tsx +++ b/packages/lib/src/components/internal/Address/Address.tsx @@ -39,9 +39,11 @@ export default function Address(props: AddressProps) { const showAddressSearch = !!props.onAddressLookup; + const [ignoreCountryChange, setIgnoreCountryChange] = useState(false); + const showAddressFields = props.onAddressLookup ? hasSelectedAddress || useManualAddress : true; - const { data, errors, valid, isValid, handleChangeFor, triggerValidation, setData } = useForm({ + const { data, errors, valid, isValid, handleChangeFor, triggerValidation, setData, mergeData } = useForm({ schema: requiredFieldsSchema, defaultData: props.data, // Ensure any passed validation rules are merged with the default ones @@ -52,13 +54,17 @@ export default function Address(props: AddressProps) { const setSearchData = useCallback( (selectedAddress: AddressData) => { const propsKeysToProcess = ADDRESS_SCHEMA; - propsKeysToProcess.forEach(propKey => { + const newStateData = propsKeysToProcess.reduce((acc: AddressData, propKey) => { // Make sure the data provided by the merchant is always strings const providedValue = selectedAddress[propKey]; - if (providedValue === null || providedValue === undefined) return; - // Cast everything to string - setData(propKey, String(providedValue)); - }); + if (providedValue !== null && providedValue !== undefined) { + // Cast everything to string + acc[propKey] = String(providedValue); + } + return acc; + }, {}); + mergeData(newStateData); + setIgnoreCountryChange(true); triggerValidation(); setHasSelectedAddress(true); }, @@ -93,6 +99,12 @@ export default function Address(props: AddressProps) { * - Applies validation on postalCode field in case it has any value */ useEffect((): void => { + // if the country was set via setSearchData we don't want to trigger this + if (ignoreCountryChange) { + setIgnoreCountryChange(false); + return; + } + const stateOrProvince = specifications.countryHasDataset(data.country) ? '' : FALLBACK_VALUE; const newData = { ...data, stateOrProvince }; diff --git a/packages/lib/src/utils/useForm/reducer.ts b/packages/lib/src/utils/useForm/reducer.ts index 108e37efc2..e1eca0b18f 100644 --- a/packages/lib/src/utils/useForm/reducer.ts +++ b/packages/lib/src/utils/useForm/reducer.ts @@ -54,13 +54,16 @@ export function init({ schema, defaultData, processField, fieldProblems }) { } export function getReducer(processField) { - return function reducer(state, { type, key, value, mode, schema, defaultData, formValue, selectedSchema, fieldProblems }: any) { + return function reducer(state, { type, key, value, mode, schema, defaultData, formValue, selectedSchema, fieldProblems, data }) { const validationSchema: string[] = selectedSchema || state.schema; switch (type) { case 'setData': { return { ...state, data: { ...state['data'], [key]: value } }; } + case 'mergeData': { + return { ...state, data: { ...state['data'], ...data } }; + } case 'setValid': { return { ...state, valid: { ...state['valid'], [key]: value } }; } diff --git a/packages/lib/src/utils/useForm/types.ts b/packages/lib/src/utils/useForm/types.ts index 9f8fae2fb8..69c879146b 100644 --- a/packages/lib/src/utils/useForm/types.ts +++ b/packages/lib/src/utils/useForm/types.ts @@ -35,6 +35,7 @@ export interface Form extends FormState { triggerValidation: (schema?: any) => void; setSchema: (schema: any) => void; setData: (key: string, value: any) => void; + mergeData: (data: FormSchema) => void; setValid: (key: string, value: any) => void; setErrors: (key: string, value: any) => void; mergeForm: (formValue: any) => void; diff --git a/packages/lib/src/utils/useForm/useForm.ts b/packages/lib/src/utils/useForm/useForm.ts index 02fa074c46..8caea4cedb 100644 --- a/packages/lib/src/utils/useForm/useForm.ts +++ b/packages/lib/src/utils/useForm/useForm.ts @@ -55,6 +55,7 @@ function useForm(props: FormProps): Form { const setErrors = useCallback((key, value) => dispatch({ type: 'setErrors', key, value }), []); const setValid = useCallback((key, value) => dispatch({ type: 'setValid', key, value }), []); const setData = useCallback((key, value) => dispatch({ type: 'setData', key, value }), []); + const mergeData = useCallback(data => dispatch({ type: 'mergeData', data }), []); const setSchema = useCallback(schema => dispatch({ type: 'setSchema', schema, defaultData }), [state.schema]); const mergeForm = useCallback(formValue => dispatch({ type: 'mergeForm', formValue }), []); const setFieldProblems = useCallback(fieldProblems => dispatch({ type: 'setFieldProblems', fieldProblems }), [state.schema]); @@ -69,6 +70,7 @@ function useForm(props: FormProps): Form { triggerValidation, setSchema, setData, + mergeData, setValid, setErrors, isValid,