Skip to content

Commit

Permalink
feat(core): add update customer form (#794)
Browse files Browse the repository at this point in the history
  • Loading branch information
yurytut1993 authored May 22, 2024
1 parent 6661e3e commit 956d738
Show file tree
Hide file tree
Showing 15 changed files with 509 additions and 98 deletions.
5 changes: 5 additions & 0 deletions .changeset/calm-rivers-admire.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@bigcommerce/catalyst-core": minor
---

add update customer form
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { getLocale, getTranslations } from 'next-intl/server';
import { getCustomerAddresses } from '~/client/queries/get-customer-addresses';

import { Pagination } from '../../../../(faceted)/_components/pagination';
import { TabType } from '../../layout';
import { TabHeading } from '../tab-heading';

import { AddressBook } from './address-book';
Expand All @@ -16,15 +15,13 @@ interface Props {
addressesCount: number;
customerAction?: 'add-new-address';
pageInfo: CustomerAddresses['pageInfo'];
title: TabType;
}

export const AddressesContent = async ({
addresses,
addressesCount,
customerAction,
pageInfo,
title,
}: Props) => {
const locale = await getLocale();
const t = await getTranslations({ locale, namespace: 'Account.Home' });
Expand All @@ -42,7 +39,7 @@ export const AddressesContent = async ({

return (
<>
<TabHeading heading={title} locale={locale} />
<TabHeading heading="addresses" />
<AddressBook addressesCount={addressesCount} customerAddresses={addresses} key={endCursor} />
<Pagination
endCursor={endCursor}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,30 +1,38 @@
import { NextIntlClientProvider } from 'next-intl';
import { getLocale, getMessages } from 'next-intl/server';

import { TabType } from '../layout';
import { getCustomerSettingsQuery } from '../page-data';

import { ChangePasswordForm } from './change-password-form';
import { TabHeading } from './tab-heading';
import { UpdateSettingsForm } from './update-settings-form';

interface Props {
title: TabType;
action?: string | string[];
customerSettings: CustomerSettings;
}

export const SettingsContent = async ({ title, action }: Props) => {
type CustomerSettings = NonNullable<Awaited<ReturnType<typeof getCustomerSettingsQuery>>>;

export const SettingsContent = async ({ action, customerSettings }: Props) => {
const locale = await getLocale();
const messages = await getMessages({ locale });

if (action === 'change-password') {
if (action === 'change_password') {
return (
<div className="mx-auto lg:w-2/3">
<TabHeading heading={action} locale={locale} />
<TabHeading heading={action} />
<NextIntlClientProvider locale={locale} messages={{ Account: messages.Account ?? {} }}>
<ChangePasswordForm />
</NextIntlClientProvider>
</div>
);
}

return <TabHeading heading={title} locale={locale} />;
return (
<div className="mx-auto lg:w-2/3">
<TabHeading heading="settings" />
<UpdateSettingsForm {...customerSettings} />
</div>
);
};
Original file line number Diff line number Diff line change
@@ -1,17 +1,12 @@
import { getTranslations } from 'next-intl/server';
import { getLocale, getTranslations } from 'next-intl/server';

import { TabType } from '../layout';

export const TabHeading = async ({
heading,
locale,
}: {
heading: TabType | 'change-password';
locale: string;
}) => {
export const TabHeading = async ({ heading }: { heading: TabType | 'change_password' }) => {
const locale = await getLocale();
const t = await getTranslations({ locale, namespace: 'Account.Home' });
const tab = heading === 'recently-viewed' ? 'recentlyViewed' : heading;
const title = tab === 'change-password' ? 'changePassword' : tab;
const title = tab === 'change_password' ? 'changePassword' : tab;

return <h2 className="mb-8 text-3xl font-black lg:text-4xl">{t(title)}</h2>;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
'use server';

import { updateCustomer as updateCustomerClient } from '~/client/mutations/update-customer';

interface UpdateCustomerForm {
formData: FormData;
reCaptchaToken?: string;
}

export const updateCustomer = async ({ formData, reCaptchaToken }: UpdateCustomerForm) => {
formData.delete('g-recaptcha-response');

const formFields = Object.fromEntries(formData.entries());

const response = await updateCustomerClient({ formFields, reCaptchaToken });

if (response.errors.length === 0) {
const { customer } = response;

if (!customer) {
return {
status: 'error',
error: 'Customer does not exist',
};
}

const { firstName, lastName } = customer;

return { status: 'success', data: { firstName, lastName } };
}

return {
status: 'error',
error: response.errors.map((error) => error.message).join('\n'),
};
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { useTranslations } from 'next-intl';
import { ChangeEvent } from 'react';

import { Field, FieldControl, FieldLabel, FieldMessage } from '~/components/ui/form';
import { Input } from '~/components/ui/input';

import { FieldNameToFieldId } from '..';

interface TextProps {
defaultValue?: string;
entityId: number;
isRequired?: boolean;
isValid?: boolean;
label: string;
onChange: (e: ChangeEvent<HTMLInputElement>) => void;
type?: 'text' | 'email';
}

export const Text = ({
defaultValue,
entityId,
isRequired = false,
isValid,
label,
onChange,
type = 'text',
}: TextProps) => {
const t = useTranslations('Account.Settings.validationMessages');
const fieldName = FieldNameToFieldId[entityId];
const name = fieldName ?? `field-${entityId}`;

return (
<Field className="relative space-y-2 pb-7" name={name}>
<FieldLabel htmlFor={name} isRequired={isRequired}>
{label}
</FieldLabel>
<FieldControl asChild>
<Input
defaultValue={defaultValue}
id={`field-${entityId}`}
onChange={isRequired ? onChange : undefined}
onInvalid={isRequired ? onChange : undefined}
required={isRequired}
type={type}
variant={isValid === false ? 'error' : undefined}
/>
</FieldControl>
{isRequired && (
<FieldMessage
className="absolute inset-x-0 bottom-0 inline-flex w-full text-xs font-normal text-error-secondary"
match="valueMissing"
>
{t(fieldName ?? 'empty')}
</FieldMessage>
)}
</Field>
);
};
Loading

0 comments on commit 956d738

Please sign in to comment.