import { useState, useEffect, useRef } from 'react' import { useParams, Link } from 'react-router-dom' import Navbar from '../components/Navbar' import Footer from '../components/Footer' import ProductCard from '../components/ProductCard' import { API_BASE, getCategoryImage, type Category, type Product } from '../types' export default function CategoryPage() { const { id } = useParams<{ id: string }>() const [categories, setCategories] = useState([]) const [category, setCategory] = useState(null) const [products, setProducts] = useState([]) // Local progressive rendering const [displayCount, setDisplayCount] = useState(24) const loaderRef = useRef(null) const [loading, setLoading] = useState(true) const [error, setError] = useState(null) useEffect(() => { fetch(`${API_BASE}/categories`) .then((r) => r.json()) .then(setCategories) .catch(console.error) }, []) // Reset state when category changes useEffect(() => { window.scrollTo({ top: 0, behavior: 'smooth' }) setDisplayCount(24) }, [id]) useEffect(() => { if (!id) return setLoading(true) setError(null) Promise.all([ // Fetch up to 1000 items (essentially all) in one go fetch(`${API_BASE}/categories/${id}/products?limit=1000`), fetch(`${API_BASE}/categories`), ]) .then(async ([catRes, allCatsRes]) => { if (!catRes.ok) throw new Error('Category not found') const catPaginated = await catRes.json() const allCats: Category[] = await allCatsRes.json() setCategory(catPaginated.category) setProducts(catPaginated.data || []) setCategories(allCats) }) .catch((err) => setError(err.message)) .finally(() => setLoading(false)) }, [id]) // Intersection Observer for infinite scroll useEffect(() => { const observer = new IntersectionObserver( (entries) => { if (entries[0].isIntersecting && products.length > displayCount) { setDisplayCount((prev) => Math.min(prev + 12, products.length)) } }, { threshold: 0.1, rootMargin: '200px' } // Pre-load slightly before seeing the loader ) if (loaderRef.current) { observer.observe(loaderRef.current) } return () => observer.disconnect() }, [products.length, displayCount, loading]) return (
{/* Hero Banner for category */}
{category?.name} { (e.target as HTMLImageElement).style.display = 'none' }} />
{/* Breadcrumb */}
Home / Shop / {category?.name ?? '...'}

{loading ? (
) : ( category?.name )}

{!loading && category?._count && (

{category._count.products} products available

)}
{/* Products Grid */}
{/* Other Category Pills */}
{categories.map((cat) => ( {cat.name} ))}
{error ? (

⚠️

{error}

Back to Shop
) : loading ? (
{Array.from({ length: 9 }).map((_, i) => (
))}
) : products.length === 0 ? (

🌿

No products in this category yet.

) : (
{products.slice(0, displayCount).map((p) => ( ))}
{/* Invisible target for IntersectionObserver */} {displayCount < products.length && (
)}
)}
) }