diff --git a/packages/lib/src/components/internal/Address/Address.tsx b/packages/lib/src/components/internal/Address/Address.tsx index ef78364422..a320545914 100644 --- a/packages/lib/src/components/internal/Address/Address.tsx +++ b/packages/lib/src/components/internal/Address/Address.tsx @@ -52,6 +52,13 @@ export default function Address(props: AddressProps) { formatters: addressFormatters }); + // In partial address mode, country is not in the form schema but we need it for regionalized labels. + // Store the merchant's country config once at mount, then use it if form data doesn't have country. + const initialCountryRef = useRef((props.data as AddressData)?.country); + const effectiveCountry = data.country || initialCountryRef.current; + const dataWithCountry = useMemo(() => ({ ...data, country: effectiveCountry }), [data, effectiveCountry]); + + const setSearchData = useCallback( (selectedAddress: AddressData) => { const propsKeysToProcess = ADDRESS_SCHEMA; @@ -145,6 +152,11 @@ export default function Address(props: AddressProps) { return acc; }, {}); + // In partial address mode, ensure country is included in output for regionalized labels/validation. + if (!(processedData as AddressData).country && initialCountryRef.current) { + (processedData as AddressData).country = initialCountryRef.current; + } + props.onChange({ data: processedData, valid, errors, isValid }); }, [data, valid, errors, isValid]); @@ -159,7 +171,7 @@ export default function Address(props: AddressProps) { key={fieldName} allowedCountries={props.allowedCountries} classNameModifiers={[...classNameModifiers, fieldName]} - data={data} + data={dataWithCountry} errors={errors} valid={valid} fieldName={fieldName} @@ -167,7 +179,7 @@ export default function Address(props: AddressProps) { onBlur={handleChangeFor(fieldName, 'blur')} onDropdownChange={handleChangeFor(fieldName, 'blur')} specifications={specifications} - maxLength={getMaxLengthByFieldAndCountry(countrySpecificFormatters, fieldName, data.country, true)} + maxLength={getMaxLengthByFieldAndCountry(countrySpecificFormatters, fieldName, effectiveCountry, true)} trimOnBlur={true} disabled={!enabledFields.includes(fieldName)} onFieldFocusAnalytics={props.onFieldFocusAnalytics} diff --git a/packages/lib/src/components/internal/Address/Specifications.test.ts b/packages/lib/src/components/internal/Address/Specifications.test.ts index 78a760f88e..a909ecce04 100644 --- a/packages/lib/src/components/internal/Address/Specifications.test.ts +++ b/packages/lib/src/components/internal/Address/Specifications.test.ts @@ -1,4 +1,5 @@ import Specifications from './Specifications'; +import { PARTIAL_ADDRESS_SCHEMA } from './constants'; describe('Specifications', () => { const addressSpecificationsMock = { @@ -65,3 +66,25 @@ describe('Specifications', () => { expect(specifications.getAddressSchemaForCountryFlat('PT')).toStrictEqual(['country', 'city', 'postalCode']); }); }); + +describe('Partial Address Schema Specifications', () => { + const partialSpecifications = new Specifications(PARTIAL_ADDRESS_SCHEMA); + + test('should use zipCode label for US postal code in partial mode', () => { + expect(partialSpecifications.getKeyForField('postalCode', 'US')).toBe('zipCode'); + }); + + test.each(['GB', 'CA', 'AU', 'BR', 'FR', 'DE', 'NL'])( + 'should use default postalCode label for %s in partial mode', + countryCode => { + expect(partialSpecifications.getKeyForField('postalCode', countryCode)).toBe('postalCode'); + } + ); + + test.each(['US', 'GB', 'FR'])( + 'partial schema for %s should only contain postalCode field', + countryCode => { + expect(partialSpecifications.getAddressSchemaForCountryFlat(countryCode)).toStrictEqual(['postalCode']); + } + ); +}); diff --git a/packages/lib/src/components/internal/Address/constants.ts b/packages/lib/src/components/internal/Address/constants.ts index 46bf1789ae..45228e68a1 100644 --- a/packages/lib/src/components/internal/Address/constants.ts +++ b/packages/lib/src/components/internal/Address/constants.ts @@ -66,13 +66,12 @@ export const ADDRESS_SPECIFICATIONS: AddressSpecifications = { } }; -export const PARTIAL_ADDRESS_SCHEMA: AddressSpecifications = { - default: { - labels: { - [POSTAL_CODE]: 'zipCode' - }, +export const PARTIAL_ADDRESS_SCHEMA: AddressSpecifications = Object.keys(ADDRESS_SPECIFICATIONS).reduce((acc, countryCode) => { + acc[countryCode] = { + labels: ADDRESS_SPECIFICATIONS[countryCode].labels, schema: [POSTAL_CODE] - } -}; + }; + return acc; +}, {} as AddressSpecifications); export const COUNTRIES_WITH_CUSTOM_SPECIFICATION = Object.keys(ADDRESS_SPECIFICATIONS);