"use client"; import { useState, useEffect, useMemo } from "react"; import { Card } from "@/components/ui/card"; import { Input } from "@/components/ui/input"; import { Button } from "@/components/ui/button"; import { formatCurrency, cn } from "@/lib/utils"; interface Category { id: string; name: string; description: string | null; _count: { products: number; }; } interface Product { id: string; name: string; description: string | null; sku: string | null; price: number; stock: number; minStock: number; trackStock: boolean; image: string | null; lowStock: boolean; category: { id: string; name: string; }; } interface ProductGridProps { siteId: string; onAddToCart: (product: Product) => void; } export function ProductGrid({ siteId, onAddToCart }: ProductGridProps) { const [products, setProducts] = useState([]); const [categories, setCategories] = useState([]); const [selectedCategory, setSelectedCategory] = useState(null); const [searchQuery, setSearchQuery] = useState(""); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); // Fetch categories useEffect(() => { async function fetchCategories() { try { const response = await fetch("/api/products/categories"); if (!response.ok) { throw new Error("Error al cargar categorias"); } const data = await response.json(); setCategories(data); } catch (err) { console.error("Error fetching categories:", err); } } fetchCategories(); }, []); // Fetch products useEffect(() => { async function fetchProducts() { setLoading(true); setError(null); try { const params = new URLSearchParams({ siteId, isActive: "true" }); if (selectedCategory) { params.append("categoryId", selectedCategory); } if (searchQuery) { params.append("search", searchQuery); } const response = await fetch(`/api/products?${params.toString()}`); if (!response.ok) { throw new Error("Error al cargar productos"); } const data = await response.json(); setProducts(data); } catch (err) { setError(err instanceof Error ? err.message : "Error desconocido"); } finally { setLoading(false); } } // Debounce search const timeoutId = setTimeout(fetchProducts, searchQuery ? 300 : 0); return () => clearTimeout(timeoutId); }, [siteId, selectedCategory, searchQuery]); // Filter products based on category and search const filteredProducts = useMemo(() => { return products; }, [products]); const handleProductClick = (product: Product) => { if (product.trackStock && product.stock <= 0) { return; // Cannot add out of stock products } onAddToCart(product); }; return (
{/* Search Input */}
setSearchQuery(e.target.value)} className="w-full" />
{/* Category Tabs */}
{categories.map((category) => ( ))}
{/* Loading State */} {loading && (

Cargando productos...

)} {/* Error State */} {error && !loading && (

{error}

)} {/* Empty State */} {!loading && !error && filteredProducts.length === 0 && (

No se encontraron productos

{searchQuery && ( )}
)} {/* Product Grid */} {!loading && !error && filteredProducts.length > 0 && (
{filteredProducts.map((product) => { const isOutOfStock = product.trackStock && product.stock <= 0; const isLowStock = product.lowStock; return ( handleProductClick(product)} > {/* Product Image Placeholder */} {product.image ? (
{product.name}
) : (
{product.name.charAt(0).toUpperCase()}
)} {/* Product Info */}

{product.name}

{formatCurrency(product.price)}

{/* Stock Indicator */} {product.trackStock && (
{isOutOfStock ? ( Agotado ) : isLowStock ? ( Stock bajo: {product.stock} ) : ( Stock: {product.stock} )}
)}
); })}
)}
); }