From c2ff3a0f873386a72ecb28180e11f108ddb80e7a Mon Sep 17 00:00:00 2001 From: Michael Novotny Date: Fri, 14 Jul 2023 10:57:32 -0500 Subject: [PATCH] Only create cart / cookie when needed --- components/cart/actions.ts | 19 +++++++++++---- components/cart/index.tsx | 13 ++--------- components/cart/modal.tsx | 25 +++++--------------- lib/shopify/index.ts | 5 ++-- package.json | 1 - pnpm-lock.yaml | 48 ++++---------------------------------- 6 files changed, 31 insertions(+), 80 deletions(-) diff --git a/components/cart/actions.ts b/components/cart/actions.ts index 5e5f2b2ea..8188458e2 100644 --- a/components/cart/actions.ts +++ b/components/cart/actions.ts @@ -1,13 +1,24 @@ 'use server'; -import { addToCart, removeFromCart, updateCart } from 'lib/shopify'; +import { addToCart, createCart, getCart, removeFromCart, updateCart } from 'lib/shopify'; import { cookies } from 'next/headers'; export const addItem = async (variantId: string | undefined): Promise => { - const cartId = cookies().get('cartId')?.value; + let cartId = cookies().get('cartId')?.value; + let cart; - if (!cartId || !variantId) { - return new Error('Missing cartId or variantId'); + if (cartId) { + cart = await getCart(cartId); + } + + if (!cartId || !cart) { + cart = await createCart(); + cartId = cart.id; + cookies().set('cartId', cartId); + } + + if (!variantId) { + return new Error('Missing variantId'); } try { await addToCart(cartId, [{ merchandiseId: variantId, quantity: 1 }]); diff --git a/components/cart/index.tsx b/components/cart/index.tsx index 75b6978fe..3e250ba93 100644 --- a/components/cart/index.tsx +++ b/components/cart/index.tsx @@ -1,23 +1,14 @@ -import { createCart, getCart } from 'lib/shopify'; +import { getCart } from 'lib/shopify'; import { cookies } from 'next/headers'; import CartModal from './modal'; export default async function Cart() { const cartId = cookies().get('cartId')?.value; - let cartIdUpdated = false; let cart; if (cartId) { cart = await getCart(cartId); } - // If the `cartId` from the cookie is not set or the cart is empty - // (old carts becomes `null` when you checkout), then get a new `cartId` - // and re-fetch the cart. - if (!cartId || !cart) { - cart = await createCart(); - cartIdUpdated = true; - } - - return ; + return ; } diff --git a/components/cart/modal.tsx b/components/cart/modal.tsx index f07479d57..047a22957 100644 --- a/components/cart/modal.tsx +++ b/components/cart/modal.tsx @@ -9,7 +9,6 @@ import { createUrl } from 'lib/utils'; import Image from 'next/image'; import Link from 'next/link'; import { Fragment, useEffect, useRef, useState } from 'react'; -import { useCookies } from 'react-cookie'; import CloseCart from './close-cart'; import DeleteItemButton from './delete-item-button'; import EditItemQuantityButton from './edit-item-quantity-button'; @@ -19,27 +18,15 @@ type MerchandiseSearchParams = { [key: string]: string; }; -export default function CartModal({ cart, cartIdUpdated }: { cart: Cart; cartIdUpdated: boolean }) { - const [, setCookie] = useCookies(['cartId']); +export default function CartModal({ cart }: { cart: Cart | undefined }) { const [isOpen, setIsOpen] = useState(false); - const quantityRef = useRef(cart.totalQuantity); + const quantityRef = useRef(cart?.totalQuantity); const openCart = () => setIsOpen(true); const closeCart = () => setIsOpen(false); - useEffect(() => { - if (cartIdUpdated) { - setCookie('cartId', cart.id, { - path: '/', - sameSite: 'strict', - secure: process.env.NODE_ENV === 'production' - }); - } - return; - }, [setCookie, cartIdUpdated, cart.id]); - useEffect(() => { // Open cart modal when when quantity changes. - if (cart.totalQuantity !== quantityRef.current) { + if (cart && cart.totalQuantity !== quantityRef.current) { // But only if it's not already open (quantity also changes when editing items in cart). if (!isOpen) { setIsOpen(true); @@ -48,12 +35,12 @@ export default function CartModal({ cart, cartIdUpdated }: { cart: Cart; cartIdU // Always update the quantity reference quantityRef.current = cart.totalQuantity; } - }, [isOpen, cart.totalQuantity, quantityRef]); + }, [isOpen, cart?.totalQuantity, quantityRef]); return ( <> @@ -86,7 +73,7 @@ export default function CartModal({ cart, cartIdUpdated }: { cart: Cart; cartIdU - {cart.lines.length === 0 ? ( + {!cart || cart.lines.length === 0 ? (

Your cart is empty.

diff --git a/lib/shopify/index.ts b/lib/shopify/index.ts index 2e23a7f78..ec0aa19d0 100644 --- a/lib/shopify/index.ts +++ b/lib/shopify/index.ts @@ -234,15 +234,16 @@ export async function updateCart( return reshapeCart(res.body.data.cartLinesUpdate.cart); } -export async function getCart(cartId: string): Promise { +export async function getCart(cartId: string): Promise { const res = await shopifyFetch({ query: getCartQuery, variables: { cartId }, cache: 'no-store' }); + // Old carts becomes `null` when you checkout. if (!res.body.data.cart) { - return null; + return undefined; } return reshapeCart(res.body.data.cart); diff --git a/package.json b/package.json index 3a9f2061f..79f6d447f 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,6 @@ "clsx": "^1.2.1", "next": "13.4.9-canary.2", "react": "18.2.0", - "react-cookie": "^4.1.1", "react-dom": "18.2.0" }, "devDependencies": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9caed2c0a..88ee119ff 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -16,9 +16,6 @@ dependencies: react: specifier: 18.2.0 version: 18.2.0 - react-cookie: - specifier: ^4.1.1 - version: 4.1.1(react@18.2.0) react-dom: specifier: 18.2.0 version: 18.2.0(react@18.2.0) @@ -384,17 +381,6 @@ packages: tailwindcss: 3.3.2 dev: true - /@types/cookie@0.3.3: - resolution: {integrity: sha512-LKVP3cgXBT9RYj+t+9FDKwS5tdI+rPBXaNSkma7hvqy35lc7mAokC2zsqWJH0LaqIt3B962nuYI77hsJoT1gow==} - dev: false - - /@types/hoist-non-react-statics@3.3.1: - resolution: {integrity: sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==} - dependencies: - '@types/react': 18.2.14 - hoist-non-react-statics: 3.3.2 - dev: false - /@types/json5@0.0.29: resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} dev: true @@ -409,6 +395,7 @@ packages: /@types/prop-types@15.7.5: resolution: {integrity: sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==} + dev: true /@types/react-dom@18.2.6: resolution: {integrity: sha512-2et4PDvg6PVCyS7fuTc4gPoksV58bW0RwSxWKcPRcHZf0PRUGq03TKcD/rUHe3azfV6/5/biUBJw+HhCQjaP0A==} @@ -422,9 +409,11 @@ packages: '@types/prop-types': 15.7.5 '@types/scheduler': 0.16.3 csstype: 3.1.2 + dev: true /@types/scheduler@0.16.3: resolution: {integrity: sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ==} + dev: true /@typescript-eslint/parser@5.61.0(eslint@8.44.0)(typescript@5.1.3): resolution: {integrity: sha512-yGr4Sgyh8uO6fSi9hw3jAFXNBHbCtKKFMdX2IkT3ZqpKmtAq3lHS4ixB/COFuAIJpwl9/AqF7j72ZDWYKmIfvg==} @@ -890,11 +879,6 @@ packages: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} dev: true - /cookie@0.4.2: - resolution: {integrity: sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==} - engines: {node: '>= 0.6'} - dev: false - /cross-spawn@7.0.3: resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} engines: {node: '>= 8'} @@ -912,6 +896,7 @@ packages: /csstype@3.1.2: resolution: {integrity: sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==} + dev: true /damerau-levenshtein@1.0.8: resolution: {integrity: sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==} @@ -1740,12 +1725,6 @@ packages: function-bind: 1.1.1 dev: true - /hoist-non-react-statics@3.3.2: - resolution: {integrity: sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==} - dependencies: - react-is: 16.13.1 - dev: false - /hosted-git-info@2.8.9: resolution: {integrity: sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==} dev: true @@ -2711,17 +2690,6 @@ packages: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} dev: true - /react-cookie@4.1.1(react@18.2.0): - resolution: {integrity: sha512-ffn7Y7G4bXiFbnE+dKhHhbP+b8I34mH9jqnm8Llhj89zF4nPxPutxHT1suUqMeCEhLDBI7InYwf1tpaSoK5w8A==} - peerDependencies: - react: '>= 16.3.0' - dependencies: - '@types/hoist-non-react-statics': 3.3.1 - hoist-non-react-statics: 3.3.2 - react: 18.2.0 - universal-cookie: 4.0.4 - dev: false - /react-dom@18.2.0(react@18.2.0): resolution: {integrity: sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==} peerDependencies: @@ -2734,6 +2702,7 @@ packages: /react-is@16.13.1: resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} + dev: true /react@18.2.0: resolution: {integrity: sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==} @@ -3308,13 +3277,6 @@ packages: which-boxed-primitive: 1.0.2 dev: true - /universal-cookie@4.0.4: - resolution: {integrity: sha512-lbRVHoOMtItjWbM7TwDLdl8wug7izB0tq3/YVKhT/ahB4VDvWMyvnADfnJI8y6fSvsjh51Ix7lTGC6Tn4rMPhw==} - dependencies: - '@types/cookie': 0.3.3 - cookie: 0.4.2 - dev: false - /untildify@4.0.0: resolution: {integrity: sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==} engines: {node: '>=8'}