Skip to content

Commit

Permalink
Add response resolver API
Browse files Browse the repository at this point in the history
  • Loading branch information
tujoworker committed Feb 16, 2025
1 parent 11e4ab8 commit 04de67e
Show file tree
Hide file tree
Showing 3 changed files with 109 additions and 26 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ import type { UseFieldProps } from '../../types'
import { FormError } from '../../utils'
import {
GeneralConfig,
HandlerConfig,
PreResponseResolver,
ResponseResolver,
fetchData,
getCountryCodeValue,
handleCountryPath,
Expand All @@ -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<typeof resolver> & {
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<string>['onChange'] {
const abortControllerRef = { current: null }

Expand All @@ -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) {
Expand All @@ -76,18 +103,26 @@ 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
}
}
}

export function validator(
generalConfig: GeneralConfig
generalConfig: GeneralConfig,
handlerConfig?: HandlerConfig
):
| UseFieldProps<string>['onChangeValidator']
| UseFieldProps<string>['onBlurValidator'] {
Expand All @@ -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
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,27 @@ export function createContext<GeneralConfigGeneric = GeneralConfig>(
}
}

export type HandlerConfig = {
preResponseResolver?: PreResponseResolver
responseResolver?: ResponseResolver
}
export type PreResponseResolver = (fromField: { value: string }) => unknown
export type ResponseResolver<
Response = unknown,
Payload = Record<string, unknown>,
> = (
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(
Expand Down Expand Up @@ -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
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
Expand Down

0 comments on commit 04de67e

Please sign in to comment.