Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(core): improve create account form #1454

Merged
merged 3 commits into from
Oct 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading