Skip to content

Commit

Permalink
refactor: next 15
Browse files Browse the repository at this point in the history
  • Loading branch information
ddaoxuan committed Oct 24, 2024
1 parent 833eaee commit 1f6fb28
Show file tree
Hide file tree
Showing 46 changed files with 19,810 additions and 546 deletions.
30 changes: 18 additions & 12 deletions starters/shopify-meilisearch/app/actions/cart.actions.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,32 @@
"use server"

import { revalidateTag, unstable_cache } from "next/cache"
import { unstable_cacheTag as cacheTag, unstable_cacheLife as cacheLife } 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"

export const getCart = unstable_cache(async (cartId: string) => storefrontClient.getCart(cartId), [TAGS.CART], { revalidate: 60 * 15, tags: [TAGS.CART] })
export const getCart = async (cartId: string) => {
return storefrontClient.getCart(cartId)
}

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 }

let cartId = cookies().get(COOKIE_CART_ID)?.value
const cookieStore = await cookies()
let cartId = cookieStore.get(COOKIE_CART_ID)?.value
let cart

if (cartId) cart = await storefrontClient.getCart(cartId)

if (!cartId || !cart) {
cart = await storefrontClient.createCart([])
cartId = cart?.id
cartId && cookies().set(COOKIE_CART_ID, cartId)

revalidateTag(TAGS.CART)
if (cartId) {
await cookieStore.set(COOKIE_CART_ID, cartId)
cacheTag(TAGS.CART)
}
}

const itemAvailability = await getItemAvailability(cartId, variantId)
Expand All @@ -34,7 +38,7 @@ export async function addCartItem(prevState: any, variantId: string) {
}

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

return { ok: true }
}
Expand All @@ -49,26 +53,28 @@ export async function getItemAvailability(cartId: string | null | undefined, var
}

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

if (!cartId) return { ok: false }

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

return { ok: true }
}

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

if (!cartId) return { ok: false }

const { itemId, variantId, quantity } = payload

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

Expand All @@ -81,6 +87,6 @@ export async function updateItemQuantity(prevState: any, payload: { itemId: stri

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

revalidateTag(TAGS.CART)
cacheTag(TAGS.CART)
return { ok: true }
}
34 changes: 17 additions & 17 deletions starters/shopify-meilisearch/app/actions/collection.actions.ts
Original file line number Diff line number Diff line change
@@ -1,27 +1,27 @@
"use server"

import { unstable_cache } from "next/cache"
import { unstable_cacheTag as cacheTag, unstable_cacheLife as cacheLife } from "next/cache"
import { meilisearch } from "clients/search"
import { ComparisonOperators, FilterBuilder } from "lib/meilisearch/filter-builder"
import { getDemoSingleCategory, isDemoMode } from "utils/demo-utils"
import type { PlatformCollection } from "lib/shopify/types"
import { env } from "env.mjs"

export const getCollection = unstable_cache(
async (slug: string) => {
if (isDemoMode()) return getDemoSingleCategory(slug)
export const getCollection = async (slug: string) => {
"use cache"
cacheTag(`collection-${slug}`)
cacheLife("days")

const results = await meilisearch.searchDocuments<PlatformCollection>({
indexName: env.MEILISEARCH_CATEGORIES_INDEX,
options: {
filter: new FilterBuilder().where("handle", ComparisonOperators.Equal, slug).build(),
limit: 1,
attributesToRetrieve: ["handle", "title", "seo"],
},
})
if (isDemoMode()) return getDemoSingleCategory(slug)

return results.hits.find(Boolean) || null
},
["category-by-handle"],
{ revalidate: 3600 }
)
const results = await meilisearch.searchDocuments<PlatformCollection>({
indexName: env.MEILISEARCH_CATEGORIES_INDEX,
options: {
filter: new FilterBuilder().where("handle", ComparisonOperators.Equal, slug).build(),
limit: 1,
attributesToRetrieve: ["handle", "title", "seo"],
},
})

return results.hits.find(Boolean) || null
}
6 changes: 4 additions & 2 deletions starters/shopify-meilisearch/app/actions/favorites.actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,19 @@ import { COOKIE_FAVORITES } from "constants/index"
import { cookies } from "next/headers"

export async function toggleFavoriteProduct(prevState: any, handle: string) {
const cookieStore = await cookies()
const handles = await getParsedFavoritesHandles()
const isFavorite = handles.includes(handle)
const newFavorites = handles.includes(handle) ? handles.filter((i) => i !== handle) : [...handles, handle]

cookies().set(COOKIE_FAVORITES, JSON.stringify(newFavorites))
cookieStore.set(COOKIE_FAVORITES, JSON.stringify(newFavorites))

return !isFavorite
}

export async function getParsedFavoritesHandles() {
const favoritesCookie = cookies().get(COOKIE_FAVORITES)?.value || "[]"
const cookieStore = await cookies()
const favoritesCookie = cookieStore.get(COOKIE_FAVORITES)?.value || "[]"
const favoritesHandles = JSON.parse(favoritesCookie) as string[]
return favoritesHandles
}
18 changes: 15 additions & 3 deletions starters/shopify-meilisearch/app/actions/page.actions.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,20 @@
"use server"

import { storefrontClient } from "clients/storefrontClient"
import { unstable_cache } from "next/cache"
import { unstable_cacheTag as cacheTag, unstable_cacheLife as cacheLife } from "next/cache"

export const getPage = unstable_cache(async (handle: string) => await storefrontClient.getPage(handle), ["page"], { revalidate: 3600 })
export const getPage = async (handle: string) => {
"use cache"
cacheTag(`page-${handle}`)
cacheLife("days")

export const getAllPages = unstable_cache(async () => await storefrontClient.getAllPages(), ["page"], { revalidate: 3600 })
return await storefrontClient.getPage(handle)
}

export const getAllPages = async () => {
"use cache"
cacheTag("all-pages")
cacheLife("days")

return await storefrontClient.getAllPages()
}
140 changes: 70 additions & 70 deletions starters/shopify-meilisearch/app/actions/product.actions.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"use server"

import { unstable_cache } from "next/cache"
import { unstable_cacheLife as cacheLife, unstable_cacheTag as cacheTag } from "next/cache"
import { env } from "env.mjs"

import { meilisearch } from "clients/search"
Expand All @@ -11,74 +11,74 @@ import { getDemoProductReviews, getDemoSingleProduct, isDemoMode } from "utils/d
import type { CommerceProduct } from "types"
import { notifyOptIn } from "utils/opt-in"

export const searchProducts = unstable_cache(
async (query: string, limit: number = 4) => {
if (isDemoMode())
return {
hits: [],
hasMore: false,
}

const { hits, estimatedTotalHits } = await meilisearch.searchDocuments<CommerceProduct>({
indexName: env.MEILISEARCH_PRODUCTS_INDEX,
query,
options: {
limit,
attributesToRetrieve: ["id", "handle", "title", "featuredImage", "images", "variants"],
},
})

return { hits, hasMore: estimatedTotalHits > limit }
},
["autocomplete-search"],
{ revalidate: 3600 }
)

export const getProduct = unstable_cache(
async (handle: string) => {
if (isDemoMode()) return getDemoSingleProduct(handle)

const { results } = await meilisearch.getDocuments<CommerceProduct>({
indexName: env.MEILISEARCH_PRODUCTS_INDEX,
options: {
filter: new FilterBuilder().where("handle", ComparisonOperators.Equal, handle).build(),
limit: 1,
},
})

return results.find(Boolean) || null
},
["product-by-handle"],
{ revalidate: 3600 }
)

export const getProductReviews = unstable_cache(
async (handle: string, { page = 1, limit = 10 } = { page: 1, limit: 10 }) => {
if (isDemoMode()) return getDemoProductReviews()

if (!env.MEILISEARCH_REVIEWS_INDEX) {
notifyOptIn({ feature: "reviews", source: "product.actions.ts" })
return { reviews: [], total: 0 }
export const searchProducts = async (query: string, limit: number = 4) => {
"use cache"
cacheTag(`search-products-${query}`)
cacheLife("days")

if (isDemoMode())
return {
hits: [],
hasMore: false,
}

const { results, total } = await meilisearch.getDocuments<Review>({
indexName: env.MEILISEARCH_REVIEWS_INDEX,
options: {
filter: new FilterBuilder()
.where("product_handle", ComparisonOperators.Equal, handle)
.and()
.where("published", ComparisonOperators.Equal, "true")
.and()
.where("hidden", ComparisonOperators.Equal, "false")
.build(),
limit,
offset: (page - 1) * limit,
fields: ["body", "rating", "verified", "reviewer", "published", "created_at", "hidden", "featured"],
},
})

return { reviews: results.sort((a, b) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime()), total }
},
["product-reviews-by-handle"],
{ revalidate: 3600 }
)
const { hits, estimatedTotalHits } = await meilisearch.searchDocuments<CommerceProduct>({
indexName: env.MEILISEARCH_PRODUCTS_INDEX,
query,
options: {
limit,
attributesToRetrieve: ["id", "handle", "title", "featuredImage", "images", "variants"],
},
})

return { hits, hasMore: estimatedTotalHits > limit }
}

export const getProduct = async (handle: string) => {
"use cache"
cacheTag(`product-${handle}`)
cacheLife("days")

if (isDemoMode()) return getDemoSingleProduct(handle)

const { results } = await meilisearch.getDocuments<CommerceProduct>({
indexName: env.MEILISEARCH_PRODUCTS_INDEX,
options: {
filter: new FilterBuilder().where("handle", ComparisonOperators.Equal, handle).build(),
limit: 1,
},
})

return results.find(Boolean) || null
}

export const getProductReviews = async (handle: string, { page = 1, limit = 10 } = { page: 1, limit: 10 }) => {
"use cache"
cacheTag(`product-reviews-${handle}`)
cacheLife("days")

if (isDemoMode()) return getDemoProductReviews()

if (!env.MEILISEARCH_REVIEWS_INDEX) {
notifyOptIn({ feature: "reviews", source: "product.actions.ts" })
return { reviews: [], total: 0 }
}

const { results, total } = await meilisearch.getDocuments<Review>({
indexName: env.MEILISEARCH_REVIEWS_INDEX,
options: {
filter: new FilterBuilder()
.where("product_handle", ComparisonOperators.Equal, handle)
.and()
.where("published", ComparisonOperators.Equal, "true")
.and()
.where("hidden", ComparisonOperators.Equal, "false")
.build(),
limit,
offset: (page - 1) * limit,
fields: ["body", "rating", "verified", "reviewer", "published", "created_at", "hidden", "featured"],
},
})

return { reviews: results.sort((a, b) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime()), total }
}
3 changes: 2 additions & 1 deletion starters/shopify-meilisearch/app/actions/reviews.actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ import { headers } from "next/headers"

export const submitReview = async (payload: Omit<ProductReviewBody, "ip_addr">) => {
try {
const ipAddress = headers().get("x-forwarded-for") || null
const headersStore = await headers()
const ipAddress = headersStore.get("x-forwarded-for") || null
await reviewsClient.createProductReview({ ...payload, ip_addr: ipAddress })
} catch (err) {
throw new Error(err as string)
Expand Down
12 changes: 8 additions & 4 deletions starters/shopify-meilisearch/app/actions/user.actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,24 +11,28 @@ export async function signupUser({ email, password }: { email: string; password:
}

export async function loginUser({ email, password }: { email: string; password: string }) {
const cookieStore = await cookies()
const user = await storefrontClient.createUserAccessToken({ email, password })
cookies().set(COOKIE_ACCESS_TOKEN, user?.accessToken || "", { expires: new Date(user?.expiresAt || "") })
cookieStore.set(COOKIE_ACCESS_TOKEN, user?.accessToken || "", { expires: new Date(user?.expiresAt || "") })
return user
}

export async function getCurrentUser() {
const accessToken = cookies().get(COOKIE_ACCESS_TOKEN)?.value
const cookieStore = await cookies()
const accessToken = cookieStore.get(COOKIE_ACCESS_TOKEN)?.value
const user = await storefrontClient.getUser(accessToken || "")
return user
}

export async function updateUser(input: Pick<PlatformUserCreateInput, "firstName" | "lastName" | "phone">) {
const accessToken = cookies().get(COOKIE_ACCESS_TOKEN)?.value
const cookieStore = await cookies()
const accessToken = cookieStore.get(COOKIE_ACCESS_TOKEN)?.value

const user = await storefrontClient.updateUser(accessToken!, { ...input })
return user
}

export async function logoutUser() {
cookies().delete(COOKIE_ACCESS_TOKEN)
const cookieStore = await cookies()
cookieStore.delete(COOKIE_ACCESS_TOKEN)
}
2 changes: 0 additions & 2 deletions starters/shopify-meilisearch/app/api/redirects/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@ type RedirectEntry = {
permanent: boolean
}

export const runtime = "edge"

export function GET(request: NextRequest) {
const pathname = request.nextUrl.searchParams.get("pathname")

Expand Down
Loading

0 comments on commit 1f6fb28

Please sign in to comment.