241 lines
8.0 KiB
TypeScript
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 };
|