177 lines
6.0 KiB
TypeScript
177 lines
6.0 KiB
TypeScript
import { BadgeCheck } from "lucide-react";
|
||
|
||
import { Rating } from "@/components/shadcnblocks/rating";
|
||
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
|
||
import { Separator } from "@/components/ui/separator";
|
||
import { cn } from "@/lib/utils";
|
||
|
||
interface Review {
|
||
id: string;
|
||
rating: number;
|
||
title: string;
|
||
content: string;
|
||
author: {
|
||
name: string;
|
||
avatar?: string;
|
||
};
|
||
date: string;
|
||
verified?: boolean;
|
||
}
|
||
|
||
const DEFAULT_REVIEWS: Review[] = [
|
||
{
|
||
id: "1",
|
||
rating: 5,
|
||
title: "فراتر از انتظارم بود",
|
||
content:
|
||
"اول کمی تردید داشتم، ولی این محصول واقعاً جواب داد. کیفیت ساخت عالی است و زودتر از موعد به دستم رسید. اگر هنوز مردد هستید، حتماً پیشنهاد میکنم امتحان کنید.",
|
||
author: {
|
||
name: "سارا احمدی",
|
||
avatar: "/block-media/shadcnblocks/block/avatar-1.webp",
|
||
},
|
||
date: "۲۰ آذر ۱۴۰۳",
|
||
verified: true,
|
||
},
|
||
{
|
||
id: "2",
|
||
rating: 4,
|
||
title: "ارزش خرید بالا",
|
||
content:
|
||
"بهطور کلی محصول خوبی است و دقیقاً همان کاری را میکند که باید. یک ستاره کم کردم چون بستهبندی میتوانست بهتر باشد، ولی خود محصول عالی است.",
|
||
author: {
|
||
name: "مازیار رضایی",
|
||
avatar: "/block-media/shadcnblocks/block/avatar-2.webp",
|
||
},
|
||
date: "۱۸ آذر ۱۴۰۳",
|
||
verified: true,
|
||
},
|
||
{
|
||
id: "3",
|
||
rating: 5,
|
||
title: "عالی برای استفاده روزمره",
|
||
content:
|
||
"یک ماه است هر روز از آن استفاده میکنم و هنوز مثل روز اول به نظر میرسد و درست کار میکند. با این قیمت، کیفیت ساخت واقعاً قابل تحسین است. برای خواهرم هم یکی خریدم.",
|
||
author: {
|
||
name: "نیلوفر حسینی",
|
||
avatar: "/block-media/shadcnblocks/block/avatar-3.webp",
|
||
},
|
||
date: "۱۵ آذر ۱۴۰۳",
|
||
verified: true,
|
||
},
|
||
{
|
||
id: "4",
|
||
rating: 4,
|
||
title: "خوب، ولی کامل نیست",
|
||
content:
|
||
"محصول خوب است و درست کار میکند. تنها نکته کوچک این است که رنگ کمی با عکسها فرق دارد، ولی در مجموع خرید رضایتبخشی بود.",
|
||
author: {
|
||
name: "امیر محمدی",
|
||
},
|
||
date: "۱۲ آذر ۱۴۰۳",
|
||
verified: false,
|
||
},
|
||
{
|
||
id: "5",
|
||
rating: 5,
|
||
title: "بهترین خرید امسالم",
|
||
content:
|
||
"واقعاً عاشقش شدم! به جزئیات با دقت زیادی توجه شده. وقتی سوال داشتم، پشتیبانی هم بسیار مفید بود. از هر نظر پنج ستاره.",
|
||
author: {
|
||
name: "رؤیا کاظمی",
|
||
avatar: "/block-media/shadcnblocks/block/avatar-7.webp",
|
||
},
|
||
date: "۸ آذر ۱۴۰۳",
|
||
verified: true,
|
||
},
|
||
];
|
||
|
||
interface Reviews1Props {
|
||
reviews?: Review[];
|
||
title?: string;
|
||
className?: string;
|
||
}
|
||
|
||
const Reviews1 = ({
|
||
reviews = DEFAULT_REVIEWS,
|
||
title = "نظرات مشتریان",
|
||
className,
|
||
}: Reviews1Props) => {
|
||
const averageRating =
|
||
reviews.reduce((sum, review) => sum + review.rating, 0) / reviews.length;
|
||
|
||
const formattedAverage = averageRating.toLocaleString("fa-IR", {
|
||
minimumFractionDigits: 1,
|
||
maximumFractionDigits: 1,
|
||
});
|
||
const reviewCountLabel = `${reviews.length.toLocaleString("fa-IR")} نظر`;
|
||
|
||
return (
|
||
<section
|
||
dir="rtl"
|
||
lang="fa"
|
||
className={cn("py-16 md:py-24", className)}
|
||
>
|
||
<div className="container max-w-3xl">
|
||
<div className="mb-8">
|
||
<h2 className="text-xl font-semibold tracking-tight md:text-3xl">
|
||
{title}
|
||
</h2>
|
||
<div className="mt-2 flex items-center gap-3">
|
||
<Rating rate={averageRating} className="[&_svg]:size-5" />
|
||
<span className="text-sm text-muted-foreground">
|
||
{formattedAverage} از ۵ · {reviewCountLabel}
|
||
</span>
|
||
</div>
|
||
</div>
|
||
|
||
<div className="space-y-0">
|
||
{reviews.map((review, index) => (
|
||
<div key={review.id}>
|
||
{index > 0 && <Separator className="my-6" />}
|
||
<div className="space-y-3">
|
||
<div>
|
||
<Rating rate={review.rating} className="[&_svg]:size-4" />
|
||
<h3 className="mt-2 font-medium">{review.title}</h3>
|
||
</div>
|
||
|
||
<p className="text-sm leading-relaxed text-muted-foreground">
|
||
{review.content}
|
||
</p>
|
||
|
||
<div className="flex items-center gap-3">
|
||
<Avatar className="size-8">
|
||
<AvatarImage
|
||
src={review.author.avatar}
|
||
alt={review.author.name}
|
||
/>
|
||
<AvatarFallback className="text-xs">
|
||
{review.author.name
|
||
.split(/\s+/)
|
||
.slice(0, 2)
|
||
.map((part) => part[0])
|
||
.join("")}
|
||
</AvatarFallback>
|
||
</Avatar>
|
||
<div className="flex items-center gap-2 text-sm">
|
||
<span className="font-medium">{review.author.name}</span>
|
||
{review.verified && (
|
||
<span className="flex items-center gap-1 text-emerald-600">
|
||
<BadgeCheck className="size-4" />
|
||
<span className="text-xs">خرید تأییدشده</span>
|
||
</span>
|
||
)}
|
||
<span className="text-muted-foreground">·</span>
|
||
<span className="text-muted-foreground">{review.date}</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
))}
|
||
</div>
|
||
</div>
|
||
</section>
|
||
);
|
||
};
|
||
|
||
export { Reviews1 };
|