-
{title}
+
{title}
{!!price && (
{currency}
diff --git a/starters/shopify-algolia/views/product/review-button.tsx b/starters/shopify-algolia/app/product/_components/review-button.tsx
similarity index 66%
rename from starters/shopify-algolia/views/product/review-button.tsx
rename to starters/shopify-algolia/app/product/_components/review-button.tsx
index 9532512d..5f39476c 100644
--- a/starters/shopify-algolia/views/product/review-button.tsx
+++ b/starters/shopify-algolia/app/product/_components/review-button.tsx
@@ -1,6 +1,6 @@
"use client"
-import { Button } from "components/ui/button-old"
+import { Button } from "components/ui/button"
import { useModalStore } from "stores/modal-store"
import { useQueryState } from "nuqs"
@@ -9,14 +9,16 @@ type ReviewButtonProps = {
}
export const ReviewButton = ({ productId }: ReviewButtonProps) => {
- const open = useModalStore((s) => s.openModal)
+ const { openModal } = useModalStore()
const [_, setPid] = useQueryState("pid")
return (
+
+ )
+}
diff --git a/starters/shopify-algolia/views/product/reviews-section.tsx b/starters/shopify-algolia/app/product/_components/reviews-section.tsx
similarity index 80%
rename from starters/shopify-algolia/views/product/reviews-section.tsx
rename to starters/shopify-algolia/app/product/_components/reviews-section.tsx
index b7587565..75ff8580 100644
--- a/starters/shopify-algolia/views/product/reviews-section.tsx
+++ b/starters/shopify-algolia/app/product/_components/reviews-section.tsx
@@ -7,26 +7,26 @@ import { RobotIcon } from "components/icons/robot-icon"
import { isOptIn, notifyOptIn } from "utils/opt-in"
import { StarIcon } from "components/icons/star-icon"
import { cn } from "utils/cn"
-import { getProductReviews } from "app/actions/product.actions"
+import { buttonVariants } from "components/ui/button"
+import { getProductReviews } from "lib/algolia"
import { removeOptionsFromUrl } from "utils/product-options-utils"
type ReviewsSectionProps = {
productId: string
productHandle: string
- slug: string
avgRating: number | undefined
summary?: string
className?: string
+ slug: string
}
export const ReviewsSection = async ({ productId, productHandle, summary, avgRating, className, slug }: ReviewsSectionProps) => {
+ const { reviews, total } = await getProductReviews(removeOptionsFromUrl(slug), { limit: 16 })
if (!isOptIn("reviews")) {
notifyOptIn({ feature: "reviews", source: "components/ReviewsSection" })
return null
}
- const { reviews, total } = await getProductReviews(removeOptionsFromUrl(slug), { limit: 16 })
-
if (reviews?.length <= 0) {
return (
@@ -39,9 +39,10 @@ export const ReviewsSection = async ({ productId, productHandle, summary, avgRat
)
}
+
return (
-
+
@@ -49,11 +50,12 @@ export const ReviewsSection = async ({ productId, productHandle, summary, avgRat
({total})
{!!avgRating && (
-
+
{avgRating.toFixed(2)}
)}
+
{!!summary && (
@@ -65,21 +67,19 @@ export const ReviewsSection = async ({ productId, productHandle, summary, avgRat
{summary}
)}
-
-
-
-
-
+
+
- {reviews.map(({ body, reviewer: { name }, rating, created_at }) => (
-
+ {reviews.map(({ body, rating, created_at, reviewer: { name: author } }) => (
+
))}
+
-
+
See all reviews
diff --git a/starters/shopify-algolia/views/product/right-section.tsx b/starters/shopify-algolia/app/product/_components/right-section.tsx
similarity index 100%
rename from starters/shopify-algolia/views/product/right-section.tsx
rename to starters/shopify-algolia/app/product/_components/right-section.tsx
diff --git a/starters/shopify-algolia/views/product/side-images.tsx b/starters/shopify-algolia/app/product/_components/side-images.tsx
similarity index 100%
rename from starters/shopify-algolia/views/product/side-images.tsx
rename to starters/shopify-algolia/app/product/_components/side-images.tsx
diff --git a/starters/shopify-algolia/views/product/similar-product-section-skeleton.tsx b/starters/shopify-algolia/app/product/_components/similar-product-section-skeleton.tsx
similarity index 100%
rename from starters/shopify-algolia/views/product/similar-product-section-skeleton.tsx
rename to starters/shopify-algolia/app/product/_components/similar-product-section-skeleton.tsx
diff --git a/starters/shopify-algolia/app/product/_components/similar-products-section.tsx b/starters/shopify-algolia/app/product/_components/similar-products-section.tsx
new file mode 100644
index 00000000..7b182b52
--- /dev/null
+++ b/starters/shopify-algolia/app/product/_components/similar-products-section.tsx
@@ -0,0 +1,30 @@
+import { Carousel, CarouselContent, CarouselItem, CarouselNext, CarouselPrevious } from "components/ui/carousel"
+import { ProductCard } from "components/product-card"
+import { getSimilarProducts } from "lib/algolia"
+
+interface SimilarProductsSectionProps {
+ slug: string
+ objectID: string
+}
+
+export async function SimilarProductsSection({ slug, objectID }: SimilarProductsSectionProps) {
+ const items = await getSimilarProducts(slug, objectID)
+
+ return (
+
+
+
+ You might also like
+
+
+ {items.map((product, idx) => (
+
+
+
+ ))}
+
+
+
+
+ )
+}
diff --git a/starters/shopify-algolia/views/product/variant.tsx b/starters/shopify-algolia/app/product/_components/variant.tsx
similarity index 89%
rename from starters/shopify-algolia/views/product/variant.tsx
rename to starters/shopify-algolia/app/product/_components/variant.tsx
index f55d94c2..3fb1c529 100644
--- a/starters/shopify-algolia/views/product/variant.tsx
+++ b/starters/shopify-algolia/app/product/_components/variant.tsx
@@ -23,7 +23,7 @@ export function Variant({ singleCombination, isActive, href, cartItem }: Variant
prefetch={false}
scroll={false}
className={cn(
- "relative flex h-[40px] min-w-[80px] cursor-pointer items-center justify-center border border-black bg-white p-1.5 text-[11px] uppercase transition-colors hover:bg-neutral-800 hover:text-white",
+ "relative flex h-[40px] min-w-[80px] cursor-pointer items-center justify-center rounded-md border border-black bg-white p-1.5 text-[11px] font-medium transition-colors hover:bg-neutral-800 hover:text-white",
{ "bg-neutral-800 text-white": isActive },
{ "stroke-black opacity-80 hover:bg-transparent hover:text-black": isOutOfStock }
)}
diff --git a/starters/shopify-algolia/views/product/variants-section.tsx b/starters/shopify-algolia/app/product/_components/variants-section.tsx
similarity index 100%
rename from starters/shopify-algolia/views/product/variants-section.tsx
rename to starters/shopify-algolia/app/product/_components/variants-section.tsx
diff --git a/starters/shopify-algolia/app/reviews/[slug]/metadata.ts b/starters/shopify-algolia/app/reviews/[slug]/metadata.ts
index 32e635ae..c2c0855d 100644
--- a/starters/shopify-algolia/app/reviews/[slug]/metadata.ts
+++ b/starters/shopify-algolia/app/reviews/[slug]/metadata.ts
@@ -1,9 +1,9 @@
-import { getProduct } from "app/actions/product.actions"
-import { env } from "process"
import { makeKeywords } from "utils/make-keywords"
import { removeOptionsFromUrl } from "utils/product-options-utils"
import type { ProductReviewsPageProps } from "./page"
import { Metadata } from "next"
+import { getProduct } from "lib/algolia"
+import { env } from "env.mjs"
export async function generateMetadata({ params: { slug } }: ProductReviewsPageProps): Promise
{
const product = await getProduct(removeOptionsFromUrl(slug))
diff --git a/starters/shopify-algolia/app/reviews/[slug]/page.tsx b/starters/shopify-algolia/app/reviews/[slug]/page.tsx
index 46d950ac..e04180cb 100644
--- a/starters/shopify-algolia/app/reviews/[slug]/page.tsx
+++ b/starters/shopify-algolia/app/reviews/[slug]/page.tsx
@@ -1,13 +1,16 @@
import { notFound, redirect } from "next/navigation"
-import { getProduct, getProductReviews } from "app/actions/product.actions"
+
+import { getProduct, getProductReviews } from "lib/algolia"
+
import { Breadcrumbs } from "components/breadcrumbs"
-import { BackButton } from "views/product/back-button"
-import { StarRating } from "views/product/star-rating"
-import { PaginationSection } from "views/listing/pagination-section"
+import { BackButton } from "components/back-button"
+import { StarRating } from "components/star-rating"
+import { PaginationSection } from "components/filters/pagination-section"
import { removeOptionsFromUrl } from "utils/product-options-utils"
import type { CommerceProduct } from "types"
+import { HITS_PER_PAGE } from "constants/index"
export { generateMetadata } from "./metadata"
@@ -19,29 +22,29 @@ export interface ProductReviewsPageProps {
}
export default async function ProductReviews({ params: { slug }, searchParams }: ProductReviewsPageProps) {
- return
-}
-
-async function ProductReviewsView({ slug, searchParams }: { slug: string; searchParams: ProductReviewsPageProps["searchParams"] }) {
- const limit = 20
const page = searchParams.page ? parseInt(searchParams.page as string) : 1
- const product = await getProduct(removeOptionsFromUrl(slug))
- const { reviews, total: totalReviews } = await getProductReviews(removeOptionsFromUrl(slug), { limit, page })
+ const [product, { reviews, total: totalReviews }] = await Promise.all([
+ getProduct(removeOptionsFromUrl(slug)),
+ getProductReviews(removeOptionsFromUrl(slug), { HITS_PER_PAGE, page }),
+ ])
- const totalPages = Math.ceil(totalReviews / limit)
+ const totalPages = Math.ceil(totalReviews / HITS_PER_PAGE)
if (!product) {
return notFound()
}
+ if (page > Math.ceil(totalReviews / HITS_PER_PAGE)) {
+ redirect(`/reviews/${slug}`)
+ }
+
if (totalReviews <= 0) {
return (
-
@@ -53,10 +56,6 @@ async function ProductReviewsView({ slug, searchParams }: { slug: string; search
)
}
- if (page > Math.ceil(totalReviews / limit)) {
- redirect(`/reviews/${slug}`)
- }
-
return (
diff --git a/starters/shopify-algolia/app/search/page.tsx b/starters/shopify-algolia/app/search/page.tsx
index 7c0b1b63..6bfd7784 100644
--- a/starters/shopify-algolia/app/search/page.tsx
+++ b/starters/shopify-algolia/app/search/page.tsx
@@ -1,8 +1,8 @@
import type { Metadata } from "next"
import { Suspense } from "react"
import type { SearchParamsType } from "types"
-import { PageSkeleton } from "views/category/page-skeleton"
-import { SearchView } from "views/search/search-view"
+import { PageSkeleton } from "app/category/_components/page-skeleton"
+import { SearchView } from "components/search-view"
export const metadata: Metadata = {
title: "Search | Enterprise Commerce",
diff --git a/starters/shopify-algolia/app/settings/page.tsx b/starters/shopify-algolia/app/settings/page.tsx
deleted file mode 100644
index f2335568..00000000
--- a/starters/shopify-algolia/app/settings/page.tsx
+++ /dev/null
@@ -1,5 +0,0 @@
-import { SettingsView } from "views/settings/settings-view"
-
-export default function Settings() {
- return
-}
diff --git a/starters/shopify-algolia/app/sitemap.ts b/starters/shopify-algolia/app/sitemap.ts
index 100e3a60..197e9145 100644
--- a/starters/shopify-algolia/app/sitemap.ts
+++ b/starters/shopify-algolia/app/sitemap.ts
@@ -1,76 +1,71 @@
import { env } from "env.mjs"
import { MetadataRoute } from "next"
-import { algolia } from "clients/search"
-import { getDemoCategories, getDemoProducts, isDemoMode } from "utils/demo-utils"
-import type { PlatformCollection } from "lib/shopify/types"
-import type { CommerceProduct } from "types"
-
-export const revalidate = 604800 // once a week
-export const runtime = "nodejs"
-
-const BASE_URL = env.LIVE_URL
-const HITS_PER_PAGE = 24
+import { getCategories, getProducts } from "lib/algolia"
+import { HITS_PER_PAGE } from "constants/index"
export default async function sitemap(): Promise
{
const staticRoutes: MetadataRoute.Sitemap = [
{
- url: `${BASE_URL}/`,
+ url: `${env.LIVE_URL}/`,
lastModified: new Date(new Date().setHours(0, 0, 0, 0)),
changeFrequency: "daily",
priority: 1,
},
{
- url: `${BASE_URL}/`,
+ url: `${env.LIVE_URL}/`,
lastModified: new Date(new Date().setHours(0, 0, 0, 0)),
changeFrequency: "daily",
priority: 1,
},
{
- url: `${BASE_URL}/terms-conditions`,
+ url: `${env.LIVE_URL}/terms-conditions`,
lastModified: new Date(),
priority: 0.1,
},
{
- url: `${BASE_URL}/privacy-policy`,
+ url: `${env.LIVE_URL}/privacy-policy`,
lastModified: new Date(),
priority: 0.1,
},
]
- let allHits: CommerceProduct[] = []
- let allCollections: PlatformCollection[] = []
+ const allHits = (
+ await getProducts({
+ hitsPerPage: 50,
+ attributesToRetrieve: ["handle", "updatedAt"],
+ })
+ ).hits
- if (!isDemoMode()) {
- allHits = await getResults(env.ALGOLIA_PRODUCTS_INDEX)
- allCollections = await getResults(env.ALGOLIA_CATEGORIES_INDEX)
- } else {
- allHits = getDemoProducts().hits
- allCollections = getDemoCategories()
- }
+ const allCollections = (
+ await getCategories({
+ hitsPerPage: 50,
+ attributesToRetrieve: ["handle", "updatedAt"],
+ })
+ ).hits
- const paginationRoutes = Array.from({ length: allHits?.length / HITS_PER_PAGE }, (_, i) => {
+ const paginationRoutes = Array.from({ length: allHits.length / HITS_PER_PAGE }, (_, i) => {
const item: MetadataRoute.Sitemap[0] = {
- url: `${BASE_URL}/search?page=${i + 1}`,
+ url: `${env.LIVE_URL}/search?page=${i + 1}`,
priority: 0.5,
changeFrequency: "monthly",
}
return item
})
- const productRoutes = allHits?.map((hit) => {
+ const productRoutes = allHits.map(({ handle, updatedAt }) => {
const item: MetadataRoute.Sitemap[0] = {
- url: `${BASE_URL}/product/${hit.handle}`,
- lastModified: hit.updatedAt,
+ url: `${env.LIVE_URL}/product/${handle}`,
+ lastModified: updatedAt,
priority: 0.5,
changeFrequency: "monthly",
}
return item
})
- const collectionsRoutes = allCollections?.map((collection) => {
+ const collectionsRoutes = allCollections.map(({ handle, updatedAt }) => {
const item: MetadataRoute.Sitemap[0] = {
- url: `${BASE_URL}/category/${collection.handle}`,
- lastModified: collection.updatedAt,
+ url: `${env.LIVE_URL}/category/${handle}`,
+ lastModified: updatedAt,
priority: 0.5,
changeFrequency: "monthly",
}
@@ -79,14 +74,3 @@ export default async function sitemap(): Promise {
return [...staticRoutes, ...paginationRoutes, ...productRoutes, ...collectionsRoutes]
}
-
-async function getResults>(indexName: string) {
- const { hits } = await algolia.search({
- indexName,
- searchParams: {
- hitsPerPage: 50,
- },
- })
-
- return hits || ([] as T[])
-}
diff --git a/starters/shopify-algolia/clients/replicate.ts b/starters/shopify-algolia/clients/replicate.ts
deleted file mode 100644
index a2a3a988..00000000
--- a/starters/shopify-algolia/clients/replicate.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-import { env } from "env.mjs"
-import Replicate from "replicate"
-
-const replicateClient = () => {
- if (!env.REPLICATE_API_KEY) return null
- return new Replicate({
- auth: env.REPLICATE_API_KEY || "",
- })
-}
-
-export const replicate = replicateClient()
diff --git a/starters/shopify-algolia/clients/reviews.ts b/starters/shopify-algolia/clients/reviews.ts
deleted file mode 100644
index a83ce96c..00000000
--- a/starters/shopify-algolia/clients/reviews.ts
+++ /dev/null
@@ -1,15 +0,0 @@
-import { createJudgeClient } from "lib/reviews"
-import { env } from "env.mjs"
-import { isOptIn, notifyOptIn } from "utils/opt-in"
-
-export const reviewsClient = (() => {
- if (!isOptIn("reviews")) {
- notifyOptIn({ feature: "reviews", source: "clients/reviews" })
- }
-
- return createJudgeClient({
- baseUrl: env.JUDGE_BASE_URL!,
- apiKey: env.JUDGE_API_TOKEN!,
- shopDomain: env.SHOPIFY_STORE_DOMAIN,
- })
-})()
diff --git a/starters/shopify-algolia/clients/search.ts b/starters/shopify-algolia/clients/search.ts
deleted file mode 100644
index 0f3c4fb3..00000000
--- a/starters/shopify-algolia/clients/search.ts
+++ /dev/null
@@ -1,10 +0,0 @@
-import "server-only"
-
-import { env } from "env.mjs"
-import { algolia as searchClient } from "lib/algolia"
-
-export const algolia: ReturnType = searchClient({
- applicationId: env.ALGOLIA_APP_ID || "",
- // Make sure write api key never leaks to the client
- apiKey: env.ALGOLIA_WRITE_API_KEY || "",
-})
diff --git a/starters/shopify-algolia/clients/storefront.ts b/starters/shopify-algolia/clients/storefront.ts
deleted file mode 100644
index fd277f65..00000000
--- a/starters/shopify-algolia/clients/storefront.ts
+++ /dev/null
@@ -1,10 +0,0 @@
-import "server-only"
-
-import { createShopifyClient } from "lib/shopify"
-import { env } from "../env.mjs"
-
-export const storefrontClient = createShopifyClient({
- storeDomain: env.SHOPIFY_STORE_DOMAIN || "",
- storefrontAccessToken: env.SHOPIFY_STOREFRONT_ACCESS_TOKEN || "",
- adminAccessToken: env.SHOPIFY_ADMIN_ACCESS_TOKEN || "",
-})
diff --git a/starters/shopify-algolia/components.json b/starters/shopify-algolia/components.json
index 354ac1cb..eb80aacd 100644
--- a/starters/shopify-algolia/components.json
+++ b/starters/shopify-algolia/components.json
@@ -11,7 +11,7 @@
"prefix": ""
},
"aliases": {
- "ui": "components",
+ "ui": "components/ui",
"components": "components",
"utils": "utils"
}
diff --git a/starters/shopify-algolia/components/auth-actions.tsx b/starters/shopify-algolia/components/auth-actions.tsx
deleted file mode 100644
index 73dcf4c6..00000000
--- a/starters/shopify-algolia/components/auth-actions.tsx
+++ /dev/null
@@ -1,19 +0,0 @@
-"use client"
-
-import { Button } from "components/ui/button-old"
-import { useModalStore } from "stores/modal-store"
-
-export function AuthActions() {
- const openModal = useModalStore((s) => s.openModal)
-
- return (
-
-
-
-
- )
-}
diff --git a/starters/shopify-algolia/views/product/back-button.tsx b/starters/shopify-algolia/components/back-button.tsx
similarity index 100%
rename from starters/shopify-algolia/views/product/back-button.tsx
rename to starters/shopify-algolia/components/back-button.tsx
diff --git a/starters/shopify-algolia/components/breadcrumbs.tsx b/starters/shopify-algolia/components/breadcrumbs.tsx
index 454f7738..8a9de501 100644
--- a/starters/shopify-algolia/components/breadcrumbs.tsx
+++ b/starters/shopify-algolia/components/breadcrumbs.tsx
@@ -1,5 +1,5 @@
-import { Breadcrumb, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbSeparator } from "components/ui/breadcrumb"
import React from "react"
+import { Breadcrumb, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbSeparator } from "components/ui/breadcrumb"
import { cn } from "utils/cn"
interface BreadcrumbsProps {
@@ -20,13 +20,13 @@ export function Breadcrumbs({ items, className }: BreadcrumbsProps) {
{title}
- {!isLast && }
+ {!isLast && }
)
})}
diff --git a/starters/shopify-algolia/components/call-to-action.tsx b/starters/shopify-algolia/components/call-to-action.tsx
deleted file mode 100644
index c39ac766..00000000
--- a/starters/shopify-algolia/components/call-to-action.tsx
+++ /dev/null
@@ -1,32 +0,0 @@
-import { Button } from "components/ui/button-old"
-import { Input } from "components/ui/input"
-import { Label } from "components/ui/label"
-
-export function CallToAction() {
- return (
-
-
-
-
-
Become a member and receive our special discounts.
-
-
-
-
-
-
-
- )
-}
diff --git a/starters/shopify-algolia/views/cart/cart-item.tsx b/starters/shopify-algolia/components/cart/cart-item.tsx
similarity index 90%
rename from starters/shopify-algolia/views/cart/cart-item.tsx
rename to starters/shopify-algolia/components/cart/cart-item.tsx
index dd88f60f..514c5693 100644
--- a/starters/shopify-algolia/views/cart/cart-item.tsx
+++ b/starters/shopify-algolia/components/cart/cart-item.tsx
@@ -1,8 +1,8 @@
/* eslint-disable react/no-children-prop */
-import { PlatformCartItem } from "lib/shopify/types"
import Image from "next/image"
import Link from "next/link"
+import { PlatformCartItem } from "lib/shopify/types"
import { cn } from "utils/cn"
import { ChangeQuantityButton } from "./change-quantity-button"
import { DeleteButton } from "./delete-button"
@@ -34,9 +34,9 @@ export function CartItem(props: CartItemProps) {
diff --git a/starters/shopify-algolia/views/cart/cart-sheet.tsx b/starters/shopify-algolia/components/cart/cart-sheet.tsx
similarity index 87%
rename from starters/shopify-algolia/views/cart/cart-sheet.tsx
rename to starters/shopify-algolia/components/cart/cart-sheet.tsx
index d1161487..a870e929 100644
--- a/starters/shopify-algolia/views/cart/cart-sheet.tsx
+++ b/starters/shopify-algolia/components/cart/cart-sheet.tsx
@@ -1,12 +1,16 @@
-import { PlatformCart } from "lib/shopify/types"
+import { useRouter } from "next/navigation"
+
import { Button } from "components/ui/button-old"
import { CloseIcon } from "components/icons/close-icon"
import { Sheet, SheetClose, SheetContent, SheetFooter, SheetHeader, SheetTitle } from "components/ui/sheet"
-import { useRouter } from "next/navigation"
-import { CartItem } from "./cart-item"
-import { cn } from "utils/cn"
import { LoadingDots } from "components/loading-dots"
+import { cn } from "utils/cn"
+
+import { PlatformCart } from "lib/shopify/types"
+
+import { CartItem } from "./cart-item"
+
interface CartSheetProps {
cart: PlatformCart | null
onCartClose: () => void
@@ -25,8 +29,8 @@ export function CartSheet({ cart, isOpen, onCartClose, isPending }: CartSheetPro
return (
onCartClose()}>
-
-
+
+
Review your cart
{isPending ? : null}
@@ -39,7 +43,7 @@ export function CartSheet({ cart, isOpen, onCartClose, isPending }: CartSheetPro
{!hasAnyItems && }
-
+
{cart?.items.map((singleItem) => (
-
+
Subtotal
{subtotalFormatted}
-
+
Shipping
Calculated at checkout
-
+
diff --git a/starters/shopify-algolia/views/cart/cart-view.tsx b/starters/shopify-algolia/components/cart/cart-view.tsx
similarity index 60%
rename from starters/shopify-algolia/views/cart/cart-view.tsx
rename to starters/shopify-algolia/components/cart/cart-view.tsx
index 2fb8ab18..09b88fb3 100644
--- a/starters/shopify-algolia/views/cart/cart-view.tsx
+++ b/starters/shopify-algolia/components/cart/cart-view.tsx
@@ -1,13 +1,11 @@
"use client"
-import { getCart } from "app/actions/cart.actions"
-import { COOKIE_CART_ID } from "constants/index"
-import dynamic from "next/dynamic"
import { useEffect, useTransition } from "react"
+import dynamic from "next/dynamic"
+import { getOrCreateCart } from "app/actions/cart.actions"
import { useCartStore } from "stores/cart-store"
-import { getCookie } from "utils/get-cookie"
-const CartSheet = dynamic(() => import("views/cart/cart-sheet").then((mod) => mod.CartSheet))
+const CartSheet = dynamic(() => import("components/cart/cart-sheet").then((mod) => mod.CartSheet))
export function CartView() {
const [isPending, startTransition] = useTransition()
@@ -17,12 +15,8 @@ export function CartView() {
useEffect(() => {
startTransition(async () => {
- const cartId = getCookie(COOKIE_CART_ID)
-
- if (!cartId) return
-
- const newCart = await getCart(cartId)
- newCart && setCart(newCart)
+ const { cart } = await getOrCreateCart()
+ cart && setCart(cart)
})
}, [lastUpdatedAt, setCart])
diff --git a/starters/shopify-algolia/views/cart/change-quantity-button.tsx b/starters/shopify-algolia/components/cart/change-quantity-button.tsx
similarity index 90%
rename from starters/shopify-algolia/views/cart/change-quantity-button.tsx
rename to starters/shopify-algolia/components/cart/change-quantity-button.tsx
index bbff38db..f4158e07 100644
--- a/starters/shopify-algolia/views/cart/change-quantity-button.tsx
+++ b/starters/shopify-algolia/components/cart/change-quantity-button.tsx
@@ -1,23 +1,25 @@
-import { updateItemQuantity } from "app/actions/cart.actions"
-import { Spinner } from "components/spinner"
import { useTransition } from "react"
import { toast } from "sonner"
+
+import { updateItemQuantity } from "app/actions/cart.actions"
+import { Spinner } from "components/spinner"
import { useCartStore } from "stores/cart-store"
interface ChangeQuantityButtonProps {
id: string
variantId: string
quantity: number
+ productId: string
children: React.ReactNode
}
-export function ChangeQuantityButton({ id, variantId, quantity, children }: ChangeQuantityButtonProps) {
+export function ChangeQuantityButton({ id, variantId, quantity, productId, children }: ChangeQuantityButtonProps) {
const refresh = useCartStore((prev) => prev.refresh)
const [isPending, startTransition] = useTransition()
const handleClick = () => {
startTransition(async () => {
- const { ok, message } = await updateItemQuantity(null, { itemId: id, variantId, quantity })
+ const { ok, message } = await updateItemQuantity(null, { itemId: id, variantId, quantity, productId })
if (!ok && message) {
toast.warning(message)
diff --git a/starters/shopify-algolia/views/cart/delete-button.tsx b/starters/shopify-algolia/components/cart/delete-button.tsx
similarity index 99%
rename from starters/shopify-algolia/views/cart/delete-button.tsx
rename to starters/shopify-algolia/components/cart/delete-button.tsx
index 28fedf8a..6dcdb5ff 100644
--- a/starters/shopify-algolia/views/cart/delete-button.tsx
+++ b/starters/shopify-algolia/components/cart/delete-button.tsx
@@ -1,6 +1,7 @@
+import { useTransition } from "react"
+
import { removeCartItem } from "app/actions/cart.actions"
import { LoadingDots } from "components/loading-dots"
-import { useTransition } from "react"
import { useCartStore } from "stores/cart-store"
import { cn } from "utils/cn"
diff --git a/starters/shopify-algolia/components/category-card.tsx b/starters/shopify-algolia/components/category-card.tsx
new file mode 100644
index 00000000..2546e0db
--- /dev/null
+++ b/starters/shopify-algolia/components/category-card.tsx
@@ -0,0 +1,32 @@
+import Image from "next/image"
+import Link from "next/link"
+import { PlatformCollection } from "lib/shopify/types"
+import { cn } from "utils/cn"
+
+interface CategoryCardProps extends Pick
{
+ index: number
+ className?: string
+}
+
+export const CategoryCard = ({ handle, image, title, index, className }: CategoryCardProps) => {
+ const href = `/category/${handle}`
+ return (
+
+
+
+
{title}
+
+
+ )
+}
diff --git a/starters/shopify-algolia/components/compact-product-card.tsx b/starters/shopify-algolia/components/compact-product-card.tsx
new file mode 100644
index 00000000..5fe9bb38
--- /dev/null
+++ b/starters/shopify-algolia/components/compact-product-card.tsx
@@ -0,0 +1,79 @@
+import Image from "next/image"
+import Link from "next/link"
+import { cn } from "utils/cn"
+import { type CurrencyType, mapCurrencyToSign } from "utils/map-currency-to-sign"
+import type { CommerceProduct } from "types"
+import { StarIcon } from "components/icons/star-icon"
+
+interface ProductCardProps extends Pick {
+ priority?: boolean
+ prefetch?: boolean
+ className?: string
+}
+
+export const CompactProductCard = ({
+ variants,
+ handle,
+ title,
+ featuredImage,
+ minPrice,
+ avgRating,
+ totalReviews,
+ className,
+ priority,
+ vendor,
+ prefetch = false,
+}: ProductCardProps) => {
+ const noOfVariants = variants?.length
+ const href = `/product/${handle}`
+ const linkAria = `Visit product: ${title}`
+ const variantPrice = variants?.find(Boolean)?.price
+
+ return (
+
+
+
+
+
+ {/* remove first word from the title as it includes vendor (this just needs feed update and then can be removed) */}
+
{title.split(" ").slice(1).join(" ")}
+
+ {!!variantPrice &&
From {mapCurrencyToSign((variantPrice.currencyCode as CurrencyType) || "USD") + minPrice.toFixed(2)}}
+
+ {!!vendor &&
{vendor}
}
+
+
+ {!!avgRating && !!totalReviews && (
+ <>
+
+
+ {avgRating.toFixed(2)}
+
+ ({totalReviews} review{totalReviews !== 1 && "s"})
+
+
+ •
+ >
+ )}
+ {noOfVariants > 0 && (
+
+ {noOfVariants} variant{noOfVariants > 1 ? "s" : ""}
+
+ )}
+
+
+
+
+ )
+}
diff --git a/starters/shopify-algolia/views/demo-mode-alert.tsx b/starters/shopify-algolia/components/demo-mode-alert.tsx
similarity index 100%
rename from starters/shopify-algolia/views/demo-mode-alert.tsx
rename to starters/shopify-algolia/components/demo-mode-alert.tsx
diff --git a/starters/shopify-algolia/views/draft-toolbar.tsx b/starters/shopify-algolia/components/draft-toolbar.tsx
similarity index 52%
rename from starters/shopify-algolia/views/draft-toolbar.tsx
rename to starters/shopify-algolia/components/draft-toolbar.tsx
index ae61b476..cf814966 100644
--- a/starters/shopify-algolia/views/draft-toolbar.tsx
+++ b/starters/shopify-algolia/components/draft-toolbar.tsx
@@ -2,10 +2,16 @@
import { VercelToolbar } from "@vercel/toolbar/next"
import { usePathname } from "next/navigation"
+import { useEffect, useState } from "react"
export default function DraftToolbar() {
+ const [hasToolbarHash, setHasToolbarHash] = useState(false)
const pathname = usePathname()
- const hasToolbarHash = window.location.hash === "#toolbar"
+
+ useEffect(() => {
+ if (typeof window === "undefined") return
+ setHasToolbarHash(window.location.hash === "#toolbar")
+ }, [pathname])
return pathname.endsWith("/draft") || hasToolbarHash ? : null
}
diff --git a/starters/shopify-algolia/components/expandable-content.tsx b/starters/shopify-algolia/components/expandable-content.tsx
index f43d66d4..66b252a7 100644
--- a/starters/shopify-algolia/components/expandable-content.tsx
+++ b/starters/shopify-algolia/components/expandable-content.tsx
@@ -42,7 +42,7 @@ export const ExpandableContent = ({ children, className, lines = 2 }: Expandable
{children}
{isClamped && (
-