Files
reui-blocks/blocks/compare-products2.tsx
T

218 lines
7.1 KiB
TypeScript

"use client";
import { Check, X as XIcon } from "lucide-react";
import { AspectRatio } from "@/components/ui/aspect-ratio";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@/components/ui/table";
import { cn } from "@/lib/utils";
interface ProductSpec {
name: string;
values: (string | boolean)[];
}
interface Product {
id: string;
name: string;
image: string;
price: number;
originalPrice?: number;
rating: number;
badge?: string;
}
interface CompareProducts2Props {
products?: Product[];
specs?: ProductSpec[];
className?: string;
}
const DEFAULT_PRODUCTS: Product[] = [
{
id: "1",
name: "هدفون بی‌سیم پرو",
image:
"/block-media/shadcnblocks/block/ecommerce/electronics/Modern-White-Headphones-1.png",
price: 299,
rating: 4.8,
},
{
id: "2",
name: "هدفون استودیویی پلاس",
image:
"/block-media/shadcnblocks/block/ecommerce/electronics/Sleek-Black-Headphones-1.jpeg",
price: 249,
originalPrice: 279,
rating: 4.5,
},
];
const DEFAULT_SPECS: ProductSpec[] = [
{ name: "اندازه درایور", values: ["۴۰ میلی‌متر", "۵۰ میلی‌متر"] },
{
name: "پاسخ فرکانسی",
values: ["۲۰Hz–۲۰kHz", "۱۰Hz–۴۰kHz"],
},
{ name: "حذف نویز فعال", values: [true, true] },
{ name: "عمر باتری", values: ["۳۰ ساعت", "۲۴ ساعت"] },
{ name: "بی‌سیم", values: [true, true] },
{ name: "نسخه بلوتوث", values: ["۵٫۳", "۵٫۲"] },
{ name: "طراحی تاشو", values: [true, false] },
{ name: "وزن", values: ["۲۵۰ گرم", "۲۸۰ گرم"] },
{ name: "کیف همراه", values: [true, true] },
{ name: "گارانتی", values: ["۲ سال", "۲ سال"] },
];
const formatPrice = (price: number) =>
new Intl.NumberFormat("fa-IR", {
style: "currency",
currency: "IRR",
maximumFractionDigits: 0,
}).format(price);
const formatRating = (rating: number) =>
rating.toLocaleString("fa-IR", {
minimumFractionDigits: 1,
maximumFractionDigits: 1,
});
const CompareProducts2 = ({
products = DEFAULT_PRODUCTS,
specs = DEFAULT_SPECS,
className,
}: CompareProducts2Props) => {
const renderValue = (value: string | boolean) => {
if (typeof value === "boolean") {
return value ? (
<Check className="size-4 text-emerald-600" aria-label="دارد" />
) : (
<XIcon className="size-4 text-muted-foreground" aria-label="ندارد" />
);
}
return <span className="text-sm font-medium">{value}</span>;
};
return (
<section
dir="rtl"
lang="fa"
className={cn("py-16 text-start md:py-24", className)}
>
<div className="container max-w-5xl">
<div className="mb-12 text-center">
<h2 className="text-3xl font-semibold tracking-tight">
مقایسه محصولات
</h2>
</div>
<div className="overflow-x-auto rounded-lg border">
<Table>
<TableHeader>
<TableRow className="border-b hover:bg-transparent">
<TableHead className="w-64 bg-muted/50 px-6 py-8 font-semibold">
<span className="text-sm tracking-wider text-muted-foreground">
مشخصات فنی
</span>
</TableHead>
{products.map((product, index) => (
<TableHead
key={product.id}
className={cn(
"min-w-[280px] bg-muted/30 px-6 py-8",
index < products.length - 1 && "border-e",
)}
>
<div className="space-y-4">
<div className="flex items-start gap-4">
<div className="size-24 shrink-0 overflow-hidden rounded-md bg-background">
<AspectRatio ratio={1}>
<img
src={product.image}
alt={product.name}
className="size-full object-cover"
/>
</AspectRatio>
</div>
<div className="flex-1 space-y-2">
{product.badge && (
<Badge variant="secondary" className="text-xs">
{product.badge}
</Badge>
)}
<h3 className="text-lg leading-tight font-semibold">
{product.name}
</h3>
<div className="flex items-baseline gap-2">
<span className="text-xl font-bold">
{formatPrice(product.price)}
</span>
{product.originalPrice && (
<span className="text-xs text-muted-foreground line-through">
{formatPrice(product.originalPrice)}
</span>
)}
</div>
<div className="flex items-center gap-1 text-sm">
<span className="text-amber-500" aria-hidden="true">
★
</span>
<span className="font-medium">
{formatRating(product.rating)}
</span>
</div>
</div>
</div>
<Button className="w-full" size="sm" variant="outline">
افزودن به سبد
</Button>
</div>
</TableHead>
))}
</TableRow>
</TableHeader>
<TableBody>
{specs.map((spec, index) => (
<TableRow
key={index}
className={cn(
"border-b hover:bg-muted/30",
index % 2 === 0 && "bg-muted/20",
)}
>
<TableCell className="px-6 py-5 font-medium">
{spec.name}
</TableCell>
{spec.values.map((value, vIndex) => (
<TableCell
key={vIndex}
className={cn(
"px-6 py-5 text-center",
vIndex < spec.values.length - 1 && "border-e",
)}
>
<div className="flex items-center justify-center">
{renderValue(value)}
</div>
</TableCell>
))}
</TableRow>
))}
</TableBody>
</Table>
</div>
</div>
</section>
);
};
export { CompareProducts2 };