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

241 lines
8.0 KiB
TypeScript

"use client";
import {
ArrowRight,
Check,
Plus,
ShoppingCart,
X as XIcon,
} from "lucide-react";
import { useState } from "react";
import { Button } from "@/components/ui/button";
import { Card, CardContent } from "@/components/ui/card";
import { ScrollArea, ScrollBar } from "@/components/ui/scroll-area";
import { Separator } from "@/components/ui/separator";
import { cn } from "@/lib/utils";
interface Product {
id: string;
name: string;
image: string;
price: number;
originalPrice?: number;
rating: number;
reviews: number;
highlights: string[];
}
interface CompareProducts3Props {
products?: Product[];
maxProducts?: number;
className?: string;
}
const DEFAULT_PRODUCTS: Product[] = [
{
id: "1",
name: "ایرباد بی‌سیم پریمیوم",
image:
"/block-media/shadcnblocks/block/ecommerce/electronics/Modern-White-Headphones-1.png",
price: 199,
rating: 4.8,
reviews: 2341,
highlights: [
"حذف نویز فعال",
"۳۰ ساعت باتری با کیس",
"صدای فضایی",
"مقاوم در برابر آب IPX4",
],
},
{
id: "2",
name: "ایرباد ورزشی پرو",
image:
"/block-media/shadcnblocks/block/ecommerce/electronics/Sleek-Black-Headphones-1.jpeg",
price: 149,
originalPrice: 179,
rating: 4.5,
reviews: 1892,
highlights: [
"ماندگاری مطمئن برای ورزش",
"۲۴ ساعت باتری با کیس",
"ضدآب IPX7",
"حالت صدای محیط",
],
},
{
id: "3",
name: "ایرباد بی‌سیم سری پایه",
image:
"/block-media/shadcnblocks/block/ecommerce/electronics/Modern-Headphones-1.jpeg",
price: 79,
rating: 4.2,
reviews: 956,
highlights: [
"کنترل لمسی",
"۱۸ ساعت باتری با کیس",
"دستیار صوتی",
"طراحی جمع‌وجور",
],
},
];
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 CompareProducts3 = ({
products = DEFAULT_PRODUCTS,
maxProducts = 4,
className,
}: CompareProducts3Props) => {
const [selectedProducts, setSelectedProducts] = useState<Product[]>(products);
const removeProduct = (id: string) => {
setSelectedProducts((prev) => prev.filter((p) => p.id !== id));
};
const canAddMore = selectedProducts.length < maxProducts;
return (
<section
dir="rtl"
lang="fa"
className={cn("py-16 text-start md:py-24", className)}
>
<div className="container">
<div className="mb-8 flex items-center justify-between">
<div>
<h2 className="text-xl font-bold tracking-tight md:text-3xl">
مقایسه مشخصات محصولات
</h2>
<p className="mt-1 text-muted-foreground">
حداکثر ۴{" "}
{maxProducts.toLocaleString("fa-IR")} محصول را برای مقایسه انتخاب کنید.
</p>
</div>
{selectedProducts.length > 0 && (
<Button
variant="ghost"
onClick={() => setSelectedProducts([])}
className="text-destructive hover:text-destructive"
>
حذف همه موارد
</Button>
)}
</div>
<ScrollArea className="w-full">
<div className="flex gap-4 pb-4">
{selectedProducts.map((product) => (
<Card key={product.id} className="w-72 shrink-0 gap-0 p-0">
<CardContent className="p-0">
<div className="relative">
<Button
variant="secondary"
size="icon"
className="absolute start-2 top-2 z-10 size-7"
onClick={() => removeProduct(product.id)}
aria-label={`حذف ${product.name}`}
>
<XIcon className="size-4" />
</Button>
<div className="aspect-square bg-muted">
<img
src={product.image}
alt={product.name}
className="size-full object-cover"
/>
</div>
</div>
<div className="p-4">
<h3 className="leading-tight font-semibold">
{product.name}
</h3>
<div className="mt-2 flex items-center gap-2">
<span className="text-lg font-bold">
{formatPrice(product.price)}
</span>
{product.originalPrice && (
<span className="text-sm text-muted-foreground line-through">
{formatPrice(product.originalPrice)}
</span>
)}
</div>
<div className="mt-2 flex items-center gap-1 text-sm">
<span className="text-amber-500" aria-hidden="true">
★
</span>
<span className="font-medium">
{formatRating(product.rating)}
</span>
<span className="text-muted-foreground">
({product.reviews.toLocaleString("fa-IR")} دیدگاه)
</span>
</div>
<Separator className="my-4" />
<div className="space-y-2">
{product.highlights.map((highlight, index) => (
<div
key={index}
className="flex items-start gap-2 text-sm"
>
<Check
className="mt-0.5 size-4 shrink-0 text-emerald-600"
aria-hidden="true"
/>
<span>{highlight}</span>
</div>
))}
</div>
<Button className="mt-4 w-full">
<ShoppingCart className="ms-2 size-4" />
افزودن به سبد خرید
</Button>
</div>
</CardContent>
</Card>
))}
{canAddMore && (
<Card className="w-72 shrink-0 cursor-pointer gap-0 border-dashed p-0 transition-colors hover:border-primary hover:bg-muted/50">
<CardContent className="flex h-full min-h-[400px] flex-col items-center justify-center p-4 text-center">
<div className="mb-3 flex size-16 items-center justify-center rounded-full bg-muted">
<Plus className="size-6 text-muted-foreground" />
</div>
<p className="font-medium">افزودن محصول جدید</p>
<p className="mt-1 text-sm text-muted-foreground">
برای مقایسه بهتر، محصول دیگری را نیز انتخاب کنید.
</p>
<Button variant="outline" className="mt-4">
مشاهده فهرست محصولات
<ArrowRight className="ms-2 size-4 rtl:rotate-180" />
</Button>
</CardContent>
</Card>
)}
</div>
<ScrollBar orientation="horizontal" />
</ScrollArea>
</div>
</section>
);
};
export { CompareProducts3 };