Skip to content

Commit

Permalink
feat(core): add loading state on item quantity change
Browse files Browse the repository at this point in the history
  • Loading branch information
jorgemoya committed Apr 17, 2024
1 parent 622f257 commit 726674a
Show file tree
Hide file tree
Showing 12 changed files with 274 additions and 138 deletions.
5 changes: 5 additions & 0 deletions .changeset/ninety-hornets-allow.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@bigcommerce/catalyst-core": patch
---

add loading state on item quantity update and remove when quantity equals 0
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ test-results/
playwright-report/
playwright/.cache/
graphql-env.d.ts
.DS_Store
47 changes: 47 additions & 0 deletions apps/core/app/[locale]/(default)/cart/_actions/remove-item.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
'use server';

import { revalidateTag } from 'next/cache';
import { cookies } from 'next/headers';

import { graphql } from '~/client/graphql';
import { deleteCartLineItem } from '~/client/mutations/delete-cart-line-item';

type DeleteCartLineItemInput = ReturnType<typeof graphql.scalar<'DeleteCartLineItemInput'>>;

export async function removeItem({
lineItemEntityId,
}: Omit<DeleteCartLineItemInput, 'cartEntityId'>) {
// export async function removeProduct(formData: FormData) {
try {
const cartId = cookies().get('cartId')?.value;
// const lineItemEntityId = formData.get('lineItemEntityId');

if (!cartId) {
return { status: 'error', error: 'No cartId cookie found' };
}

if (!lineItemEntityId) {
return { status: 'error', error: 'No lineItemEntityId found' };
}

const updatedCart = await deleteCartLineItem(cartId, lineItemEntityId);

// If we remove the last item in a cart the cart is deleted
// so we need to remove the cartId cookie and clear shipping data
if (!updatedCart) {
cookies().delete('cartId');
cookies().delete('shippingCosts');
revalidateTag('cart');
}

revalidateTag('cart');

return { status: 'success', data: updatedCart };
} catch (e: unknown) {
if (e instanceof Error) {
return { status: 'error', error: e.message };
}

return { status: 'error' };
}
}
32 changes: 0 additions & 32 deletions apps/core/app/[locale]/(default)/cart/_actions/remove-products.ts

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
'use server';

import { revalidatePath } from 'next/cache';
import { cookies } from 'next/headers';

import { graphql } from '~/client/graphql';
import { updateCartLineItem } from '~/client/mutations/update-cart-line-item';

import { removeItem } from './remove-item';

type CartLineItemInput = ReturnType<typeof graphql.scalar<'CartLineItemInput'>>;
type UpdateCartLineItemInput = ReturnType<typeof graphql.scalar<'UpdateCartLineItemInput'>>;

interface UpdateProductQuantityParams extends CartLineItemInput {
lineItemEntityId: UpdateCartLineItemInput['lineItemEntityId'];
}

export async function updateItemQuantity({
lineItemEntityId,
productEntityId,
quantity,
variantEntityId,
selectedOptions,
}: UpdateProductQuantityParams) {
try {
const cartId = cookies().get('cartId')?.value;

if (!cartId) {
return { status: 'error', error: 'No cartId cookie found' };
}

if (!lineItemEntityId) {
return { status: 'error', error: 'No lineItemEntityId found' };
}

if (quantity === 0) {
const result = await removeItem({ lineItemEntityId });

return result;
}

const cartLineItemData = Object.assign(
{ quantity, productEntityId },
variantEntityId && { variantEntityId },
selectedOptions && { selectedOptions },
);

const updatedCart = await updateCartLineItem(cartId, lineItemEntityId, {
lineItem: cartLineItemData,
});

if (!updatedCart) {
return { status: 'error', error: 'Failed to change product quantity in Cart' };
}

revalidatePath('/cart');

return { status: 'success', data: updatedCart };
} catch (e: unknown) {
if (e instanceof Error) {
return { status: 'error', error: e.message };
}

return { status: 'error' };
}
}

This file was deleted.

24 changes: 13 additions & 11 deletions apps/core/app/[locale]/(default)/cart/_components/cart-item.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import { getTranslations } from 'next-intl/server';
import { NextIntlClientProvider } from 'next-intl';
import { getMessages } from 'next-intl/server';

import { getCart } from '~/client/queries/get-cart';
import { ExistingResultType } from '~/client/util';
import { BcImage } from '~/components/bc-image';

import { removeProduct } from '../_actions/remove-products';

import { CartItemCounter } from './cart-item-counter';
import { RemoveFromCartButton } from './remove-from-cart-button';
import { ItemQuantity } from './item-quantity';
import { RemoveItem } from './remove-item';

export type Product =
| ExistingResultType<typeof getCart>['lineItems']['physicalItems'][number]
Expand All @@ -16,11 +15,13 @@ export type Product =
export const CartItem = async ({
currencyCode,
product,
locale,
}: {
currencyCode: string;
product: Product;
locale: string;
}) => {
const t = await getTranslations('Cart');
const messages = await getMessages({ locale });

const currencyFormatter = new Intl.NumberFormat('en-US', {
style: 'currency',
Expand Down Expand Up @@ -99,18 +100,19 @@ export const CartItem = async ({
)}
</div>

<CartItemCounter product={product} />
<NextIntlClientProvider locale={locale} messages={{ Cart: messages.Cart ?? {} }}>
<ItemQuantity product={product} />
</NextIntlClientProvider>

<div>
<p className="inline-flex w-24 justify-center text-lg font-bold">
{currencyFormatter.format(product.extendedSalePrice.value)}
</p>
</div>

<form action={removeProduct}>
<input name="lineItemEntityId" type="hidden" value={product.entityId} />
<RemoveFromCartButton label={t('removeFromCart')} spinnerLabel={t('spinnerText')} />
</form>
<NextIntlClientProvider locale={locale} messages={{ Cart: messages.Cart ?? {} }}>
<RemoveItem lineItemEntityId={product.entityId} />
</NextIntlClientProvider>
</div>
</li>
);
Expand Down
Loading

0 comments on commit 726674a

Please sign in to comment.