diff --git a/.changeset/grumpy-roses-attack.md b/.changeset/grumpy-roses-attack.md new file mode 100644 index 000000000..b52e1ff66 --- /dev/null +++ b/.changeset/grumpy-roses-attack.md @@ -0,0 +1,5 @@ +--- +"@bigcommerce/catalyst-core": minor +--- + +Update the register customer page to use toasts for messaging. diff --git a/core/app/[locale]/(default)/(auth)/register/_actions/register-customer.ts b/core/app/[locale]/(default)/(auth)/register/_actions/register-customer.ts index 63a2cd049..23de2ae83 100644 --- a/core/app/[locale]/(default)/(auth)/register/_actions/register-customer.ts +++ b/core/app/[locale]/(default)/(auth)/register/_actions/register-customer.ts @@ -37,11 +37,6 @@ const RegisterCustomerMutation = graphql(` type Variables = VariablesOf; type RegisterCustomerInput = Variables['input']; -interface RegisterCustomerForm { - formData: FormData; - reCaptchaToken?: string; -} - const isRegisterCustomerInput = (data: unknown): data is RegisterCustomerInput => { if (typeof data === 'object' && data !== null && 'email' in data) { return true; @@ -50,7 +45,15 @@ const isRegisterCustomerInput = (data: unknown): data is RegisterCustomerInput = return false; }; -export const registerCustomer = async ({ formData, reCaptchaToken }: RegisterCustomerForm) => { +interface RegisterCustomerResponse { + status: 'success' | 'error'; + message: string; +} + +export const registerCustomer = async ( + formData: FormData, + reCaptchaToken?: string, +): Promise => { const t = await getTranslations('Register'); formData.delete('customer-confirmPassword'); @@ -60,7 +63,7 @@ export const registerCustomer = async ({ formData, reCaptchaToken }: RegisterCus if (!isRegisterCustomerInput(parsedData)) { return { status: 'error', - errors: [t('Errors.inputError')], + message: t('Errors.inputError'), }; } @@ -78,14 +81,13 @@ export const registerCustomer = async ({ formData, reCaptchaToken }: RegisterCus const result = response.data.customer.registerCustomer; - if (result.errors.length === 0) { - return { status: 'success', data: parsedData }; + if (result.errors.length > 0) { + result.errors.forEach((error) => { + throw new Error(error.message); + }); } - return { - status: 'error', - errors: result.errors.map((error) => error.message), - }; + return { status: 'success', message: t('Form.successMessage') }; } catch (error) { // eslint-disable-next-line no-console console.error(error); @@ -93,13 +95,13 @@ export const registerCustomer = async ({ formData, reCaptchaToken }: RegisterCus if (error instanceof BigCommerceAPIError) { return { status: 'error', - errors: [t('Errors.apiError')], + message: t('Errors.apiError'), }; } return { status: 'error', - errors: [t('Errors.error')], + message: t('Errors.error'), }; } }; 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 8ae467e19..573ace62f 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 @@ -1,14 +1,12 @@ 'use client'; +import { AlertCircle, Check } from 'lucide-react'; import { useTranslations } from 'next-intl'; import { ChangeEvent, MouseEvent, useRef, useState } from 'react'; import { useFormStatus } from 'react-dom'; import ReCaptcha from 'react-google-recaptcha'; +import { toast } from 'react-hot-toast'; -import { - AccountState as FormStatus, - useAccountStatusContext, -} from '~/app/[locale]/(default)/account/_components/account-status-provider'; import { ExistingResultType } from '~/client/util'; import { Checkboxes, @@ -36,9 +34,7 @@ import { } from '~/components/form-fields/shared/field-handlers'; import { Button } from '~/components/ui/button'; import { Field, Form, FormSubmit } from '~/components/ui/form'; -import { Message } from '~/components/ui/message'; -import { SubmitMessagesList } from '../../../account/_components/submit-messages-list'; import { login } from '../_actions/login'; import { registerCustomer } from '../_actions/register-customer'; import { getRegisterCustomerQuery } from '../page-data'; @@ -83,7 +79,6 @@ export const RegisterCustomerForm = ({ reCaptchaSettings, }: RegisterCustomerProps) => { const form = useRef(null); - const [formStatus, setFormStatus] = useState(null); const [textInputValid, setTextInputValid] = useState>({}); const [passwordValid, setPassswordValid] = useState>({ @@ -101,8 +96,6 @@ export const RegisterCustomerForm = ({ const [reCaptchaToken, setReCaptchaToken] = useState(''); const [isReCaptchaValid, setReCaptchaValid] = useState(true); - const { setAccountState } = useAccountStatusContext(); - const t = useTranslations('Register.Form'); const handleTextInputValidation = (e: ChangeEvent) => { @@ -199,9 +192,8 @@ export const RegisterCustomerForm = ({ const onSubmit = async (formData: FormData) => { if (formData.get('customer-password') !== formData.get('customer-confirmPassword')) { - setFormStatus({ - status: 'error', - messages: [t('confirmPassword')], + toast.error(t('confirmPassword'), { + icon: , }); window.scrollTo({ @@ -220,191 +212,183 @@ export const RegisterCustomerForm = ({ setReCaptchaValid(true); - const submit = await registerCustomer({ formData, reCaptchaToken }); - - if (submit.status === 'success') { - setAccountState({ status: 'success', messages: [''] }); + const { status, message } = await registerCustomer(formData, reCaptchaToken); - await login(formData); - } + if (status === 'error') { + toast.error(message, { + icon: , + }); - if (submit.status === 'error') { - setFormStatus({ status: 'error', messages: submit.errors ?? [''] }); + return; } - window.scrollTo({ - top: 0, - behavior: 'smooth', + toast.success(message, { + icon: , }); + + await login(formData); }; return ( - <> - {formStatus && formStatus.status !== 'idle' && ( - - - - )} -
-
- {addressFields.map((field) => { + +
+ {addressFields.map((field) => { + const fieldId = field.entityId; + const fieldName = createFieldName(field, 'customer'); + + if (field.__typename === 'TextFormField' && FULL_NAME_FIELDS.includes(fieldId)) { + return ( + + + + ); + } + + return null; + })} +
+
+ {customerFields + .filter((field) => !CUSTOMER_FIELDS_TO_EXCLUDE.includes(field.entityId)) + .map((field) => { const fieldId = field.entityId; const fieldName = createFieldName(field, 'customer'); - if (field.__typename === 'TextFormField' && FULL_NAME_FIELDS.includes(fieldId)) { - return ( - - - - ); - } + switch (field.__typename) { + case 'TextFormField': + return ( + + + + ); + + case 'PasswordFormField': + return ( + + + + ); + + case 'MultilineTextFormField': { + return ( + + + + ); + } - return null; - })} -
-
- {customerFields - .filter((field) => !CUSTOMER_FIELDS_TO_EXCLUDE.includes(field.entityId)) - .map((field) => { - const fieldId = field.entityId; - const fieldName = createFieldName(field, 'customer'); - - switch (field.__typename) { - case 'TextFormField': - return ( - - - - ); - - case 'PasswordFormField': - return ( - - - - ); - - case 'MultilineTextFormField': { - return ( - - - - ); - } - - case 'NumberFormField': { - return ( - - - - ); - } - - case 'DateFormField': { - return ( - - - - ); - } - - case 'RadioButtonsFormField': { - return ( - - - - ); - } - - case 'PicklistFormField': { - return ( - - - - ); - } - - case 'CheckboxesFormField': { - return ( - - - - ); - } - - default: - return null; + case 'NumberFormField': { + return ( + + + + ); } - })} - {reCaptchaSettings?.isEnabledOnStorefront && ( - - - {!isReCaptchaValid && ( - - {t('recaptchaText')} - - )} - - )} -
- - - - - - + + case 'DateFormField': { + return ( + + + + ); + } + + case 'RadioButtonsFormField': { + return ( + + + + ); + } + + case 'PicklistFormField': { + return ( + + + + ); + } + + case 'CheckboxesFormField': { + return ( + + + + ); + } + + default: + return null; + } + })} + {reCaptchaSettings?.isEnabledOnStorefront && ( + + + {!isReCaptchaValid && ( + + {t('recaptchaText')} + + )} + + )} +
+ + + + + ); }; diff --git a/core/messages/en.json b/core/messages/en.json index 18abc4960..e190de8ed 100644 --- a/core/messages/en.json +++ b/core/messages/en.json @@ -68,7 +68,8 @@ "submit": "Create account", "submitting": "Creating account...", "recaptchaText": "Pass ReCAPTCHA check", - "confirmPassword": "Passwords don't match" + "confirmPassword": "Passwords don't match", + "successMessage": "Account was successfully created." }, "Errors": { "inputError": "Something went wrong with processing user input.",