"use client"; import { useQuery } from "convex/react"; import { usePathname, useRouter, useSearchParams } from "next/navigation"; import { useCallback, useMemo, useState } from "react"; import { api } from "../../../../../convex/_generated/api"; import { ShopBreadcrumbBar } from "@/components/shop/ShopBreadcrumbBar"; import { ShopCategoryStrip } from "@/components/shop/ShopCategoryStrip"; import { ShopFilterModal } from "@/components/shop/ShopFilterModal"; import { ShopFilterSidebar } from "@/components/shop/ShopFilterSidebar"; import { ShopPageBanner } from "@/components/shop/ShopPageBanner"; import { ShopProductGrid } from "@/components/shop/ShopProductGrid"; import { ShopToolbar, type SortOption } from "@/components/shop/ShopToolbar"; import { ShopEmptyState } from "@/components/shop/state/ShopEmptyState"; import { ShopErrorState } from "@/components/shop/state/ShopErrorState"; import { ShopProductGridSkeleton } from "@/components/shop/state/ShopProductGridSkeleton"; import { CustomerConfidenceBooster } from "@/components/sections/CustomerConfidenceBooster"; import { filterStateFromSearchParams, filterStateToSearchParams, shopFilterStateToApiArgs, } from "@/lib/shop/filterState"; import { enrichedProductToCardProps, type EnrichedProduct, } from "@/lib/shop/productMapper"; import { PET_CATEGORY_SLUGS, TOP_CATEGORY_SLUGS, } from "@/lib/shop/constants"; const SORT_OPTIONS: SortOption[] = [ { value: "newest", label: "Newest" }, { value: "price-asc", label: "Price: Low to High" }, { value: "price-desc", label: "Price: High to Low" }, ]; function formatCategoryLabel(slug: string): string { if (slug === "other-pets") return "Other Pets"; return slug.charAt(0).toUpperCase() + slug.slice(1); } export function ShopIndexContent() { const router = useRouter(); const pathname = usePathname(); const searchParams = useSearchParams(); const [sort, setSort] = useState("newest"); const [filterModalOpen, setFilterModalOpen] = useState(false); const filterState = useMemo( () => filterStateFromSearchParams(searchParams), [searchParams], ); const filterArgs = useMemo(() => shopFilterStateToApiArgs(filterState), [filterState]); const filterOptions = useQuery(api.products.getFilterOptions, {}); const products = useQuery(api.products.listActive, filterArgs); const setFilterStateToUrl = useCallback( (state: typeof filterState) => { const params = filterStateToSearchParams(state); const q = params.toString(); router.replace(q ? `${pathname}?${q}` : pathname); }, [pathname, router], ); const stripLinks = useMemo( () => [ ...PET_CATEGORY_SLUGS.map((slug) => ({ label: formatCategoryLabel(slug), href: `/shop/${slug}`, })), ...TOP_CATEGORY_SLUGS.map((slug) => ({ label: formatCategoryLabel(slug), href: `/shop/${slug}`, })), ], [], ); const sortedProducts = useMemo(() => { if (!products || !Array.isArray(products)) return []; const list = [...products] as EnrichedProduct[]; if (sort === "newest") { list.sort((a, b) => (b.createdAt ?? 0) - (a.createdAt ?? 0)); } else if (sort === "price-asc") { list.sort((a, b) => { const pa = a.variants?.[0]?.price ?? 0; const pb = b.variants?.[0]?.price ?? 0; return pa - pb; }); } else if (sort === "price-desc") { list.sort((a, b) => { const pa = a.variants?.[0]?.price ?? 0; const pb = b.variants?.[0]?.price ?? 0; return pb - pa; }); } return list; }, [products, sort]); const handleRetry = useCallback(() => { window.location.reload(); }, []); return (
{/* Top row: breadcrumb + toolbar (same row) */}
setFilterModalOpen(true)} resultCount={Array.isArray(products) ? products.length : undefined} />
{/* Two-column layout on lg: sidebar | main */}
{/* Left: filter sidebar (desktop only) */} {/* Right: category strip + product area */}
{products === undefined ? ( ) : products === null ? ( ) : Array.isArray(products) && products.length === 0 ? ( ) : ( ({ ...enrichedProductToCardProps(p as EnrichedProduct), id: (p as { _id: string })._id, }))} /> )}
{/* Filter modal (mobile/tablet only); filters apply on "Apply filter" */} setFilterModalOpen(false)} onApply={() => setFilterModalOpen(false)} filterOptions={filterOptions ?? null} filterState={filterState} onApplyFilters={setFilterStateToUrl} filterOptionsLoading={filterOptions === undefined} />
); }