CATALOG COMPONENT
Display the platform product catalog with stats, filters, and product cards
PREVIEW
CODE
1import { CatalogGrid } from '@/components/fanbace/catalog';2import { useCatalog } from '@/lib/sdk';3 4export default function CatalogPage() {5 const { products, loading } = useCatalog();6 7 if (loading) return <CatalogSkeleton />;8 9 return (10 <CatalogGrid11 products={products}12 onProductClick={(product) => {13 // Handle product click14 router.push(`/products/${product.id}`);15 }}16 />17 );18}PROPS
| Prop | Type | Default | Description |
|---|---|---|---|
| products | CatalogProduct[] | [] | Array of catalog products to display |
| onProductClick | (product) => void | - | Callback when product card is clicked |
| showStats | boolean | true | Show catalog statistics banner |
| loading | boolean | false | Show loading skeleton |
VARIANTS
Loading State
Empty State
Compact View (2 Products)
Grid View (3 Products)
FULL CATALOG VIEW

Gildan 5000
Heavy Cotton T-Shirt
Classic heavy cotton t-shirt, perfect for custom printing. Durable and comfortable.
6 colors • 7 sizes

Stanley/Stella Rocker
Iconic Unisex T-Shirt
The iconic unisex t-shirt. Made from organic cotton with a contemporary fit.
6 colors • 7 sizes

Gildan 18500
Heavy Blend Crewneck Sweatshirt
Classic crewneck sweatshirt with air-jet spun yarn for softer feel and no pilling.
5 colors • 6 sizes

Stanley/Stella Drummer
Essential Unisex Hoodie
The essential unisex hoodie. Made from organic cotton with brushed fleece interior.
5 colors • 6 sizes

AWDis JH030
College Hoodie
Classic college hoodie with double fabric hood and kangaroo pocket.
6 colors • 7 sizes

Stanley/Stella Roller
Essential Unisex Sweatshirt
The essential unisex sweatshirt with brushed fleece interior for extra comfort.
5 colors • 6 sizes
USAGE EXAMPLES
IN CREATOR DASHBOARD
Show catalog to creators browsing products
1function CreatorDashboard() {2 const { products } = useCatalog();3 const router = useRouter();4 5 return (6 <div className="container">7 <h1>CHOOSE A BASE PRODUCT</h1>8 9 <CatalogGrid10 products={products}11 onProductClick={(product) => {12 router.push(`/creator/design?baseProduct=${product.id}`);13 }}14 />15 </div>16 );17}WITH FILTERING
Filter catalog by category or attributes
1function FilterableCatalog() {2 const { products } = useCatalog();3 const [category, setCategory] = useState('all');4 5 const filteredProducts = category === 'all'6 ? products7 : products.filter(p => p.type === category);8 9 return (10 <div>11 <CategoryFilter12 value={category}13 onChange={setCategory}14 />15 16 <CatalogGrid products={filteredProducts} />17 </div>18 );19}WITH ANALYTICS
Track product views and interactions
1function AnalyticsCatalog() {2 const { products } = useCatalog();3 const { trackEvent } = useAnalytics();4 5 const handleProductClick = (product) => {6 trackEvent('catalog_product_viewed', {7 product_id: product.id,8 product_name: product.name,9 product_type: product.type,10 base_price: product.basePrice,11 });12 13 router.push(`/products/${product.id}`);14 };15 16 return (17 <CatalogGrid18 products={products}19 onProductClick={handleProductClick}20 />21 );22}WITH SEARCH & FILTERS
Add search and category filtering
1function SearchableCatalog() {2 const { products } = useCatalog();3 const [search, setSearch] = useState('');4 const [filters, setFilters] = useState({5 type: 'all',6 priceRange: 'all',7 });8 9 const filteredProducts = products10 .filter(p =>11 search === '' ||12 p.name.toLowerCase().includes(search.toLowerCase())13 )14 .filter(p =>15 filters.type === 'all' ||16 p.type === filters.type17 );18 19 return (20 <div className="space-y-6">21 <div className="flex gap-4">22 <Input23 placeholder="Search products..."24 value={search}25 onChange={(e) => setSearch(e.target.value)}26 />27 <Select28 value={filters.type}29 onValueChange={(v) => setFilters({...filters, type: v})}30 >31 <SelectItem value="all">All Types</SelectItem>32 <SelectItem value="T-Shirt">T-Shirts</SelectItem>33 <SelectItem value="Hoodie">Hoodies</SelectItem>34 </Select>35 </div>36 37 <CatalogGrid products={filteredProducts} />38 </div>39 );40}WITH FAVORITES
Let creators save favorite products
1function FavoriteCatalog() {2 const { products } = useCatalog();3 const { favorites, toggleFavorite } = useFavorites();4 5 const handleFavorite = (productId) => {6 toggleFavorite(productId);7 toast.success('Added to favorites!');8 };9 10 return (11 <CatalogGrid12 products={products}13 renderExtra={(product) => (14 <Button15 variant="ghost"16 size="icon"17 onClick={() => handleFavorite(product.id)}18 >19 <Heart20 className={favorites.includes(product.id) ? 'fill-red-500' : ''}21 />22 </Button>23 )}24 />25 );26}WITH LAZY LOADING
Load more products on scroll
1function InfiniteCatalog() {2 const {3 products,4 loading,5 hasMore,6 loadMore7 } = useInfiniteCatalog();8 9 useEffect(() => {10 const observer = new IntersectionObserver(11 (entries) => {12 if (entries[0].isIntersecting && hasMore && !loading) {13 loadMore();14 }15 },16 { threshold: 0.1 }17 );18 19 const sentinel = document.getElementById('catalog-sentinel');20 if (sentinel) observer.observe(sentinel);21 22 return () => observer.disconnect();23 }, [hasMore, loading]);24 25 return (26 <div>27 <CatalogGrid products={products} />28 29 {loading && <CatalogSkeleton />}30 31 <div id="catalog-sentinel" className="h-4" />32 </div>33 );34}