diff --git a/clients/banking/src/components/TransferInternationalDynamicFormBuilder.tsx b/clients/banking/src/components/TransferInternationalDynamicFormBuilder.tsx index 23ccedae7..d153fe9a3 100644 --- a/clients/banking/src/components/TransferInternationalDynamicFormBuilder.tsx +++ b/clients/banking/src/components/TransferInternationalDynamicFormBuilder.tsx @@ -31,6 +31,7 @@ type DynamicForm = Form>; export type DynamicFormApi = { submitDynamicForm: DynamicForm["submitForm"]; + setDynamicFieldError: DynamicForm["setFieldError"]; }; type TransferInternationalDynamicFormBuilderProps = { @@ -92,9 +93,14 @@ type DynamicFormProps = { const DynamicForm = forwardRef( ({ fields, form, onChange }, forwardedRef) => { - const { Field, listenFields, submitForm, validateField, getFieldState } = useForm(form); - - useImperativeHandle(forwardedRef, () => ({ submitDynamicForm: submitForm }), [submitForm]); + const { Field, listenFields, submitForm, validateField, getFieldState, setFieldError } = + useForm(form); + + useImperativeHandle( + forwardedRef, + () => ({ submitDynamicForm: submitForm, setDynamicFieldError: setFieldError }), + [submitForm, setFieldError], + ); useEffect(() => { const keys = Object.keys(form); diff --git a/clients/banking/src/components/TransferInternationalWizardBeneficiary.tsx b/clients/banking/src/components/TransferInternationalWizardBeneficiary.tsx index 899f24339..8c21b4482 100644 --- a/clients/banking/src/components/TransferInternationalWizardBeneficiary.tsx +++ b/clients/banking/src/components/TransferInternationalWizardBeneficiary.tsx @@ -9,13 +9,19 @@ import { TransitionView } from "@swan-io/lake/src/components/TransitionView"; import { animations, colors } from "@swan-io/lake/src/constants/design"; import { useDebounce } from "@swan-io/lake/src/hooks/useDebounce"; import { useUrqlQuery } from "@swan-io/lake/src/hooks/useUrqlQuery"; -import { isNotNullishOrEmpty, isNullishOrEmpty } from "@swan-io/lake/src/utils/nullish"; +import { + isNotNullish, + isNotNullishOrEmpty, + isNullish, + isNullishOrEmpty, +} from "@swan-io/lake/src/utils/nullish"; import { useEffect, useMemo, useRef, useState } from "react"; import { ActivityIndicator, View } from "react-native"; import { hasDefinedKeys, useForm } from "react-ux-form"; import { AsyncData, Result } from "@swan-io/boxed"; import { LakeAlert } from "@swan-io/lake/src/components/LakeAlert"; +import { LakeText } from "@swan-io/lake/src/components/LakeText"; import { noop } from "@swan-io/lake/src/utils/function"; import { StyleSheet } from "react-native"; import { P, match } from "ts-pattern"; @@ -50,7 +56,7 @@ export type Beneficiary = { type Props = { initialBeneficiary?: Beneficiary; amount: Amount; - errors?: string[]; + errors?: string[][]; onPressPrevious: () => void; onSave: (details: Beneficiary) => void; }; @@ -81,25 +87,32 @@ export const TransferInternationalWizardBeneficiary = ({ [locale.language, dynamicFields], ); - const { Field, submitForm, FieldsListener, listenFields, setFieldValue, getFieldState } = - useForm<{ - name: string; - route: string; - results: ResultItem[]; - }>({ - name: { - initialValue: initialBeneficiary?.name ?? "", - validate: validateRequired, - }, - route: { - initialValue: initialBeneficiary?.route ?? "", - validate: () => undefined, - }, - results: { - initialValue: initialBeneficiary?.results ?? [], - validate: () => undefined, - }, - }); + const { + Field, + submitForm, + FieldsListener, + listenFields, + setFieldValue, + getFieldState, + setFieldError, + } = useForm<{ + name: string; + route: string; + results: ResultItem[]; + }>({ + name: { + initialValue: initialBeneficiary?.name ?? "", + validate: validateRequired, + }, + route: { + initialValue: initialBeneficiary?.route ?? "", + validate: () => undefined, + }, + results: { + initialValue: initialBeneficiary?.results ?? [], + validate: () => undefined, + }, + }); useEffect(() => { match(data) @@ -147,16 +160,37 @@ export const TransferInternationalWizardBeneficiary = ({ listenFields(["results"], () => refresh()); }, [listenFields, refresh]); + useEffect(() => { + if (isNotNullish(errors) && errors.length) { + for (const error of errors) { + if (isNotNullishOrEmpty(error[0])) { + dynamicFormApiRef.current?.setDynamicFieldError(error[0], error[1]); + } + } + } + }, [setFieldError, errors, dynamicFormApiRef.current?.setDynamicFieldError]); + + const orphanErrors = useMemo(() => errors?.filter(([key]) => isNullish(key)), [errors])?.map( + ([_, message]) => message, + ); + return ( - - {errors?.map((message, i) => ( - - - - - ))} - + + {orphanErrors?.map((message, i) => ( + {message} + ))} + + ) : null + } + > ( diff --git a/clients/banking/src/components/TransferInternationalWizardDetails.tsx b/clients/banking/src/components/TransferInternationalWizardDetails.tsx index f2b27bfd4..53ba67f70 100644 --- a/clients/banking/src/components/TransferInternationalWizardDetails.tsx +++ b/clients/banking/src/components/TransferInternationalWizardDetails.tsx @@ -108,12 +108,14 @@ export const TransferInternationalWizardDetails = ({ graphQLErrors: P.array({ extensions: { code: "BeneficiaryValidationError", - errors: P.array({ message: P.select(P.string) }), + errors: P.select(), }, }), }, - ([messages]) => { - onPressPrevious(messages); + ([errors]) => { + onPressPrevious( + errors.map(({ message, path }) => [beneficiary.results[path[2]]?.key, message]), + ); }, ) .otherwise(() => showToast({ variant: "error", title: t("error.generic") })); diff --git a/clients/banking/src/locales/en.json b/clients/banking/src/locales/en.json index 830eee152..dbcec7075 100644 --- a/clients/banking/src/locales/en.json +++ b/clients/banking/src/locales/en.json @@ -727,6 +727,7 @@ "transfer.new.sendFullBalance.description": "Choose how much to leave in your account, and transfer the rest to your beneficiary", "transfer.new.sendRegularTransfer": "Send a regular standing order instead", "transfer.new.sendRegularTransfer.description": "You will send a regular standing order", + "transfer.new.internationalTransfer.errors.title": "Some error occured", "transfer.new.internationalTransfer.title": "New international transfer", "transfer.new.internationalTransfer.amount.title": "Enter details about your transfer", "transfer.new.internationalTransfer.amount.summary.title": "You're sending",