Skip to content

Commit

Permalink
feat(core): add delete address functionality for account
Browse files Browse the repository at this point in the history
  • Loading branch information
bc-alexsaiannyi committed Apr 30, 2024
1 parent 53428a9 commit 3ff572e
Show file tree
Hide file tree
Showing 8 changed files with 178 additions and 18 deletions.
5 changes: 5 additions & 0 deletions .changeset/grumpy-rice-bake.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@bigcommerce/catalyst-core": patch
---

Add delete address functionality for account
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,18 @@ export const Pagination = ({
const beforeSearchParams = new URLSearchParams(searchParams);

beforeSearchParams.delete('after');
beforeSearchParams.set('before', String(startCursor));

if (startCursor) {
beforeSearchParams.set('before', String(startCursor));
}

const afterSearchParams = new URLSearchParams(searchParams);

afterSearchParams.delete('before');
afterSearchParams.set('after', String(endCursor));

if (endCursor) {
afterSearchParams.set('after', String(endCursor));
}

return (
<nav aria-label="Pagination" className="my-6 text-center text-primary">
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
'use server';

import { revalidatePath } from 'next/cache';

import { deleteCustomerAddress } from '~/client/mutations/delete-customer-address';

export const deleteAddress = async (addressId: number) => {
try {
const response = await deleteCustomerAddress(addressId);

revalidatePath('/account/addresses', 'page');

if (response.errors.length === 0) {
return { status: 'success', message: 'The address has been deleted' };
}

return {
status: 'error',
message: response.errors.map((error) => error.message).join('\n'),
};
} catch (error: unknown) {
if (error instanceof Error) {
return {
status: 'error',
message: error.message,
};
}

return { status: 'error', message: 'Unknown error' };
}
};
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,24 @@ type CustomerAddresses = NonNullable<Awaited<ReturnType<typeof getCustomerAddres

interface Props {
addresses: CustomerAddresses['addresses'];
addressesCount: number;
pageInfo: CustomerAddresses['pageInfo'];
title: TabType;
}

export const AddressesContent = async ({ addresses, pageInfo, title }: Props) => {
export const AddressesContent = async ({ addresses, addressesCount, pageInfo, title }: Props) => {
const locale = await getLocale();
const tPagination = await getTranslations({ locale, namespace: 'Pagination' });
const { hasNextPage, hasPreviousPage, startCursor, endCursor } = pageInfo;

return (
<>
{tabHeading(title, locale)}
<AddressesList customerAddressBook={addresses} />
<AddressesList
addressesCount={addressesCount}
customerAddressBook={addresses}
key={endCursor}
/>
<Pagination
endCursor={endCursor}
hasNextPage={hasNextPage}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,36 +1,67 @@
'use client';

import { Button } from '@bigcommerce/components/button';
import { useTranslations } from 'next-intl';
import { useState } from 'react';

import { getCustomerAddresses } from '~/client/queries/get-customer-addresses';
import { Link } from '~/components/link';

import { deleteAddress } from '../_actions/delete-address';

import { Modal } from './modal';

type Addresses = NonNullable<Awaited<ReturnType<typeof getCustomerAddresses>>>['addresses'];

interface Props {
customerAddressBook: Addresses;
interface AddressChangeProps {
addressId: number;
isAddressRemovable: boolean;
onDelete: (state: Addresses | ((prevState: Addresses) => Addresses)) => void;
}

const AddressChangeButtons = () => {
const AddressChangeButtons = ({ addressId, isAddressRemovable, onDelete }: AddressChangeProps) => {
const t = useTranslations('Account.Addresses');

const handleDeleteAddress = async () => {
const { status } = await deleteAddress(addressId);

if (status === 'success') {
onDelete((prevAddressBook) =>
prevAddressBook.filter(({ entityId }) => entityId !== addressId),
);
}
};

return (
<div className="my-2 flex w-fit gap-x-2 divide-y-0">
<Button aria-label={t('editButton')} variant="secondary">
{t('editButton')}
</Button>
<Button aria-label={t('deleteButton')} variant="subtle">
{t('deleteButton')}
</Button>
<Modal
actionHandler={handleDeleteAddress}
confirmationText={t('confirmDeleteAddress')}
title={t('deleteModalTitle')}
>
<Button aria-label={t('deleteButton')} disabled={!isAddressRemovable} variant="subtle">
{t('deleteButton')}
</Button>
</Modal>
</div>
);
};

export const AddressesList = ({ customerAddressBook }: Props) => {
interface Props {
customerAddressBook: Addresses;
addressesCount: number;
}

export const AddressesList = ({ addressesCount, customerAddressBook }: Props) => {
const t = useTranslations('Account.Addresses');
const [addressBook, setAddressBook] = useState(customerAddressBook);

return (
<ul className="mb-12">
{customerAddressBook.map(
{addressBook.map(
({
entityId,
firstName,
Expand All @@ -57,13 +88,17 @@ export const AddressesList = ({ customerAddressBook }: Props) => {
</p>
<p>{countryCode}</p>
</div>
<AddressChangeButtons />
<AddressChangeButtons
addressId={entityId}
isAddressRemovable={addressesCount > 1}
onDelete={setAddressBook}
/>
</li>
),
)}
<li className="flex w-full border-collapse flex-col justify-start gap-2 border-t border-gray-200 pt-8">
<Button aria-label={t('addNewAddress')} asChild className="w-fit hover:text-white">
<Link href="/account/add-new-address">{t('addNewAddress')}</Link>
<Link href="/account/add-address">{t('addNewAddress')}</Link>
</Button>
</li>
</ul>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
'use client';

import { Button } from '@bigcommerce/components/button';
import {
Dialog,
DialogAction,
DialogCancel,
DialogContent,
DialogDescription,
DialogOverlay,
DialogPortal,
DialogTitle,
DialogTrigger,
} from '@bigcommerce/components/dialog';
import { X } from 'lucide-react';
import { MouseEventHandler, PropsWithChildren } from 'react';

interface Props extends PropsWithChildren {
actionHandler?: MouseEventHandler<HTMLButtonElement>;
title: string;
descriptionText?: string;
confirmationText?: string;
abortText?: string;
}

export const Modal = ({
abortText = 'Cancel',
actionHandler,
confirmationText = 'OK',
descriptionText,
title,
children,
}: Props) => {
return (
<Dialog>
<DialogTrigger aria-controls="modal-content" asChild>
{children}
</DialogTrigger>
<DialogPortal>
<DialogOverlay />
<DialogContent id="modal-content">
<div className="flex justify-between gap-4 p-6">
<DialogTitle>{title}</DialogTitle>
<DialogCancel asChild>
<Button className="ms-auto w-min p-2" type="button" variant="subtle">
<X>
<title>{abortText}</title>
</X>
</Button>
</DialogCancel>
</div>
{Boolean(descriptionText) && <DialogDescription>{descriptionText}</DialogDescription>}
<div className="flex flex-col gap-2 p-6 lg:flex-row">
<DialogAction asChild>
<Button className="w-full lg:w-fit" onClick={actionHandler} variant="primary">
{confirmationText}
</Button>
</DialogAction>
<DialogCancel asChild>
<Button className="w-full lg:w-fit" variant="subtle">
{abortText}
</Button>
</DialogCancel>
</div>
</DialogContent>
</DialogPortal>
</Dialog>
);
};
13 changes: 10 additions & 3 deletions apps/core/app/[locale]/(default)/account/[tab]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,16 @@ export default async function AccountTabPage({ params: { tab, locale }, searchPa
notFound();
}

const { addresses, pageInfo } = customerAddressesDetails;

return <AddressesContent addresses={addresses} pageInfo={pageInfo} title={tab} />;
const { addresses, pageInfo, addressesCount } = customerAddressesDetails;

return (
<AddressesContent
addresses={addresses}
addressesCount={addressesCount}
pageInfo={pageInfo}
title={tab}
/>
);
}

case 'wishlists':
Expand Down
4 changes: 3 additions & 1 deletion apps/core/messages/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,9 @@
"alternativeAddress": "Alternative",
"addNewAddress": "Add new address",
"editButton": "Edit",
"deleteButton": "Delete"
"deleteButton": "Delete",
"confirmDeleteAddress": "Delete address",
"deleteModalTitle": "Are you sure you want to delete Address"
},
"Login": {
"heading": "Log In",
Expand Down

0 comments on commit 3ff572e

Please sign in to comment.