Skip to content

Commit 7f8f9ff

Browse files
committed
use cache
1 parent 6759421 commit 7f8f9ff

37 files changed

+768
-1220
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -36,3 +36,4 @@ yarn-error.log*
3636
# typescript
3737
*.tsbuildinfo
3838
next-env.d.ts
39+
.env*.local

app/[page]/opengraph-image.tsx

-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
import OpengraphImage from 'components/opengraph-image';
22
import { getPage } from 'lib/shopify';
33

4-
export const runtime = 'edge';
5-
64
export default async function Image({ params }: { params: { page: string } }) {
75
const page = await getPage(params.page);
86
const title = page.seo?.title || page.title;

app/globals.css

+15-4
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,17 @@
1-
@tailwind base;
2-
@tailwind components;
3-
@tailwind utilities;
1+
@import 'tailwindcss';
2+
3+
@plugin "@tailwindcss/container-queries";
4+
@plugin "@tailwindcss/typography";
5+
6+
@layer base {
7+
*,
8+
::after,
9+
::before,
10+
::backdrop,
11+
::file-selector-button {
12+
border-color: var(--color-gray-200, currentColor);
13+
}
14+
}
415

516
@media (prefers-color-scheme: dark) {
617
html {
@@ -17,5 +28,5 @@
1728
a,
1829
input,
1930
button {
20-
@apply focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-neutral-400 focus-visible:ring-offset-2 focus-visible:ring-offset-neutral-50 dark:focus-visible:ring-neutral-600 dark:focus-visible:ring-offset-neutral-900;
31+
@apply focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-neutral-400 focus-visible:ring-offset-2 focus-visible:ring-offset-neutral-50 dark:focus-visible:ring-neutral-600 dark:focus-visible:ring-offset-neutral-900;
2132
}

app/layout.tsx

+9-20
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,12 @@ import { Navbar } from 'components/layout/navbar';
33
import { WelcomeToast } from 'components/welcome-toast';
44
import { GeistSans } from 'geist/font/sans';
55
import { getCart } from 'lib/shopify';
6-
import { ensureStartsWith } from 'lib/utils';
7-
import { cookies } from 'next/headers';
86
import { ReactNode } from 'react';
97
import { Toaster } from 'sonner';
108
import './globals.css';
9+
import { baseUrl } from 'lib/utils';
1110

12-
const { TWITTER_CREATOR, TWITTER_SITE, SITE_NAME } = process.env;
13-
const baseUrl = process.env.NEXT_PUBLIC_VERCEL_URL
14-
? `https://${process.env.NEXT_PUBLIC_VERCEL_URL}`
15-
: 'http://localhost:3000';
16-
const twitterCreator = TWITTER_CREATOR ? ensureStartsWith(TWITTER_CREATOR, '@') : undefined;
17-
const twitterSite = TWITTER_SITE ? ensureStartsWith(TWITTER_SITE, 'https://') : undefined;
11+
const { SITE_NAME } = process.env;
1812

1913
export const metadata = {
2014
metadataBase: new URL(baseUrl),
@@ -25,21 +19,16 @@ export const metadata = {
2519
robots: {
2620
follow: true,
2721
index: true
28-
},
29-
...(twitterCreator &&
30-
twitterSite && {
31-
twitter: {
32-
card: 'summary_large_image',
33-
creator: twitterCreator,
34-
site: twitterSite
35-
}
36-
})
22+
}
3723
};
3824

39-
export default async function RootLayout({ children }: { children: ReactNode }) {
40-
const cartId = (await cookies()).get('cartId')?.value;
25+
export default async function RootLayout({
26+
children
27+
}: {
28+
children: ReactNode;
29+
}) {
4130
// Don't await the fetch, pass the Promise to the context provider
42-
const cart = getCart(cartId);
31+
const cart = getCart();
4332

4433
return (
4534
<html lang="en" className={GeistSans.variable}>

app/opengraph-image.tsx

-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
import OpengraphImage from 'components/opengraph-image';
22

3-
export const runtime = 'edge';
4-
53
export default async function Image() {
64
return await OpengraphImage();
75
}

app/page.tsx

+2-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@ import { ThreeItemGrid } from 'components/grid/three-items';
33
import Footer from 'components/layout/footer';
44

55
export const metadata = {
6-
description: 'High-performance ecommerce store built with Next.js, Vercel, and Shopify.',
6+
description:
7+
'High-performance ecommerce store built with Next.js, Vercel, and Shopify.',
78
openGraph: {
89
type: 'website'
910
}

app/product/[handle]/page.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ export default async function ProductPage(props: { params: Promise<{ handle: str
8080
__html: JSON.stringify(productJsonLd)
8181
}}
8282
/>
83-
<div className="mx-auto max-w-screen-2xl px-4">
83+
<div className="mx-auto max-w-(--breakpoint-2xl) px-4">
8484
<div className="flex flex-col rounded-lg border border-neutral-200 bg-white p-8 md:p-12 lg:flex-row lg:gap-8 dark:border-neutral-800 dark:bg-black">
8585
<div className="h-full w-full basis-full lg:basis-4/6">
8686
<Suspense

app/robots.ts

+1-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
1-
const baseUrl = process.env.NEXT_PUBLIC_VERCEL_URL
2-
? `https://${process.env.NEXT_PUBLIC_VERCEL_URL}`
3-
: 'http://localhost:3000';
1+
import { baseUrl } from 'lib/utils';
42

53
export default function robots() {
64
return {

app/search/[collection]/opengraph-image.tsx

+5-3
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
import OpengraphImage from 'components/opengraph-image';
22
import { getCollection } from 'lib/shopify';
33

4-
export const runtime = 'edge';
5-
6-
export default async function Image({ params }: { params: { collection: string } }) {
4+
export default async function Image({
5+
params
6+
}: {
7+
params: { collection: string };
8+
}) {
79
const collection = await getCollection(params.collection);
810
const title = collection?.seo?.title || collection?.title;
911

app/search/layout.tsx

+10-3
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,23 @@ import Collections from 'components/layout/search/collections';
33
import FilterList from 'components/layout/search/filter';
44
import { sorting } from 'lib/constants';
55
import ChildrenWrapper from './children-wrapper';
6+
import { Suspense } from 'react';
67

7-
export default function SearchLayout({ children }: { children: React.ReactNode }) {
8+
export default function SearchLayout({
9+
children
10+
}: {
11+
children: React.ReactNode;
12+
}) {
813
return (
914
<>
10-
<div className="mx-auto flex max-w-screen-2xl flex-col gap-8 px-4 pb-4 text-black md:flex-row dark:text-white">
15+
<div className="mx-auto flex max-w-(--breakpoint-2xl) flex-col gap-8 px-4 pb-4 text-black md:flex-row dark:text-white">
1116
<div className="order-first w-full flex-none md:max-w-[125px]">
1217
<Collections />
1318
</div>
1419
<div className="order-last min-h-screen w-full md:order-none">
15-
<ChildrenWrapper>{children}</ChildrenWrapper>
20+
<Suspense fallback={null}>
21+
<ChildrenWrapper>{children}</ChildrenWrapper>
22+
</Suspense>
1623
</div>
1724
<div className="order-none flex-none md:order-last md:w-[125px]">
1825
<FilterList list={sorting} title="Sort by" />

app/sitemap.ts

+4-6
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,12 @@
11
import { getCollections, getPages, getProducts } from 'lib/shopify';
2-
import { validateEnvironmentVariables } from 'lib/utils';
2+
import { baseUrl, validateEnvironmentVariables } from 'lib/utils';
33
import { MetadataRoute } from 'next';
44

55
type Route = {
66
url: string;
77
lastModified: string;
88
};
99

10-
const baseUrl = process.env.NEXT_PUBLIC_VERCEL_URL
11-
? `https://${process.env.NEXT_PUBLIC_VERCEL_URL}`
12-
: 'http://localhost:3000';
13-
1410
export const dynamic = 'force-dynamic';
1511

1612
export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
@@ -45,7 +41,9 @@ export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
4541
let fetchedRoutes: Route[] = [];
4642

4743
try {
48-
fetchedRoutes = (await Promise.all([collectionsPromise, productsPromise, pagesPromise])).flat();
44+
fetchedRoutes = (
45+
await Promise.all([collectionsPromise, productsPromise, pagesPromise])
46+
).flat();
4947
} catch (error) {
5048
throw JSON.stringify(error, null, 2);
5149
}

components/cart/actions.ts

+26-29
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,47 @@
11
'use server';
22

33
import { TAGS } from 'lib/constants';
4-
import { addToCart, createCart, getCart, removeFromCart, updateCart } from 'lib/shopify';
4+
import {
5+
addToCart,
6+
createCart,
7+
getCart,
8+
removeFromCart,
9+
updateCart
10+
} from 'lib/shopify';
511
import { revalidateTag } from 'next/cache';
612
import { cookies } from 'next/headers';
713
import { redirect } from 'next/navigation';
814

9-
export async function addItem(prevState: any, selectedVariantId: string | undefined) {
10-
let cartId = (await cookies()).get('cartId')?.value;
11-
12-
if (!cartId || !selectedVariantId) {
15+
export async function addItem(
16+
prevState: any,
17+
selectedVariantId: string | undefined
18+
) {
19+
if (!selectedVariantId) {
1320
return 'Error adding item to cart';
1421
}
1522

1623
try {
17-
await addToCart(cartId, [{ merchandiseId: selectedVariantId, quantity: 1 }]);
24+
await addToCart([{ merchandiseId: selectedVariantId, quantity: 1 }]);
1825
revalidateTag(TAGS.cart);
1926
} catch (e) {
2027
return 'Error adding item to cart';
2128
}
2229
}
2330

2431
export async function removeItem(prevState: any, merchandiseId: string) {
25-
let cartId = (await cookies()).get('cartId')?.value;
26-
27-
if (!cartId) {
28-
return 'Missing cart ID';
29-
}
30-
3132
try {
32-
const cart = await getCart(cartId);
33+
const cart = await getCart();
3334

3435
if (!cart) {
3536
return 'Error fetching cart';
3637
}
3738

38-
const lineItem = cart.lines.find((line) => line.merchandise.id === merchandiseId);
39+
const lineItem = cart.lines.find(
40+
(line) => line.merchandise.id === merchandiseId
41+
);
3942

4043
if (lineItem && lineItem.id) {
41-
await removeFromCart(cartId, [lineItem.id]);
44+
await removeFromCart([lineItem.id]);
4245
revalidateTag(TAGS.cart);
4346
} else {
4447
return 'Item not found in cart';
@@ -55,28 +58,24 @@ export async function updateItemQuantity(
5558
quantity: number;
5659
}
5760
) {
58-
let cartId = (await cookies()).get('cartId')?.value;
59-
60-
if (!cartId) {
61-
return 'Missing cart ID';
62-
}
63-
6461
const { merchandiseId, quantity } = payload;
6562

6663
try {
67-
const cart = await getCart(cartId);
64+
const cart = await getCart();
6865

6966
if (!cart) {
7067
return 'Error fetching cart';
7168
}
7269

73-
const lineItem = cart.lines.find((line) => line.merchandise.id === merchandiseId);
70+
const lineItem = cart.lines.find(
71+
(line) => line.merchandise.id === merchandiseId
72+
);
7473

7574
if (lineItem && lineItem.id) {
7675
if (quantity === 0) {
77-
await removeFromCart(cartId, [lineItem.id]);
76+
await removeFromCart([lineItem.id]);
7877
} else {
79-
await updateCart(cartId, [
78+
await updateCart([
8079
{
8180
id: lineItem.id,
8281
merchandiseId,
@@ -86,7 +85,7 @@ export async function updateItemQuantity(
8685
}
8786
} else if (quantity > 0) {
8887
// If the item doesn't exist in the cart and quantity > 0, add it
89-
await addToCart(cartId, [{ merchandiseId, quantity }]);
88+
await addToCart([{ merchandiseId, quantity }]);
9089
}
9190

9291
revalidateTag(TAGS.cart);
@@ -97,9 +96,7 @@ export async function updateItemQuantity(
9796
}
9897

9998
export async function redirectToCheckout() {
100-
let cartId = (await cookies()).get('cartId')?.value;
101-
let cart = await getCart(cartId);
102-
99+
let cart = await getCart();
103100
redirect(cart!.checkoutUrl);
104101
}
105102

components/cart/add-to-cart.tsx

+12-6
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ function SubmitButton({
2727
);
2828
}
2929

30-
console.log(selectedVariantId);
3130
if (!selectedVariantId) {
3231
return (
3332
<button
@@ -65,21 +64,28 @@ export function AddToCart({ product }: { product: Product }) {
6564
const [message, formAction] = useActionState(addItem, null);
6665

6766
const variant = variants.find((variant: ProductVariant) =>
68-
variant.selectedOptions.every((option) => option.value === state[option.name.toLowerCase()])
67+
variant.selectedOptions.every(
68+
(option) => option.value === state[option.name.toLowerCase()]
69+
)
6970
);
7071
const defaultVariantId = variants.length === 1 ? variants[0]?.id : undefined;
7172
const selectedVariantId = variant?.id || defaultVariantId;
72-
const actionWithVariant = formAction.bind(null, selectedVariantId);
73-
const finalVariant = variants.find((variant) => variant.id === selectedVariantId)!;
73+
const addItemAction = formAction.bind(null, selectedVariantId);
74+
const finalVariant = variants.find(
75+
(variant) => variant.id === selectedVariantId
76+
)!;
7477

7578
return (
7679
<form
7780
action={async () => {
7881
addCartItem(finalVariant, product);
79-
await actionWithVariant();
82+
addItemAction();
8083
}}
8184
>
82-
<SubmitButton availableForSale={availableForSale} selectedVariantId={selectedVariantId} />
85+
<SubmitButton
86+
availableForSale={availableForSale}
87+
selectedVariantId={selectedVariantId}
88+
/>
8389
<p aria-live="polite" className="sr-only" role="status">
8490
{message}
8591
</p>

0 commit comments

Comments
 (0)