Skip to content

Commit

Permalink
refactor: move storefront lib
Browse files Browse the repository at this point in the history
  • Loading branch information
ddaoxuan committed Oct 31, 2024
1 parent be94644 commit a28b955
Show file tree
Hide file tree
Showing 15 changed files with 394 additions and 337 deletions.
103 changes: 67 additions & 36 deletions starters/shopify-meilisearch/app/actions/cart.actions.ts
Original file line number Diff line number Diff line change
@@ -1,86 +1,117 @@
"use server"

import { revalidateTag, unstable_cache } from "next/cache"
import { revalidateTag } from "next/cache"
import { cookies } from "next/headers"
import { storefrontClient } from "clients/storefrontClient"
import { COOKIE_CART_ID, TAGS } from "constants/index"
import { isDemoMode } from "utils/demo-utils"
import { createCart, createCartItem, deleteCartItem, getCart, getProduct, updateCartItem } from "lib/shopify"

export const getCart = unstable_cache(async (cartId: string) => storefrontClient.getCart(cartId), [TAGS.CART], { revalidate: 60 * 15, tags: [TAGS.CART] })
export async function getOrCreateCart() {
const cartId = cookies().get(COOKIE_CART_ID)?.value
const cart = cartId ? await getCart(cartId) : await createCart()

export async function addCartItem(prevState: any, variantId: string) {
if (isDemoMode()) return { ok: false, message: "Demo mode active. Filtering, searching, and adding to cart disabled." }
if (!variantId) return { ok: false }
if (!cartId) {
const newCartId = cart?.id
if (newCartId) {
cookies().set(COOKIE_CART_ID, newCartId)
revalidateTag(TAGS.CART)
}
}

let cartId = cookies().get(COOKIE_CART_ID)?.value
let cart
return { cartId: cart?.id, cart }
}

if (cartId) cart = await storefrontClient.getCart(cartId)
export async function getItemAvailability({
cartId,
variantId,
productId,
}: {
cartId: string | null | undefined
variantId: string | null | undefined
productId: string | null | undefined
}) {
if (!variantId) {
return { inCartQuantity: 0, inStockQuantity: 0 }
}

if (!cartId || !cart) {
cart = await storefrontClient.createCart([])
cartId = cart?.id
cartId && cookies().set(COOKIE_CART_ID, cartId)
if (!cartId) {
const product = await getProduct(productId!)
const inStockQuantity = product?.variants?.find((variant) => variant.id === variantId)?.quantityAvailable ?? Infinity
return {
inCartQuantity: 0,
inStockQuantity,
}
}

revalidateTag(TAGS.CART)
const cart = await getCart(cartId)
const cartItem = cart?.items?.find((item) => item.merchandise.id === variantId)

return {
inCartQuantity: cartItem?.quantity ?? 0,
inStockQuantity: cartItem?.merchandise.quantityAvailable ?? Infinity,
}
}

const itemAvailability = await getItemAvailability(cartId, variantId)
export async function addCartItem(prevState: any, variantId: string, productId: string) {
if (isDemoMode()) {
return {
ok: false,
message: "Demo mode active. Filtering, searching, and adding to cart disabled.",
}
}

if (!itemAvailability || itemAvailability.inCartQuantity >= itemAvailability.inStockQuantity)
if (!variantId) return { ok: false }

const { cartId } = await getOrCreateCart()

if (!cartId) return { ok: false }

const availability = await getItemAvailability({ cartId, variantId, productId })
if (!availability || availability.inCartQuantity >= availability.inStockQuantity) {
return {
ok: false,
message: "This product is out of stock",
}
}

await storefrontClient.createCartItem(cartId!, [{ merchandiseId: variantId, quantity: 1 }])
await createCartItem(cartId, [{ merchandiseId: variantId, quantity: 1 }])
revalidateTag(TAGS.CART)

return { ok: true }
}

export async function getItemAvailability(cartId: string | null | undefined, variantId: string | null | undefined) {
if (!cartId || !variantId) return { inCartQuantity: 0, inStockQuantity: Infinity }

const cart = await storefrontClient.getCart(cartId)
const cartItem = cart?.items?.find((item) => item.merchandise.id === variantId)

return { inCartQuantity: cartItem?.quantity ?? 0, inStockQuantity: cartItem?.merchandise.quantityAvailable ?? Infinity }
}

export async function removeCartItem(prevState: any, itemId: string) {
const cartId = cookies().get(COOKIE_CART_ID)?.value

if (!cartId) return { ok: false }

await storefrontClient.deleteCartItem(cartId!, [itemId])
await deleteCartItem(cartId, [itemId])
revalidateTag(TAGS.CART)

return { ok: true }
}

export async function updateItemQuantity(prevState: any, payload: { itemId: string; variantId: string; quantity: number }) {
export async function updateItemQuantity(prevState: any, payload: { itemId: string; variantId: string; quantity: number; productId: string }) {
const cartId = cookies().get(COOKIE_CART_ID)?.value

if (!cartId) return { ok: false }

const { itemId, variantId, quantity } = payload
const { itemId, variantId, quantity, productId } = payload

if (quantity === 0) {
await storefrontClient.deleteCartItem(cartId, [itemId])
await deleteCartItem(cartId, [itemId])
revalidateTag(TAGS.CART)
return { ok: true }
}

const itemAvailability = await getItemAvailability(cartId, variantId)
if (!itemAvailability || quantity > itemAvailability.inStockQuantity)
const itemAvailability = await getItemAvailability({ cartId, variantId, productId })
if (!itemAvailability || quantity > itemAvailability.inStockQuantity) {
return {
ok: false,
message: "This product is out of stock",
}
}

await storefrontClient.updateCartItem(cartId, [{ id: itemId, merchandiseId: variantId, quantity }])

await updateCartItem(cartId, [{ id: itemId, merchandiseId: variantId, quantity }])
revalidateTag(TAGS.CART)

return { ok: true }
}
8 changes: 4 additions & 4 deletions starters/shopify-meilisearch/app/api/feed/sync/route.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import type { PlatformProduct } from "lib/shopify/types"
import { storefrontClient } from "clients/storefrontClient"
import { env } from "env.mjs"
import { compareHmac } from "utils/compare-hmac"
import { enrichProduct } from "utils/enrich-product"
import { deleteCategories, deleteProducts, updateCategories, updateProducts } from "lib/meilisearch"
import { getCollection, getHierarchicalCollections, getProduct } from "lib/shopify"

type SupportedTopic = "products/update" | "products/delete" | "products/create" | "collections/update" | "collections/delete" | "collections/create"

Expand Down Expand Up @@ -49,7 +49,7 @@ async function handleCollectionTopics(topic: SupportedTopic, { id }: Record<stri
switch (topic) {
case "collections/update":
case "collections/create":
const collection = await storefrontClient.getCollectionById(makeShopifyId(`${id}`, "Collection"))
const collection = await getCollection(makeShopifyId(`${id}`, "Collection"))
if (!collection) {
console.error(`Collection ${id} not found`)
return new Response(JSON.stringify({ message: "Collection not found" }), { status: 404, headers: { "Content-Type": "application/json" } })
Expand All @@ -74,8 +74,8 @@ async function handleProductTopics(topic: SupportedTopic, { id }: Record<string,
switch (topic) {
case "products/update":
case "products/create":
const product = await storefrontClient.getProduct(makeShopifyId(`${id}`, "Product"))
const items = env.SHOPIFY_HIERARCHICAL_NAV_HANDLE ? (await storefrontClient.getHierarchicalCollections(env.SHOPIFY_HIERARCHICAL_NAV_HANDLE)).items : []
const product = await getProduct(makeShopifyId(`${id}`, "Product"))
const items = env.SHOPIFY_HIERARCHICAL_NAV_HANDLE ? (await getHierarchicalCollections(env.SHOPIFY_HIERARCHICAL_NAV_HANDLE)).items : []

if (!product) {
console.error(`Product ${id} not found`)
Expand Down
2 changes: 1 addition & 1 deletion starters/shopify-meilisearch/app/pages/[slug]/metadata.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { getPage } from "clients/storefrontClient"
import { getPage } from "lib/shopify"
import { Metadata } from "next"

export async function generateMetadata({ params: { slug } }: { params: { slug: string } }): Promise<Metadata> {
Expand Down
2 changes: 1 addition & 1 deletion starters/shopify-meilisearch/app/pages/[slug]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { format } from "date-fns/format"
import { getAllPages, getPage } from "clients/storefrontClient"
import { getAllPages, getPage } from "lib/shopify"

export const revalidate = 86400
export const dynamic = "force-static"
Expand Down
10 changes: 4 additions & 6 deletions starters/shopify-meilisearch/app/product/[slug]/draft/page.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { unstable_cache } from "next/cache"
import { Suspense } from "react"
import { draftMode } from "next/headers"
import { notFound } from "next/navigation"
import { Suspense } from "react"
import { storefrontClient } from "clients/storefrontClient"
import type { CommerceProduct } from "types"

import { Breadcrumbs } from "components/breadcrumbs"

import { getAdminProduct, getProductByHandle } from "lib/shopify"
import type { PlatformProduct } from "lib/shopify/types"

import { getCombination, getOptionsFromUrl, hasValidOption, removeOptionsFromUrl } from "utils/product-options-utils"
import { BackButton } from "views/product/back-button"
import { SimilarProductsSection } from "views/product/similar-products-section"
Expand Down Expand Up @@ -95,14 +95,12 @@ async function ProductView({ slug }: { slug: string }) {
async function getDraftAwareProduct(slug: string) {
const draft = draftMode()

let product = await storefrontClient.getProductByHandle(removeOptionsFromUrl(slug))
let product = await getProductByHandle(removeOptionsFromUrl(slug))
if (draft.isEnabled && product) product = await getAdminProduct(product?.id)

return product
}

const getAdminProduct = unstable_cache(async (id: string) => storefrontClient.getAdminProduct(id), ["admin-product-by-handle"], { revalidate: 1 })

function makeBreadcrumbs(product: PlatformProduct) {
const lastCollection = product.collections?.findLast(Boolean)

Expand Down
15 changes: 0 additions & 15 deletions starters/shopify-meilisearch/clients/storefrontClient.ts

This file was deleted.

Loading

0 comments on commit a28b955

Please sign in to comment.