'use client'; import React, { useEffect, useMemo, useState } from 'react'; import { useParams } from 'next/navigation'; import ProductCard from './product-card'; import ProductFilters, { type ProductFilterFacet } from './product-filters'; import ProductToolbar from './product-toolbar'; import { Button } from '@/components/ui/button'; import { Loader } from '@/app/components/ui/loader'; import { getCollectionProductsPage, type CollectionSortKey, } from '@/hooks/use-shopify-collections'; import type { Product } from '@/hooks/use-shopify-products'; const PAGE_SIZE = 24; const GRID_CLASSES = 'grid grid-cols-2 lg:grid-cols-4 xl:grid-cols-5 gap-x-8 gap-y-12'; interface SortOption { label: string; sortKey: CollectionSortKey; reverse: boolean; } const SORT_OPTIONS: SortOption[] = [ { label: 'Featured', sortKey: 'COLLECTION_DEFAULT', reverse: false }, { label: 'Best Selling', sortKey: 'BEST_SELLING', reverse: false }, { label: 'Price: Low to High', sortKey: 'PRICE', reverse: false }, { label: 'Price: High to Low', sortKey: 'PRICE', reverse: true }, { label: 'Newest', sortKey: 'CREATED', reverse: true }, ]; const CollectionDetail: React.FC = () => { const params = useParams(); const handle = params?.handle as string; const [products, setProducts] = useState([]); const [filters, setFilters] = useState([]); const [title, setTitle] = useState(null); const [loading, setLoading] = useState(true); const [loadingMore, setLoadingMore] = useState(false); const [error, setError] = useState(null); const [cursor, setCursor] = useState(null); const [hasNextPage, setHasNextPage] = useState(false); const [sortIndex, setSortIndex] = useState(0); const [filtersOpen, setFiltersOpen] = useState(false); const [activeFilters, setActiveFilters] = useState([]); const sort = SORT_OPTIONS[sortIndex]; const activeKey = useMemo(() => activeFilters.join('|'), [activeFilters]); // Fall back to the handle until the collection's real title arrives. const formattedTitle = handle ? handle.replace(/-/g, ' ').replace(/\b\w/g, (l) => l.toUpperCase()) : 'Collection'; useEffect(() => { if (!handle) return; let cancelled = false; const run = async () => { try { setLoading(true); setError(null); const page = await getCollectionProductsPage(handle, { first: PAGE_SIZE, sortKey: sort.sortKey, reverse: sort.reverse, filterInputs: activeFilters, }); if (cancelled) return; if (!page.collection) { setError('Collection not found'); return; } setTitle(page.collection.title); setProducts(page.products); setCursor(page.endCursor); setHasNextPage(page.hasNextPage); // Keep the facet list stable while a selection is active, so options // don't disappear out from under the panel. if (activeFilters.length === 0) setFilters(page.filters); } catch (err) { if (cancelled) return; console.error('Error fetching collection products:', err); setError(err instanceof Error ? err.message : 'Failed to load collection'); } finally { if (!cancelled) setLoading(false); } }; run(); return () => { cancelled = true; }; }, [handle, sort.sortKey, sort.reverse, activeKey]); const handleLoadMore = async () => { if (loadingMore || !hasNextPage) return; try { setLoadingMore(true); const page = await getCollectionProductsPage(handle, { first: PAGE_SIZE, after: cursor, sortKey: sort.sortKey, reverse: sort.reverse, filterInputs: activeFilters, }); setProducts((prev) => { const seen = new Set(prev.map((p) => p.id)); return [...prev, ...page.products.filter((p) => !seen.has(p.id))]; }); setCursor(page.endCursor); setHasNextPage(page.hasNextPage); } catch (err) { console.error('Failed to load more products:', err); } finally { setLoadingMore(false); } }; return (

{title || formattedTitle}

0 ? products.length : null} onOpenFilters={() => setFiltersOpen(true)} sortOptions={SORT_OPTIONS} sortIndex={sortIndex} onSortChange={setSortIndex} activeFilterCount={activeFilters.length} />
{loading ? (
{Array.from({ length: 10 }).map((_, index) => (
))}
) : error ? (

{error}

) : products.length === 0 ? (

{activeFilters.length > 0 ? 'No products matched your filters.' : "This collection doesn't have any products yet."}

) : ( <>
{products.map((product) => ( ))}
{hasNextPage && (
)} )}
); }; export default CollectionDetail;