Skip to content

Commit

Permalink
chore(core): fetch checkout url until click (#912)
Browse files Browse the repository at this point in the history
  • Loading branch information
deini committed May 14, 2024
1 parent d0352c0 commit 5ec3d76
Show file tree
Hide file tree
Showing 8 changed files with 84 additions and 34 deletions.
5 changes: 5 additions & 0 deletions .changeset/lazy-tools-collect.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@bigcommerce/catalyst-core": patch
---

fetch checkout redirect url when user clicks proceed to checkout button
37 changes: 37 additions & 0 deletions core/app/[locale]/(default)/cart/_actions/redirect-to-checkout.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
'use server';

import { redirect } from 'next/navigation';
import { z } from 'zod';

import { client } from '~/client';
import { graphql } from '~/client/graphql';

const CheckoutRedirectMutation = graphql(`
mutation CheckoutRedirectMutation($cartId: String!) {
cart {
createCartRedirectUrls(input: { cartEntityId: $cartId }) {
redirectUrls {
redirectedCheckoutUrl
}
}
}
}
`);

export const redirectToCheckout = async (formData: FormData) => {
const cartId = z.string().parse(formData.get('cartId'));

const { data } = await client.fetch({
document: CheckoutRedirectMutation,
variables: { cartId },
fetchOptions: { cache: 'no-store' },
});

const url = data.cart.createCartRedirectUrls.redirectUrls?.redirectedCheckoutUrl;

if (!url) {
throw new Error('Invalid checkout url.');
}

redirect(url);
};
51 changes: 28 additions & 23 deletions core/app/[locale]/(default)/cart/_components/checkout-button.tsx
Original file line number Diff line number Diff line change
@@ -1,31 +1,36 @@
import { client } from '~/client';
import { graphql } from '~/client/graphql';
import { Button } from '~/components/ui/button';
'use client';

import { Loader2 as Spinner } from 'lucide-react';
import { useTranslations } from 'next-intl';
import { useFormStatus } from 'react-dom';

export const CheckoutButtonMutation = graphql(`
mutation CheckoutButtonMutation($cartId: String!) {
cart {
createCartRedirectUrls(input: { cartEntityId: $cartId }) {
redirectUrls {
redirectedCheckoutUrl
}
}
}
}
`);
import { Button } from '~/components/ui/button';

export const CheckoutButton = async ({ cartId, label }: { cartId: string; label: string }) => {
const { data } = await client.fetch({
document: CheckoutButtonMutation,
variables: { cartId },
fetchOptions: { cache: 'no-store' },
});
import { redirectToCheckout } from '../_actions/redirect-to-checkout';

const checkoutUrl = data.cart.createCartRedirectUrls.redirectUrls?.redirectedCheckoutUrl;
const InternalButton = () => {
const t = useTranslations('Cart');
const { pending } = useFormStatus();

return (
<Button asChild className="mt-6">
<a href={checkoutUrl}>{label}</a>
<Button className="mt-6" disabled={pending}>
{pending ? (
<>
<Spinner aria-hidden="true" className="animate-spin text-primary " />
<span className="sr-only">{t('loading')}</span>
</>
) : (
t('proceedToCheckout')
)}
</Button>
);
};

export const CheckoutButton = ({ cartId }: { cartId: string }) => {
return (
<form action={redirectToCheckout}>
<input name="cartId" type="hidden" value={cartId} />
<InternalButton />
</form>
);
};
13 changes: 8 additions & 5 deletions core/app/[locale]/(default)/cart/page.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { cookies } from 'next/headers';
import { getTranslations } from 'next-intl/server';
import { Suspense } from 'react';
import { NextIntlClientProvider } from 'next-intl';
import { getMessages, getTranslations } from 'next-intl/server';

import { getSessionCustomerId } from '~/auth';
import { client } from '~/client';
Expand Down Expand Up @@ -50,7 +50,10 @@ export default async function CartPage({ params: { locale } }: Props) {
return <EmptyCart locale={locale} />;
}

const messages = await getMessages({ locale });
const Cart = messages.Cart ?? {};
const t = await getTranslations({ locale, namespace: 'Cart' });

const customerId = await getSessionCustomerId();

const { data } = await client.fetch({
Expand Down Expand Up @@ -87,9 +90,9 @@ export default async function CartPage({ params: { locale } }: Props) {
<div className="col-span-1 col-start-2 lg:col-start-3">
{checkout && <CheckoutSummary data={checkout} />}

<Suspense fallback={t('loading')}>
<CheckoutButton cartId={cartId} label={t('proceedToCheckout')} />
</Suspense>
<NextIntlClientProvider locale={locale} messages={{ Cart }}>
<CheckoutButton cartId={cartId} />
</NextIntlClientProvider>
</div>
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ export default async function RegisterCustomer({ params: { locale } }: Props) {

return (
<div className="mx-auto mb-10 mt-8 text-base lg:w-2/3">
<h1 className="my-6 my-8 text-4xl font-black lg:my-8 lg:text-5xl">{t('heading')}</h1>
<h1 className="my-6 text-4xl font-black lg:my-8 lg:text-5xl">{t('heading')}</h1>
<NextIntlClientProvider locale={locale} messages={{ Account }}>
<RegisterCustomerForm
addressFields={addressFields}
Expand Down
4 changes: 2 additions & 2 deletions core/tests/ui/desktop/e2e/cart.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ test('Edit product quantity in cart', async ({ page }) => {
await page.getByRole('link', { name: 'Cart Items 1' }).click();

await expect(page.getByRole('heading', { level: 1, name: 'Your cart' })).toBeVisible();
await expect(page.getByRole('link', { name: 'Proceed to checkout' })).toBeVisible();
await expect(page.getByRole('button', { name: 'Proceed to checkout' })).toBeVisible();

await page.getByRole('button', { name: 'Increase count' }).click();

Expand All @@ -37,7 +37,7 @@ test('Proceed to checkout', async ({ page }) => {

await expect(page.getByRole('heading', { level: 1, name: 'Your cart' })).toBeVisible();

await page.getByRole('link', { name: 'Proceed to checkout' }).click();
await page.getByRole('button', { name: 'Proceed to checkout' }).click();

await expect(page.getByRole('heading', { name: 'Order Summary', level: 3 })).toBeVisible();
await expect(page.getByRole('heading', { name: `1 x ${sampleProduct}`, level: 4 })).toBeVisible();
Expand Down
4 changes: 2 additions & 2 deletions core/tests/ui/desktop/e2e/coupon.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ test.beforeEach(async ({ page }) => {
await page.getByRole('link', { name: 'Cart Items 1' }).click();

await expect(page.getByRole('heading', { level: 1, name: 'Your cart' })).toBeVisible();
await expect(page.getByRole('link', { name: 'Proceed to checkout' })).toBeVisible();
await expect(page.getByRole('button', { name: 'Proceed to checkout' })).toBeVisible();

await page.getByRole('button', { name: 'Add' }).nth(1).click();
});
Expand Down Expand Up @@ -46,7 +46,7 @@ test('Coupon code fails', async ({ page }) => {
});

test('Apply coupon on checkout', async ({ page }) => {
await page.getByRole('link', { name: 'Proceed to checkout' }).click();
await page.getByRole('button', { name: 'Proceed to checkout' }).click();

await expect(page.getByRole('link', { name: 'Coupon/Gift Certificate' })).toBeVisible();
await expect(page.getByText('Total (USD) $225.00')).toBeVisible();
Expand Down
2 changes: 1 addition & 1 deletion core/tests/ui/mobile/checkout-experience.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ test('Checkout experience on ios mobile', async ({ page }) => {
await page.getByRole('link', { name: 'Cart Items 1' }).click();
await expect(page.getByRole('heading', { level: 1, name: 'Your cart' })).toBeVisible();

await page.getByRole('link', { name: 'Proceed to checkout' }).click();
await page.getByRole('button', { name: 'Proceed to checkout' }).click();

await page.getByLabel('Email').fill(faker.internet.email());

Expand Down

0 comments on commit 5ec3d76

Please sign in to comment.