From 74c6762d789c245187656e8f3723d2f5b7767ad5 Mon Sep 17 00:00:00 2001 From: Alexander Saiannyi Date: Mon, 18 Nov 2024 12:46:50 +0100 Subject: [PATCH] refactor(core) improve account forms submit error --- .changeset/afraid-eels-complain.md | 5 ++++ .../_actions/change-password.ts | 12 ++++----- .../_components/change-password-form.tsx | 13 +++------- .../(auth)/login/_components/login-form.tsx | 3 ++- .../_actions/reset-password.ts | 18 ++++++------- .../_components/reset-password-form/index.tsx | 19 +++++++------- .../_components/register-customer-form.tsx | 18 ++++++------- .../_components/account-status-provider.tsx | 9 +++++-- .../(tabs)/_components/submit-errors-list.tsx | 7 ------ .../_components/submit-messages-list.tsx | 7 ++++++ .../account/(tabs)/_components/utils.ts | 15 ----------- .../addresses/_actions/delete-address.ts | 8 +++--- .../addresses/_components/address-book.tsx | 5 ++-- .../addresses/add/_actions/add-address.ts | 10 ++++---- .../add/_components/add-address-form.tsx | 21 ++++++++-------- .../edit/[slug]/_actions/update-address.ts | 21 ++++++---------- .../[slug]/_components/edit-address-form.tsx | 25 +++++++++---------- .../settings/_actions/update-customer.ts | 6 ++--- .../_components/update-settings-form.tsx | 15 +++++------ .../_actions/change-password.ts | 14 +++++------ .../_components/change-password-form.tsx | 17 +++---------- 21 files changed, 116 insertions(+), 152 deletions(-) create mode 100644 .changeset/afraid-eels-complain.md delete mode 100644 core/app/[locale]/(default)/account/(tabs)/_components/submit-errors-list.tsx create mode 100644 core/app/[locale]/(default)/account/(tabs)/_components/submit-messages-list.tsx delete mode 100644 core/app/[locale]/(default)/account/(tabs)/_components/utils.ts diff --git a/.changeset/afraid-eels-complain.md b/.changeset/afraid-eels-complain.md new file mode 100644 index 0000000000..190e070033 --- /dev/null +++ b/.changeset/afraid-eels-complain.md @@ -0,0 +1,5 @@ +--- +"@bigcommerce/catalyst-core": patch +--- + +improve account forms submit errors message diff --git a/core/app/[locale]/(default)/(auth)/change-password/_actions/change-password.ts b/core/app/[locale]/(default)/(auth)/change-password/_actions/change-password.ts index c59383109d..aa067d2cc9 100644 --- a/core/app/[locale]/(default)/(auth)/change-password/_actions/change-password.ts +++ b/core/app/[locale]/(default)/(auth)/change-password/_actions/change-password.ts @@ -62,30 +62,28 @@ export const changePassword = async (_previousState: unknown, formData: FormData const result = response.data.customer.resetPassword; if (result.errors.length === 0) { - return { status: 'success', message: '' }; + return { status: 'success', messages: [''] }; } return { status: 'error', - message: result.errors.map((error) => error.message).join('\n'), + messages: result.errors.map((error) => error.message), }; } catch (error: unknown) { if (error instanceof ZodError) { return { status: 'error', - message: error.issues - .map(({ path, message }) => `${path.toString()}: ${message}.`) - .join('\n'), + messages: error.issues.map(({ path, message }) => `${path.toString()}: ${message}.`), }; } if (error instanceof Error) { return { status: 'error', - message: error.message, + messages: [error.message], }; } - return { status: 'error', message: t('Errors.error') }; + return { status: 'error', messages: [t('Errors.error')] }; } }; diff --git a/core/app/[locale]/(default)/(auth)/change-password/_components/change-password-form.tsx b/core/app/[locale]/(default)/(auth)/change-password/_components/change-password-form.tsx index c69f2d8206..318c75a41e 100644 --- a/core/app/[locale]/(default)/(auth)/change-password/_components/change-password-form.tsx +++ b/core/app/[locale]/(default)/(auth)/change-password/_components/change-password-form.tsx @@ -18,6 +18,7 @@ import { Message } from '~/components/ui/message'; import { useRouter } from '~/i18n/routing'; import { useAccountStatusContext } from '../../../account/(tabs)/_components/account-status-provider'; +import { SubmitMessagesList } from '../../../account/(tabs)/_components/submit-messages-list'; import { changePassword } from '../_actions/change-password'; interface Props { @@ -50,19 +51,13 @@ export const ChangePasswordForm = ({ customerId, customerToken }: Props) => { const router = useRouter(); const [state, formAction] = useActionState(changePassword, { status: 'idle', - message: '', + messages: [''], }); const [newPassword, setNewPasssword] = useState(''); const [isConfirmPasswordValid, setIsConfirmPasswordValid] = useState(true); const { setAccountState } = useAccountStatusContext(); - let messageText = ''; - - if (state.status === 'error') { - messageText = state.message; - } - const handleNewPasswordChange = (e: ChangeEvent) => setNewPasssword(e.target.value); const handleConfirmPasswordValidation = (e: ChangeEvent) => { @@ -72,7 +67,7 @@ export const ChangePasswordForm = ({ customerId, customerToken }: Props) => { }; if (state.status === 'success') { - setAccountState({ status: 'success', message: t('confirmChangePassword') }); + setAccountState({ status: 'success', messages: [t('confirmChangePassword')] }); router.push('/login'); } @@ -80,7 +75,7 @@ export const ChangePasswordForm = ({ customerId, customerToken }: Props) => { <> {state.status === 'error' && ( -

{messageText}

+
)} diff --git a/core/app/[locale]/(default)/(auth)/login/_components/login-form.tsx b/core/app/[locale]/(default)/(auth)/login/_components/login-form.tsx index 074aeab15b..7ed880e03b 100644 --- a/core/app/[locale]/(default)/(auth)/login/_components/login-form.tsx +++ b/core/app/[locale]/(default)/(auth)/login/_components/login-form.tsx @@ -18,6 +18,7 @@ import { import { Message } from '~/components/ui/message'; import { useAccountStatusContext } from '../../../account/(tabs)/_components/account-status-provider'; +import { SubmitMessagesList } from '../../../account/(tabs)/_components/submit-messages-list'; import { login } from '../_actions/login'; const SubmitButton = () => { @@ -66,7 +67,7 @@ export const LoginForm = () => { <> {accountState.status === 'success' && ( -

{accountState.message}

+
)} diff --git a/core/app/[locale]/(default)/(auth)/login/forgot-password/_actions/reset-password.ts b/core/app/[locale]/(default)/(auth)/login/forgot-password/_actions/reset-password.ts index 228a7415bf..0eb100cbfc 100644 --- a/core/app/[locale]/(default)/(auth)/login/forgot-password/_actions/reset-password.ts +++ b/core/app/[locale]/(default)/(auth)/login/forgot-password/_actions/reset-password.ts @@ -16,14 +16,12 @@ const processZodErrors = (err: z.ZodError) => { })); if (formErrors.length > 0) { - return formErrors.join('\n'); + return formErrors.map(({ message }) => message); } - return Object.entries(fieldErrors) - .map(([, errorList]) => { - return `${errorList?.map(({ message }) => message).join('\n')}`; - }) - .join('\n'); + return Object.entries(fieldErrors).flatMap(([, errorList]) => { + return errorList?.map(({ message }) => message) ?? ['']; + }); }; const ResetPasswordMutation = graphql(` @@ -82,20 +80,20 @@ export const resetPassword = async ({ return { status: 'error', - error: result.errors.map((error) => error.message).join('\n'), + errors: result.errors.map((error) => error.message), }; } catch (error: unknown) { if (error instanceof z.ZodError) { return { status: 'error', - error: processZodErrors(error), + errors: processZodErrors(error), }; } if (error instanceof Error) { - return { status: 'error', error: error.message }; + return { status: 'error', errors: [error.message] }; } - return { status: 'error', error: t('Errors.error') }; + return { status: 'error', errors: [t('Errors.error')] }; } }; diff --git a/core/app/[locale]/(default)/(auth)/login/forgot-password/_components/reset-password-form/index.tsx b/core/app/[locale]/(default)/(auth)/login/forgot-password/_components/reset-password-form/index.tsx index df3d8b1e6f..4ab213a512 100644 --- a/core/app/[locale]/(default)/(auth)/login/forgot-password/_components/reset-password-form/index.tsx +++ b/core/app/[locale]/(default)/(auth)/login/forgot-password/_components/reset-password-form/index.tsx @@ -5,7 +5,11 @@ import { ChangeEvent, useEffect, useRef, useState } from 'react'; import { useFormStatus } from 'react-dom'; import ReCaptcha from 'react-google-recaptcha'; -import { useAccountStatusContext } from '~/app/[locale]/(default)/account/(tabs)/_components/account-status-provider'; +import { + AccountState as FormStatus, + useAccountStatusContext, +} from '~/app/[locale]/(default)/account/(tabs)/_components/account-status-provider'; +import { SubmitMessagesList } from '~/app/[locale]/(default)/account/(tabs)/_components/submit-messages-list'; import { type FragmentOf } from '~/client/graphql'; import { Button } from '~/components/ui/button'; import { @@ -28,11 +32,6 @@ interface Props { reCaptchaSettings?: FragmentOf; } -interface FormStatus { - status: 'success' | 'error'; - message: string; -} - const SubmitButton = () => { const t = useTranslations('Login.ForgotPassword.Form'); @@ -65,7 +64,7 @@ export const ResetPasswordForm = ({ reCaptchaSettings }: Props) => { const router = useRouter(); useEffect(() => { - setAccountState({ status: 'idle' }); + setAccountState({ status: 'idle', messages: [''] }); }, [setAccountState]); const onReCatpchaChange = (token: string | null) => { @@ -107,13 +106,13 @@ export const ResetPasswordForm = ({ reCaptchaSettings }: Props) => { setAccountState({ status: 'success', - message: t('confirmResetPassword', { email: customerEmail?.toString() }), + messages: [t('confirmResetPassword', { email: customerEmail?.toString() })], }); router.push('/login'); } if (submit.status === 'error') { - setFormStatus({ status: 'error', message: submit.error ?? '' }); + setFormStatus({ status: 'error', messages: submit.errors ?? [''] }); } reCaptchaRef.current?.reset(); @@ -123,7 +122,7 @@ export const ResetPasswordForm = ({ reCaptchaSettings }: Props) => { <> {formStatus?.status === 'error' && ( -

{formStatus.message}

+
)} diff --git a/core/app/[locale]/(default)/(auth)/register/_components/register-customer-form.tsx b/core/app/[locale]/(default)/(auth)/register/_components/register-customer-form.tsx index f71d6723a2..d2bdf7a443 100644 --- a/core/app/[locale]/(default)/(auth)/register/_components/register-customer-form.tsx +++ b/core/app/[locale]/(default)/(auth)/register/_components/register-customer-form.tsx @@ -5,7 +5,10 @@ import { ChangeEvent, MouseEvent, useRef, useState } from 'react'; import { useFormStatus } from 'react-dom'; import ReCaptcha from 'react-google-recaptcha'; -import { useAccountStatusContext } from '~/app/[locale]/(default)/account/(tabs)/_components/account-status-provider'; +import { + AccountState as FormStatus, + useAccountStatusContext, +} from '~/app/[locale]/(default)/account/(tabs)/_components/account-status-provider'; import { ExistingResultType } from '~/client/util'; import { Checkboxes, @@ -35,16 +38,11 @@ import { Button } from '~/components/ui/button'; import { Field, Form, FormSubmit } from '~/components/ui/form'; import { Message } from '~/components/ui/message'; -import { SubmitErrorsList } from '../../../account/(tabs)/_components/submit-errors-list'; +import { SubmitMessagesList } from '../../../account/(tabs)/_components/submit-messages-list'; import { login } from '../_actions/login'; import { registerCustomer } from '../_actions/register-customer'; import { getRegisterCustomerQuery } from '../page-data'; -interface FormStatus { - status: 'success' | 'error'; - messages: string[]; -} - type CustomerFields = ExistingResultType['customerFields']; type AddressFields = ExistingResultType['addressFields']; @@ -225,7 +223,7 @@ export const RegisterCustomerForm = ({ const submit = await registerCustomer({ formData, reCaptchaToken }); if (submit.status === 'success') { - setAccountState({ status: 'success' }); + setAccountState({ status: 'success', messages: [''] }); await login(formData); } @@ -242,9 +240,9 @@ export const RegisterCustomerForm = ({ return ( <> - {formStatus && ( + {formStatus && formStatus.status !== 'idle' && ( - + )}
diff --git a/core/app/[locale]/(default)/account/(tabs)/_components/account-status-provider.tsx b/core/app/[locale]/(default)/account/(tabs)/_components/account-status-provider.tsx index 6683b97789..f4d259ef05 100644 --- a/core/app/[locale]/(default)/account/(tabs)/_components/account-status-provider.tsx +++ b/core/app/[locale]/(default)/account/(tabs)/_components/account-status-provider.tsx @@ -4,9 +4,14 @@ import { createContext, ReactNode, useContext, useEffect, useState } from 'react import { usePathname } from '~/i18n/routing'; -import { State as AccountState } from '../settings/change-password/_actions/change-password'; +// import { State as AccountState } from '../settings/change-password/_actions/change-password'; -const defaultState: AccountState = { status: 'idle', message: '' }; +export interface AccountState { + status: 'idle' | 'error' | 'success'; + messages: string[]; +} + +const defaultState: AccountState = { status: 'idle', messages: [''] }; export const AccountStatusContext = createContext<{ accountState: AccountState; diff --git a/core/app/[locale]/(default)/account/(tabs)/_components/submit-errors-list.tsx b/core/app/[locale]/(default)/account/(tabs)/_components/submit-errors-list.tsx deleted file mode 100644 index 44feaf145a..0000000000 --- a/core/app/[locale]/(default)/account/(tabs)/_components/submit-errors-list.tsx +++ /dev/null @@ -1,7 +0,0 @@ -export const SubmitErrorsList = ({ errors }: { errors: string[] }) => ( -
    - {errors.map((error) => ( -
  • {error}
  • - ))} -
-); diff --git a/core/app/[locale]/(default)/account/(tabs)/_components/submit-messages-list.tsx b/core/app/[locale]/(default)/account/(tabs)/_components/submit-messages-list.tsx new file mode 100644 index 0000000000..d5496c56cc --- /dev/null +++ b/core/app/[locale]/(default)/account/(tabs)/_components/submit-messages-list.tsx @@ -0,0 +1,7 @@ +export const SubmitMessagesList = ({ messages }: { messages: string[] }) => ( +
    + {messages.map((message) => ( +
  • {message}
  • + ))} +
+); diff --git a/core/app/[locale]/(default)/account/(tabs)/_components/utils.ts b/core/app/[locale]/(default)/account/(tabs)/_components/utils.ts deleted file mode 100644 index 1c57f32162..0000000000 --- a/core/app/[locale]/(default)/account/(tabs)/_components/utils.ts +++ /dev/null @@ -1,15 +0,0 @@ -interface GenericError { - [p: string]: string | string[]; - message: string; -} - -export const createErrorsList = (submitErrors: GenericError[]) => - submitErrors - .map((error) => { - if (submitErrors.length > 1) { - return `\u2022 ${error.message}`; - } - - return error.message; - }) - .join('\n'); diff --git a/core/app/[locale]/(default)/account/(tabs)/addresses/_actions/delete-address.ts b/core/app/[locale]/(default)/account/(tabs)/addresses/_actions/delete-address.ts index 6891daad19..ec5f3cf241 100644 --- a/core/app/[locale]/(default)/account/(tabs)/addresses/_actions/delete-address.ts +++ b/core/app/[locale]/(default)/account/(tabs)/addresses/_actions/delete-address.ts @@ -53,21 +53,21 @@ export const deleteAddress = async (addressId: number): Promise => { revalidatePath('/account/addresses', 'page'); if (result.errors.length === 0) { - return { status: 'success', message: t('success') }; + return { status: 'success', messages: [t('success')] }; } return { status: 'error', - message: result.errors.map((error) => error.message).join('\n'), + messages: result.errors.map((error) => error.message), }; } catch (error: unknown) { if (error instanceof Error) { return { status: 'error', - message: error.message, + messages: [error.message], }; } - return { status: 'error', message: t('error') }; + return { status: 'error', messages: [t('error')] }; } }; diff --git a/core/app/[locale]/(default)/account/(tabs)/addresses/_components/address-book.tsx b/core/app/[locale]/(default)/account/(tabs)/addresses/_components/address-book.tsx index b921fba6c2..1c42fc5f90 100644 --- a/core/app/[locale]/(default)/account/(tabs)/addresses/_components/address-book.tsx +++ b/core/app/[locale]/(default)/account/(tabs)/addresses/_components/address-book.tsx @@ -10,6 +10,7 @@ import { Message } from '~/components/ui/message'; import { useAccountStatusContext } from '../../_components/account-status-provider'; import { Modal } from '../../_components/modal'; +import { SubmitMessagesList } from '../../_components/submit-messages-list'; import { deleteAddress } from '../_actions/delete-address'; import { getCustomerAddresses } from '../page-data'; @@ -35,7 +36,7 @@ const AddressChangeButtons = ({ addressId, isAddressRemovable, onDelete }: Addre setAccountState({ status: 'success', - message: submit.message || '', + messages: submit.messages || [''], }); } }; @@ -76,7 +77,7 @@ export const AddressBook = ({ <> {(accountState.status === 'error' || accountState.status === 'success') && ( -

{accountState.message}

+
)} {!addressesCount &&

{t('emptyAddresses')}

} diff --git a/core/app/[locale]/(default)/account/(tabs)/addresses/add/_actions/add-address.ts b/core/app/[locale]/(default)/account/(tabs)/addresses/add/_actions/add-address.ts index 1d97dcf8ea..8c38c3ec89 100644 --- a/core/app/[locale]/(default)/account/(tabs)/addresses/add/_actions/add-address.ts +++ b/core/app/[locale]/(default)/account/(tabs)/addresses/add/_actions/add-address.ts @@ -64,7 +64,7 @@ export const addAddress = async ({ if (!isAddCustomerAddressInput(parsed)) { return { status: 'error', - error: t('Errors.inputError'), + errors: [t('Errors.inputError')], }; } @@ -83,21 +83,21 @@ export const addAddress = async ({ revalidatePath('/account/addresses', 'page'); if (result.errors.length === 0) { - return { status: 'success', message: t('success') }; + return { status: 'success', messages: [t('success')] }; } return { status: 'error', - message: result.errors.map((error) => error.message).join('\n'), + messages: result.errors.map((error) => error.message), }; } catch (error: unknown) { if (error instanceof Error) { return { status: 'error', - message: error.message, + messages: [error.message], }; } - return { status: 'error', message: t('Errors.error') }; + return { status: 'error', messages: [t('Errors.error')] }; } }; diff --git a/core/app/[locale]/(default)/account/(tabs)/addresses/add/_components/add-address-form.tsx b/core/app/[locale]/(default)/account/(tabs)/addresses/add/_components/add-address-form.tsx index 6a09a14dec..543dafa08c 100644 --- a/core/app/[locale]/(default)/account/(tabs)/addresses/add/_components/add-address-form.tsx +++ b/core/app/[locale]/(default)/account/(tabs)/addresses/add/_components/add-address-form.tsx @@ -36,15 +36,14 @@ import { Field, Form, FormSubmit } from '~/components/ui/form'; import { Message } from '~/components/ui/message'; import { useRouter } from '~/i18n/routing'; -import { useAccountStatusContext } from '../../../_components/account-status-provider'; +import { + AccountState as FormStatus, + useAccountStatusContext, +} from '../../../_components/account-status-provider'; +import { SubmitMessagesList } from '../../../_components/submit-messages-list'; import { addAddress } from '../_actions/add-address'; import { NewAddressQueryResult } from '../page'; -interface FormStatus { - status: 'success' | 'error'; - message: string; -} - type AddressFields = NonNullable< NewAddressQueryResult['site']['settings'] >['formFields']['shippingAddress']; @@ -124,7 +123,7 @@ export const AddAddressForm = ({ const { setAccountState } = useAccountStatusContext(); useEffect(() => { - setAccountState({ status: 'idle' }); + setAccountState({ status: 'idle', messages: [''] }); }, [setAccountState]); const handleTextInputValidation = createTextInputValidationHandler( @@ -187,7 +186,7 @@ export const AddAddressForm = ({ if (submit.status === 'success') { setAccountState({ status: 'success', - message: submit.message || '', + messages: submit.messages || [''], }); router.push('/account/addresses'); @@ -196,7 +195,7 @@ export const AddAddressForm = ({ } if (submit.status === 'error') { - setFormStatus({ status: 'error', message: submit.message || '' }); + setFormStatus({ status: 'error', messages: submit.messages || [''] }); } window.scrollTo({ @@ -207,9 +206,9 @@ export const AddAddressForm = ({ return ( <> - {formStatus && ( + {formStatus && formStatus.status !== 'idle' && ( -

{formStatus.message}

+
)} diff --git a/core/app/[locale]/(default)/account/(tabs)/addresses/edit/[slug]/_actions/update-address.ts b/core/app/[locale]/(default)/account/(tabs)/addresses/edit/[slug]/_actions/update-address.ts index b9b90ae4f0..099a82ef84 100644 --- a/core/app/[locale]/(default)/account/(tabs)/addresses/edit/[slug]/_actions/update-address.ts +++ b/core/app/[locale]/(default)/account/(tabs)/addresses/edit/[slug]/_actions/update-address.ts @@ -17,6 +17,9 @@ const UpdateCustomerAddressMutation = graphql(` updateCustomerAddress(input: $input, reCaptchaV2: $reCaptchaV2) { errors { __typename + ... on AddressDoesNotExistError { + message + } ... on CustomerAddressUpdateError { message } @@ -69,7 +72,7 @@ export const updateAddress = async ({ if (!isUpdateCustomerAddressInput(parsed)) { return { status: 'error', - error: t('Errors.inputError'), + errors: [t('Errors.inputError')], }; } @@ -91,29 +94,21 @@ export const updateAddress = async ({ revalidatePath('/account/addresses', 'page'); if (result.errors.length === 0) { - return { status: 'success', message: t('success') }; + return { status: 'success', messages: [t('success')] }; } return { status: 'error', - message: result.errors - .map((error) => { - if (error.__typename === 'AddressDoesNotExistError') { - return t('Errors.notFound'); - } - - return error.message; - }) - .join('\n'), + messages: result.errors.map((error) => error.message), }; } catch (error: unknown) { if (error instanceof Error) { return { status: 'error', - message: error.message, + messages: [error.message], }; } - return { status: 'error', message: t('Errors.error') }; + return { status: 'error', messages: [t('Errors.error')] }; } }; diff --git a/core/app/[locale]/(default)/account/(tabs)/addresses/edit/[slug]/_components/edit-address-form.tsx b/core/app/[locale]/(default)/account/(tabs)/addresses/edit/[slug]/_components/edit-address-form.tsx index b6c2570b59..e88a6e8a0b 100644 --- a/core/app/[locale]/(default)/account/(tabs)/addresses/edit/[slug]/_components/edit-address-form.tsx +++ b/core/app/[locale]/(default)/account/(tabs)/addresses/edit/[slug]/_components/edit-address-form.tsx @@ -37,17 +37,16 @@ import { Field, Form, FormSubmit } from '~/components/ui/form'; import { Message } from '~/components/ui/message'; import { useRouter } from '~/i18n/routing'; -import { useAccountStatusContext } from '../../../../_components/account-status-provider'; +import { + AccountState as FormStatus, + useAccountStatusContext, +} from '../../../../_components/account-status-provider'; import { Modal } from '../../../../_components/modal'; +import { SubmitMessagesList } from '../../../../_components/submit-messages-list'; import { deleteAddress } from '../../../_actions/delete-address'; import { updateAddress } from '../_actions/update-address'; import { CustomerEditAddressQueryResult } from '../page'; -interface FormStatus { - status: 'success' | 'error'; - message: string; -} - type Address = NonNullable< NonNullable['addresses']['edges'] >[number]['node']; @@ -130,7 +129,7 @@ export const EditAddressForm = ({ const { setAccountState } = useAccountStatusContext(); useEffect(() => { - setAccountState({ status: 'idle' }); + setAccountState({ status: 'idle', messages: [''] }); }, [setAccountState]); const [textInputValid, setTextInputValid] = useState>({}); @@ -211,7 +210,7 @@ export const EditAddressForm = ({ if (submit.status === 'success') { setAccountState({ status: 'success', - message: submit.message || '', + messages: submit.messages || [''], }); router.push('/account/addresses'); @@ -220,7 +219,7 @@ export const EditAddressForm = ({ } if (submit.status === 'error') { - setFormStatus({ status: 'error', message: submit.message || '' }); + setFormStatus({ status: 'error', messages: submit.messages || [''] }); } window.scrollTo({ @@ -233,11 +232,11 @@ export const EditAddressForm = ({ const submit = await deleteAddress(address.entityId); if (submit.status === 'success') { - setAccountState({ status: submit.status, message: submit.message || '' }); + setAccountState({ status: submit.status, messages: submit.messages || [''] }); } if (submit.status === 'error') { - setAccountState({ status: submit.status, message: submit.message || '' }); + setAccountState({ status: submit.status, messages: submit.messages || [''] }); } router.push('/account/addresses'); @@ -245,9 +244,9 @@ export const EditAddressForm = ({ return ( <> - {formStatus && ( + {formStatus && formStatus.status !== 'idle' && ( -

{formStatus.message}

+
)} diff --git a/core/app/[locale]/(default)/account/(tabs)/settings/_actions/update-customer.ts b/core/app/[locale]/(default)/account/(tabs)/settings/_actions/update-customer.ts index 1148a953a5..1da96bb890 100644 --- a/core/app/[locale]/(default)/account/(tabs)/settings/_actions/update-customer.ts +++ b/core/app/[locale]/(default)/account/(tabs)/settings/_actions/update-customer.ts @@ -74,7 +74,7 @@ export const updateCustomer = async ({ formData, reCaptchaToken }: UpdateCustome if (!isUpdateCustomerInput(parsed)) { return { status: 'error', - error: t('Errors.inputError'), + errors: [t('Errors.inputError')], }; } @@ -98,7 +98,7 @@ export const updateCustomer = async ({ formData, reCaptchaToken }: UpdateCustome if (!customer) { return { status: 'error', - error: t('Errors.notFound'), + errors: [t('Errors.notFound')], }; } @@ -109,6 +109,6 @@ export const updateCustomer = async ({ formData, reCaptchaToken }: UpdateCustome return { status: 'error', - error: result.errors.map((error) => error.message).join('\n'), + errors: result.errors.map((error) => error.message), }; }; diff --git a/core/app/[locale]/(default)/account/(tabs)/settings/_components/update-settings-form.tsx b/core/app/[locale]/(default)/account/(tabs)/settings/_components/update-settings-form.tsx index 5d6219931b..e97c028b80 100644 --- a/core/app/[locale]/(default)/account/(tabs)/settings/_components/update-settings-form.tsx +++ b/core/app/[locale]/(default)/account/(tabs)/settings/_components/update-settings-form.tsx @@ -33,6 +33,8 @@ import { Button } from '~/components/ui/button'; import { Field, Form, FormSubmit } from '~/components/ui/form'; import { Message } from '~/components/ui/message'; +import { AccountState as FormStatus } from '../../_components/account-status-provider'; +import { SubmitMessagesList } from '../../_components/submit-messages-list'; import { updateCustomer } from '../_actions/update-customer'; import { getCustomerSettingsQuery } from '../page-data'; @@ -52,11 +54,6 @@ interface FormProps { }; } -interface FormStatus { - status: 'success' | 'error'; - message: string; -} - interface SumbitMessages { messages: { submit: string; @@ -190,12 +187,12 @@ export const UpdateSettingsForm = ({ if (submit.status === 'success') { setFormStatus({ status: 'success', - message: t('successMessage'), + messages: [t('successMessage')], }); } if (submit.status === 'error') { - setFormStatus({ status: 'error', message: submit.error ?? '' }); + setFormStatus({ status: 'error', messages: submit.errors ?? [''] }); } window.scrollTo({ @@ -206,9 +203,9 @@ export const UpdateSettingsForm = ({ return ( <> - {formStatus && ( + {formStatus && formStatus.status !== 'idle' && ( -

{formStatus.message}

+
)} diff --git a/core/app/[locale]/(default)/account/(tabs)/settings/change-password/_actions/change-password.ts b/core/app/[locale]/(default)/account/(tabs)/settings/change-password/_actions/change-password.ts index 30691df16e..5bba82c318 100644 --- a/core/app/[locale]/(default)/account/(tabs)/settings/change-password/_actions/change-password.ts +++ b/core/app/[locale]/(default)/account/(tabs)/settings/change-password/_actions/change-password.ts @@ -46,7 +46,7 @@ const CustomerChangePasswordMutation = graphql(` export interface State { status: 'idle' | 'error' | 'success'; - message?: string; + messages?: string[]; } export const changePassword = async (_previousState: unknown, formData: FormData) => { @@ -74,30 +74,28 @@ export const changePassword = async (_previousState: unknown, formData: FormData const result = response.data.customer.changePassword; if (result.errors.length === 0) { - return { status: 'success', message: t('success') }; + return { status: 'success', messages: [t('success')] }; } return { status: 'error', - message: result.errors.map((error) => error.message).join('\n'), + messages: result.errors.map((error) => error.message), }; } catch (error: unknown) { if (error instanceof z.ZodError) { return { status: 'error', - message: error.issues - .map(({ path, message }) => `${path.toString()}: ${message}.`) - .join('\n'), + messages: error.issues.map(({ path, message }) => `${path.toString()}: ${message}.`), }; } if (error instanceof Error) { return { status: 'error', - message: error.message, + messages: [error.message], }; } - return { status: 'error', message: t('error') }; + return { status: 'error', messages: [t('error')] }; } }; diff --git a/core/app/[locale]/(default)/account/(tabs)/settings/change-password/_components/change-password-form.tsx b/core/app/[locale]/(default)/account/(tabs)/settings/change-password/_components/change-password-form.tsx index f08a81fd6c..e2cde1cc8f 100644 --- a/core/app/[locale]/(default)/account/(tabs)/settings/change-password/_components/change-password-form.tsx +++ b/core/app/[locale]/(default)/account/(tabs)/settings/change-password/_components/change-password-form.tsx @@ -20,6 +20,7 @@ import { import { Message } from '~/components/ui/message'; import { useAccountStatusContext } from '../../../_components/account-status-provider'; +import { SubmitMessagesList } from '../../../_components/submit-messages-list'; import { changePassword } from '../_actions/change-password'; const ChangePasswordFieldsSchema = z.object({ @@ -99,7 +100,7 @@ export const ChangePasswordForm = () => { const t = useTranslations('Account.Settings.ChangePassword'); const [state, formAction] = useActionState(changePassword, { status: 'idle', - message: '', + messages: [''], }); const [isCurrentPasswordValid, setIsCurrentPasswordValid] = useState(true); @@ -114,21 +115,11 @@ export const ChangePasswordForm = () => { setAccountState({ status: 'success', - message: t('confirmChangePassword'), + messages: [t('confirmChangePassword')], }); } }, [state, setAccountState, t]); - let messageText = ''; - - if (state.status === 'error') { - messageText = state.message; - } - - if (state.status === 'success') { - messageText = state.message; - } - const handleCurrentPasswordChange = (e: ChangeEvent) => setIsCurrentPasswordValid(!e.target.validity.valueMissing); @@ -159,7 +150,7 @@ export const ChangePasswordForm = () => { <> {state.status === 'error' && ( -

{messageText}

+
)}