diff --git a/packages/dnb-eufemia/src/extensions/forms/Connectors/Bring/postalCode.ts b/packages/dnb-eufemia/src/extensions/forms/Connectors/Bring/postalCode.ts index 48004b7fb32..3bfccf57f04 100644 --- a/packages/dnb-eufemia/src/extensions/forms/Connectors/Bring/postalCode.ts +++ b/packages/dnb-eufemia/src/extensions/forms/Connectors/Bring/postalCode.ts @@ -2,6 +2,9 @@ import type { UseFieldProps } from '../../types' import { FormError } from '../../utils' import { GeneralConfig, + HandlerConfig, + PreResponseResolver, + ResponseResolver, fetchData, getCountryCodeValue, handleCountryPath, @@ -22,16 +25,44 @@ export const supportedCountryCodes = [ 'SJ', // Svalbard and Jan Mayen ] -export type HandlerConfig = { - cityPath: string -} - export const unsupportedCountryCode = 'Postal code verification is not supported for {countryCode}.' +export type AutofillResolverResponse = { + postal_codes: { postal_code: string; city: string }[] +} +export type AutofillResolverPayload = { + city: string +} + +export const preResponseResolver: PreResponseResolver = ({ value }) => { + if (!value) { + return { postal_codes: [] } + } +} + +export const responseResolver: ResponseResolver< + AutofillResolverResponse, + AutofillResolverPayload +> = (response, handlerConfig) => { + const resolver = handlerConfig?.responseResolver + if (typeof resolver === 'function') { + return resolver(response) as ReturnType & { + payload: AutofillResolverPayload + } + } + + const { postal_code, city } = response?.postal_codes?.[0] || {} + + return { + matcher: (value) => value === postal_code, + payload: { city }, + } +} + export function autofill( generalConfig: GeneralConfig, - handlerConfig?: HandlerConfig + handlerConfig?: HandlerConfig & { cityPath: string } ): UseFieldProps['onChange'] { const abortControllerRef = { current: null } @@ -58,15 +89,11 @@ export function autofill( generalConfig, parameters, abortControllerRef, - returnResult: () => { - if (!value) { - return { postal_codes: [] } - } - }, + preResponseResolver: + handlerConfig?.preResponseResolver ?? preResponseResolver, }) - const { postal_code, city } = data?.postal_codes?.[0] || {} - if (postal_code === value) { + const onMatch = (payload: AutofillResolverPayload) => { const path = handlerConfig?.cityPath if (path) { if (!additionalArgs.dataContext) { @@ -76,10 +103,17 @@ export function autofill( } additionalArgs.dataContext.handlePathChangeUnvalidated( path, - city + payload.city ) } } + + const { matcher, payload } = responseResolver(data, handlerConfig) + const match = matcher(value) + + if (match) { + return onMatch(payload) + } } catch (error) { return error } @@ -87,7 +121,8 @@ export function autofill( } export function validator( - generalConfig: GeneralConfig + generalConfig: GeneralConfig, + handlerConfig?: HandlerConfig ): | UseFieldProps['onChangeValidator'] | UseFieldProps['onBlurValidator'] { @@ -114,19 +149,20 @@ export function validator( generalConfig, parameters, abortControllerRef, - returnResult: () => { - if (!value) { - return { postal_codes: [] } - } - }, + preResponseResolver: + handlerConfig?.preResponseResolver ?? preResponseResolver, }) - if ( - status !== 400 && - data?.postal_codes?.[0]?.postal_code !== value - ) { + const onMatch = () => { return new FormError('PostalCodeAndCity.invalidCode') } + + const { matcher } = responseResolver(data, handlerConfig) + const match = matcher(value) + + if (status !== 400 && !match) { + return onMatch() + } } catch (error) { return error } diff --git a/packages/dnb-eufemia/src/extensions/forms/Connectors/createContext.ts b/packages/dnb-eufemia/src/extensions/forms/Connectors/createContext.ts index 5602450129a..7de0bb3a201 100644 --- a/packages/dnb-eufemia/src/extensions/forms/Connectors/createContext.ts +++ b/packages/dnb-eufemia/src/extensions/forms/Connectors/createContext.ts @@ -30,11 +30,27 @@ export function createContext( } } +export type HandlerConfig = { + preResponseResolver?: PreResponseResolver + responseResolver?: ResponseResolver +} +export type PreResponseResolver = (fromField: { value: string }) => unknown +export type ResponseResolver< + Response = unknown, + Payload = Record, +> = ( + response: Response, + handlerConfig?: HandlerConfig +) => { + matcher: (value: string) => boolean + payload?: Payload +} + export type FetchDataFromAPIOptions = { generalConfig: GeneralConfig parameters?: UrlSecondParameter abortControllerRef?: { current: null | AbortController } - returnResult?: (data: { value: string }) => unknown + preResponseResolver?: PreResponseResolver } async function fetchDataFromAPI( @@ -88,7 +104,7 @@ export async function fetchData( ) { const { generalConfig, parameters } = options || {} - const result = options?.returnResult?.({ value }) + const result = options?.preResponseResolver?.({ value }) if (typeof result !== 'undefined') { return result } diff --git a/packages/dnb-eufemia/src/extensions/forms/Connectors/stories/Connectors.stories.tsx b/packages/dnb-eufemia/src/extensions/forms/Connectors/stories/Connectors.stories.tsx index f8135dd8bcc..4fcfcc82085 100644 --- a/packages/dnb-eufemia/src/extensions/forms/Connectors/stories/Connectors.stories.tsx +++ b/packages/dnb-eufemia/src/extensions/forms/Connectors/stories/Connectors.stories.tsx @@ -20,14 +20,45 @@ export function PostalCode() { }, }) + type Response = { + postal_codes: { postal_code: string; city: string }[] + } + // 2. Use the context to create the onChangeValidator ... const onChangeValidator = withConfig( - Connectors.Bring.postalCode.validator + Connectors.Bring.postalCode.validator, + { + // preResponseResolver: ({ value }) => { + // if (!value) { + // return { postal_codes: [] } + // } + // }, + responseResolver: (response: Response) => { + const { postal_code, city } = response?.postal_codes?.[0] || {} + return { + matcher: (value) => value === postal_code, + payload: { city }, + } + }, + } ) // ... and an onChange function const onChange = withConfig(Connectors.Bring.postalCode.autofill, { cityPath: '/city', + // preResponseResolver: ({ value }) => { + // if (!value) { + // return { postal_codes: [] } + // } + // }, + // responseResolver: (response: Response) => { + // const { postal_code, city } = response?.postal_codes?.[0] || {} + + // return { + // matcher: (value) => value === postal_code, + // payload: { city }, + // } + // }, }) return (