Skip to content

Commit

Permalink
fix(core): improve create account form (#1454)
Browse files Browse the repository at this point in the history
* fix(core): improve create account form

* fix(core): add empty state to addresses page

* Update Account creation tests

---------

Co-authored-by: anastasiia.zvierieva <[email protected]>
  • Loading branch information
bc-yevhenii-buliuk and bc-azvierieva authored Oct 22, 2024
1 parent 313a591 commit 53599e6
Show file tree
Hide file tree
Showing 10 changed files with 53 additions and 229 deletions.
5 changes: 5 additions & 0 deletions .changeset/thick-sloths-lick.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@bigcommerce/catalyst-core": patch
---

remove unnecessary fields from create account form
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ interface RegisterCustomerForm {
}

const isRegisterCustomerInput = (data: unknown): data is RegisterCustomerInput => {
if (typeof data === 'object' && data !== null && 'email' in data && 'address' in data) {
if (typeof data === 'object' && data !== null && 'email' in data) {
return true;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@ import {
DateField,
FieldNameToFieldId,
FieldWrapper,
FULL_NAME_FIELDS,
MultilineText,
NumbersOnly,
Password,
Picklist,
PicklistOrText,
RadioButtons,
Text,
} from '~/components/form-fields';
Expand Down Expand Up @@ -46,19 +46,10 @@ interface FormStatus {

type CustomerFields = ExistingResultType<typeof getRegisterCustomerQuery>['customerFields'];
type AddressFields = ExistingResultType<typeof getRegisterCustomerQuery>['addressFields'];
type Countries = ExistingResultType<typeof getRegisterCustomerQuery>['countries'];
type CountryCode = Countries[number]['code'];
type CountryStates = Countries[number]['statesOrProvinces'];

interface RegisterCustomerProps {
addressFields: AddressFields;
countries: Countries;
customerFields: CustomerFields;
defaultCountry: {
entityId: number;
code: CountryCode;
states: CountryStates;
};
reCaptchaSettings?: {
isEnabledOnStorefront: boolean;
siteKey: string;
Expand Down Expand Up @@ -89,9 +80,7 @@ const SubmitButton = ({ messages }: SumbitMessages) => {

export const RegisterCustomerForm = ({
addressFields,
countries,
customerFields,
defaultCountry,
reCaptchaSettings,
}: RegisterCustomerProps) => {
const form = useRef<HTMLFormElement>(null);
Expand All @@ -104,7 +93,6 @@ export const RegisterCustomerForm = ({
});
const [numbersInputValid, setNumbersInputValid] = useState<Record<string, boolean>>({});
const [datesValid, setDatesValid] = useState<Record<string, boolean>>({});
const [countryStates, setCountryStates] = useState(defaultCountry.states);
const [radioButtonsValid, setRadioButtonsValid] = useState<Record<string, boolean>>({});
const [picklistValid, setPicklistValid] = useState<Record<string, boolean>>({});
const [checkboxesValid, setCheckboxesValid] = useState<Record<string, boolean>>({});
Expand Down Expand Up @@ -178,11 +166,6 @@ export const RegisterCustomerForm = ({
}
};

const handleCountryChange = (value: string) => {
const states = countries.find(({ code }) => code === value)?.statesOrProvinces;

setCountryStates(states ?? []);
};
const handleRadioButtonsChange = createRadioButtonsValidationHandler(
setRadioButtonsValid,
radioButtonsValid,
Expand Down Expand Up @@ -264,6 +247,27 @@ export const RegisterCustomerForm = ({
</Message>
)}
<Form action={onSubmit} onClick={preSubmitFieldsValidation} ref={form}>
<div className="grid grid-cols-1 gap-y-3 lg:grid-cols-2 lg:gap-x-6">
{addressFields.map((field) => {
const fieldId = field.entityId;
const fieldName = createFieldName(field, 'customer');

if (field.__typename === 'TextFormField' && FULL_NAME_FIELDS.includes(fieldId)) {
return (
<FieldWrapper fieldId={fieldId} key={fieldId}>
<Text
field={field}
isValid={textInputValid[fieldId]}
name={fieldName}
onChange={handleTextInputValidation}
/>
</FieldWrapper>
);
}

return null;
})}
</div>
<div className="mb-4 grid grid-cols-1 gap-y-3 lg:grid-cols-2 lg:gap-x-6">
{customerFields
.filter((field) => !CUSTOMER_FIELDS_TO_EXCLUDE.includes(field.entityId))
Expand All @@ -285,6 +289,18 @@ export const RegisterCustomerForm = ({
</FieldWrapper>
);

case 'PasswordFormField':
return (
<FieldWrapper fieldId={fieldId} key={fieldId}>
<Password
field={field}
isValid={passwordValid[fieldId]}
name={fieldName}
onChange={handlePasswordValidation}
/>
</FieldWrapper>
);

case 'MultilineTextFormField': {
return (
<FieldWrapper fieldId={fieldId} key={fieldId}>
Expand Down Expand Up @@ -366,167 +382,10 @@ export const RegisterCustomerForm = ({
);
}

case 'PasswordFormField': {
return (
<FieldWrapper fieldId={fieldId} key={fieldId}>
<Password
field={field}
isValid={passwordValid[fieldId]}
name={fieldName}
onChange={handlePasswordValidation}
/>
</FieldWrapper>
);
}

default:
return null;
}
})}
</div>
<div className="grid grid-cols-1 gap-y-3 lg:grid-cols-2 lg:gap-x-6">
{addressFields.map((field) => {
const fieldId = field.entityId;
const fieldName = createFieldName(field, 'address');

switch (field.__typename) {
case 'TextFormField': {
return (
<FieldWrapper fieldId={fieldId} key={fieldId}>
<Text
field={field}
isValid={textInputValid[fieldId]}
name={fieldName}
onChange={handleTextInputValidation}
/>
</FieldWrapper>
);
}

case 'MultilineTextFormField': {
return (
<FieldWrapper fieldId={fieldId} key={fieldId}>
<MultilineText
field={field}
isValid={multiTextValid[fieldId]}
name={fieldName}
onChange={handleMultiTextValidation}
/>
</FieldWrapper>
);
}

case 'NumberFormField': {
return (
<FieldWrapper fieldId={fieldId} key={fieldId}>
<NumbersOnly
field={field}
isValid={numbersInputValid[fieldId]}
name={fieldName}
onChange={handleNumbersInputValidation}
/>
</FieldWrapper>
);
}

case 'DateFormField': {
return (
<FieldWrapper fieldId={fieldId} key={fieldId}>
<DateField
field={field}
isValid={datesValid[fieldId]}
name={fieldName}
onChange={handleDatesValidation}
onValidate={setDatesValid}
/>
</FieldWrapper>
);
}

case 'RadioButtonsFormField': {
return (
<FieldWrapper fieldId={fieldId} key={fieldId}>
<RadioButtons
field={field}
isValid={radioButtonsValid[fieldId]}
name={fieldName}
onChange={handleRadioButtonsChange}
/>
</FieldWrapper>
);
}

case 'PicklistFormField': {
const isCountrySelector = fieldId === FieldNameToFieldId.countryCode;
const picklistOptions = isCountrySelector
? countries.map(({ name, code }) => ({ label: name, entityId: code }))
: field.options;

return (
<FieldWrapper fieldId={fieldId} key={fieldId}>
<Picklist
defaultValue={isCountrySelector ? defaultCountry.code : undefined}
field={field}
isValid={picklistValid[fieldId]}
name={fieldName}
onChange={isCountrySelector ? handleCountryChange : undefined}
onValidate={setPicklistValid}
options={picklistOptions}
/>
</FieldWrapper>
);
}

case 'CheckboxesFormField': {
return (
<FieldWrapper fieldId={fieldId} key={fieldId}>
<Checkboxes
field={field}
isValid={checkboxesValid[fieldId]}
name={fieldName}
onValidate={setCheckboxesValid}
options={field.options}
/>
</FieldWrapper>
);
}

case 'PicklistOrTextFormField': {
return (
<FieldWrapper fieldId={fieldId} key={fieldId}>
<PicklistOrText
defaultValue={
fieldId === FieldNameToFieldId.stateOrProvince
? countryStates[0]?.name
: undefined
}
field={field}
name={fieldName}
options={countryStates.map(({ name }) => {
return { entityId: name, label: name };
})}
/>
</FieldWrapper>
);
}

case 'PasswordFormField': {
return (
<FieldWrapper fieldId={fieldId} key={fieldId}>
<Password
field={field}
isValid={passwordValid[fieldId]}
name={fieldName}
onChange={handlePasswordValidation}
/>
</FieldWrapper>
);
}

default:
return null;
}
})}
{reCaptchaSettings?.isEnabledOnStorefront && (
<Field className="relative col-span-full max-w-full space-y-2 pb-7" name="ReCAPTCHA">
<ReCaptcha
Expand Down
22 changes: 1 addition & 21 deletions core/app/[locale]/(default)/(auth)/register/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,6 @@ import { bypassReCaptcha } from '~/lib/bypass-recaptcha';
import { RegisterCustomerForm } from './_components/register-customer-form';
import { getRegisterCustomerQuery } from './page-data';

const FALLBACK_COUNTRY = {
entityId: 226,
name: 'United States',
code: 'US',
};

export async function generateMetadata() {
const t = await getTranslations('Register');

Expand All @@ -32,28 +26,14 @@ export default async function Register() {
notFound();
}

const {
addressFields,
customerFields,
countries,
defaultCountry = FALLBACK_COUNTRY.name,
reCaptchaSettings,
} = registerCustomerData;

const {
code = FALLBACK_COUNTRY.code,
entityId = FALLBACK_COUNTRY.entityId,
statesOrProvinces,
} = countries.find(({ name }) => name === defaultCountry) || {};
const { addressFields, customerFields, reCaptchaSettings } = registerCustomerData;

return (
<div className="mx-auto mb-10 mt-8 text-base lg:w-2/3">
<h1 className="my-6 text-4xl font-black lg:my-8 lg:text-5xl">{t('heading')}</h1>
<RegisterCustomerForm
addressFields={addressFields}
countries={countries}
customerFields={customerFields}
defaultCountry={{ entityId, code, states: statesOrProvinces ?? [] }}
reCaptchaSettings={bypassReCaptcha(reCaptchaSettings)}
/>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ export const AddressBook = ({
<p>{accountState.message}</p>
</Message>
)}
{!addressesCount && <p className="border-t py-12 text-center">{t('emptyAddresses')}</p>}
<ul className="mb-12">
{addressBook.map(
({
Expand Down
13 changes: 7 additions & 6 deletions core/components/form-fields/shared/field-wrapper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,21 @@ import { PropsWithChildren } from 'react';

import { FieldNameToFieldId } from '../utils';

const LAYOUT_SINGLE_LINE_FIELDS = [
FieldNameToFieldId.email,
FieldNameToFieldId.company,
FieldNameToFieldId.phone,
];
const LAYOUT_HALF_OF_SINGLE_LINE_FIELDS = [FieldNameToFieldId.company, FieldNameToFieldId.phone];
const LAYOUT_SINGLE_LINE_FIELDS = [FieldNameToFieldId.email];

export const FieldWrapper = ({ children, fieldId }: { fieldId: number } & PropsWithChildren) => {
if (LAYOUT_SINGLE_LINE_FIELDS.includes(fieldId)) {
if (LAYOUT_HALF_OF_SINGLE_LINE_FIELDS.includes(fieldId)) {
return (
<div className="grid grid-cols-1 gap-y-6 lg:col-span-2 lg:grid-cols-2 lg:gap-x-6 lg:gap-y-2">
{children}
</div>
);
}

if (LAYOUT_SINGLE_LINE_FIELDS.includes(fieldId)) {
return <div className="grid grid-cols-1 lg:col-span-2">{children}</div>;
}

return children;
};
Loading

0 comments on commit 53599e6

Please sign in to comment.