"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 { 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, mergeFilterStateIntoSearchParams, shopFilterStateToApiArgs, } from "@/lib/shop/filterState"; import { enrichedProductToCardProps, type EnrichedProduct, } from "@/lib/shop/productMapper"; const SORT_OPTIONS: SortOption[] = [ { value: "newest", label: "Newest" }, { value: "price-asc", label: "Price: Low to High" }, { value: "price-desc", label: "Price: High to Low" }, ]; export function RecentlyAddedPage() { const router = useRouter(); const pathname = usePathname(); const searchParams = useSearchParams(); const filterState = useMemo( () => filterStateFromSearchParams(searchParams), [searchParams], ); const filterArgs = useMemo( () => shopFilterStateToApiArgs(filterState), [filterState], ); const [sort, setSort] = useState("newest"); const [filterModalOpen, setFilterModalOpen] = useState(false); const filterOptions = useQuery(api.products.getFilterOptions, { recentlyAdded: true, }); const products = useQuery(api.products.listRecentlyAdded, { ...filterArgs }); const setFilterStateToUrl = useCallback( (state: typeof filterState) => { const next = mergeFilterStateIntoSearchParams( new URLSearchParams(searchParams.toString()), state, ); const q = next.toString(); router.replace(q ? `${pathname}?${q}` : pathname); }, [pathname, router, searchParams], ); const handleApplyFiltersFromModal = useCallback( (state: typeof filterState) => { const next = mergeFilterStateIntoSearchParams( new URLSearchParams(searchParams.toString()), state, ); const q = next.toString(); router.replace(q ? `${pathname}?${q}` : pathname); setFilterModalOpen(false); }, [pathname, router, searchParams], ); const handleApplyFilter = useCallback(() => { const next = mergeFilterStateIntoSearchParams( new URLSearchParams(searchParams.toString()), filterState, ); const q = next.toString(); router.push(q ? `${pathname}?${q}` : pathname); setFilterModalOpen(false); }, [router, pathname, searchParams, filterState]); const sortedProducts = useMemo(() => { if (!products || !Array.isArray(products)) return []; const list = [...products] as EnrichedProduct[]; if (sort === "newest") { // Data is already ordered by _creationTime desc from the query list.sort((a, b) => (b.createdAt ?? 0) - (a.createdAt ?? 0)); } else if (sort === "price-asc") { list.sort((a, b) => (a.variants?.[0]?.price ?? 0) - (b.variants?.[0]?.price ?? 0)); } else if (sort === "price-desc") { list.sort((a, b) => (b.variants?.[0]?.price ?? 0) - (a.variants?.[0]?.price ?? 0)); } return list; }, [products, sort]); const handleRetry = useCallback(() => { window.location.reload(); }, []); const isLoading = products === undefined; const hasError = products === null; const isEmpty = Array.isArray(products) && products.length === 0; return (
setFilterModalOpen(true)} resultCount={Array.isArray(products) ? products.length : undefined} />
{isLoading ? ( ) : hasError ? ( ) : isEmpty ? ( ) : ( ({ ...enrichedProductToCardProps(p as EnrichedProduct), id: (p as { _id: string })._id, }))} /> )}
setFilterModalOpen(false)} onApply={handleApplyFilter} filterOptions={filterOptions ?? null} filterState={filterState} onApplyFilters={handleApplyFiltersFromModal} filterOptionsLoading={filterOptions === undefined} />
); }