Files
frontend/components/organisms/product-grid/ProductGrid.tsx
T
2026-05-14 15:57:15 +00:00

68 lines
2.2 KiB
TypeScript

"use client";
import { ProductCard } from "@/components/molecules/cards";
import { useCart } from "@/lib/cart-context";
import { useManager } from "@/lib/manager-context";
import type { ProductGridProps } from "./ProductGrid.types";
function toDisplayUrl(filename: string) {
if (!filename) return "/imgs/products/placeholder.jpg";
if (filename.startsWith("/") || filename.startsWith("http")) return filename;
return `/api/file/${filename}`;
}
export default function ProductGrid({
searchQuery = "",
isSidebarOpen = false,
}: ProductGridProps) {
const { addToCart } = useCart();
const { products } = useManager();
const filteredProducts = products.filter((p) => {
const isAvailable = p.available !== false;
const matchesSearch =
searchQuery.trim() === "" ||
p.name.toLowerCase().includes(searchQuery.toLowerCase()) ||
p.description.toLowerCase().includes(searchQuery.toLowerCase());
return isAvailable && matchesSearch;
});
const gridCols = isSidebarOpen
? "grid-cols-1 min-[480px]:grid-cols-2 lg:grid-cols-2 xl:grid-cols-3 2xl:grid-cols-4"
: "grid-cols-1 min-[480px]:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 2xl:grid-cols-5";
return (
<>
{/* ── Product grid ── */}
{filteredProducts.length > 0 ? (
<div className={`grid gap-4 ${gridCols}`}>
{filteredProducts.map(
({ id, imageUrl, name, price, description }) => (
<ProductCard
key={id}
image={toDisplayUrl(imageUrl)}
imageAlt={name}
productName={name}
price={price}
description={description}
onBuy={() => addToCart({ productId: id!, quantity: 1 })}
/>
),
)}
</div>
) : (
/* Empty state */
<div className="flex flex-col items-center justify-center gap-4 py-24 text-(--color-text-muted)">
<i className="fa-solid fa-mug-hot text-5xl opacity-30"></i>
<p className="text-base font-medium">
{searchQuery
? `Không tìm thấy món nào cho "${searchQuery}"`
: "Chưa có món trong danh mục này"}
</p>
</div>
)}
</>
);
}