128 lines
6.4 KiB
TypeScript
128 lines
6.4 KiB
TypeScript
'use client'
|
||
import { FC, useMemo, useState } from 'react'
|
||
import { Button } from '@/components/ui/button'
|
||
import { Separator } from '@/components/ui/separator'
|
||
import { Star1 } from 'iconsax-react'
|
||
import { Product, Review } from '@/types/product.types'
|
||
import AddComment from './AddComment'
|
||
|
||
interface ReviewsProps {
|
||
product: Product
|
||
reviews?: Review[]
|
||
}
|
||
|
||
const Reviews: FC<ReviewsProps> = ({ reviews = [] }) => {
|
||
const [sort, setSort] = useState<'new' | 'helpful'>('new')
|
||
const [open, setOpen] = useState(false)
|
||
const sortedReviews = useMemo(() => {
|
||
if (sort === 'new') {
|
||
return [...reviews].sort((a, b) => new Date(b.date).getTime() - new Date(a.date).getTime())
|
||
}
|
||
return [...reviews].sort((a, b) => b.helpful - a.helpful)
|
||
}, [sort, reviews])
|
||
|
||
const average = useMemo(() => {
|
||
if (reviews.length === 0) return '0.0'
|
||
const sum = reviews.reduce((acc, r) => acc + r.rating, 0)
|
||
return (sum / reviews.length).toFixed(1)
|
||
}, [reviews])
|
||
|
||
const formatDate = (dateString: string) => {
|
||
const date = new Date(dateString)
|
||
return date.toLocaleDateString('fa-IR')
|
||
}
|
||
|
||
return (
|
||
<div className="mt-12 sm:mt-16 w-full">
|
||
<div className="flex items-center justify-end gap-3 flex-row-reverse">
|
||
<h2 className="text-primary text-base sm:text-lg">نظرات خریداران</h2>
|
||
<div className="w-1 h-6 bg-primary rounded"></div>
|
||
</div>
|
||
|
||
<div className="mt-4 sm:mt-6 grid grid-cols-12 gap-4 sm:gap-6">
|
||
<div className="col-span-12 md:col-span-9 md:order-last">
|
||
<div className="flex flex-col sm:flex-row sm:items-center justify-start gap-2 sm:gap-4 text-xs sm:text-sm text-[#7F7F7F]">
|
||
<span>مرتب سازی بر اساس:</span>
|
||
<div className="flex items-center gap-4 sm:gap-6">
|
||
<button
|
||
type="button"
|
||
onClick={() => setSort('new')}
|
||
className={
|
||
sort === 'new' ? 'text-primary font-medium' : 'text-[#B2B2B2] hover:text-primary'
|
||
}
|
||
>
|
||
جدیدترین
|
||
</button>
|
||
<button
|
||
type="button"
|
||
onClick={() => setSort('helpful')}
|
||
className={
|
||
sort === 'helpful' ? 'text-primary font-medium' : 'text-[#B2B2B2] hover:text-primary'
|
||
}
|
||
>
|
||
مفیدترین
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div className="mt-4 sm:mt-6 rounded-xl bg-white">
|
||
{sortedReviews.length > 0 ? (
|
||
sortedReviews.map((review, idx) => (
|
||
<div key={review._id} className="px-4 sm:px-6 py-4 sm:py-5">
|
||
<div className="flex flex-col sm:flex-row sm:items-center justify-start gap-2 sm:gap-3">
|
||
<div className="px-2 py-0.5 rounded-full bg-[#02A55A] text-white text-xs w-fit">
|
||
{review.rating.toFixed(1)}
|
||
</div>
|
||
<div className="flex flex-wrap items-center gap-1 sm:gap-2 text-xs text-[#999999]">
|
||
{review.isVerified && (
|
||
<span className="px-2 py-0.5 rounded bg-[#F1F1F1] text-[#7F7F7F]">خریدار</span>
|
||
)}
|
||
<span className="size-1.5 rounded-full bg-[#E5E5E5]"></span>
|
||
<span>{formatDate(review.date)}</span>
|
||
<span className="size-1.5 rounded-full bg-[#E5E5E5]"></span>
|
||
<span>{review.user.name}</span>
|
||
</div>
|
||
</div>
|
||
|
||
<div className="mt-3 text-[#333333] text-xs sm:text-sm leading-6 sm:leading-7 text-right">
|
||
{review.comment}
|
||
</div>
|
||
|
||
{idx !== sortedReviews.length - 1 && <div className="mt-4 sm:mt-5"> <Separator /> </div>}
|
||
</div>
|
||
))
|
||
) : (
|
||
<div className="px-4 sm:px-6 py-8 text-center text-[#999999] text-sm">
|
||
هنوز نظری ثبت نشده است
|
||
</div>
|
||
)}
|
||
</div>
|
||
</div>
|
||
|
||
<div className="col-span-12 md:col-span-3 order-first md:order-first">
|
||
<div className="rounded-[10px] p-4 sm:p-6 h-fit md:sticky md:top-[170px]">
|
||
<div className="text-primary text-xs sm:text-sm">نظرات خریداران</div>
|
||
<div className="mt-3 sm:mt-4 flex items-center justify-end gap-2">
|
||
<Star1 size={16} color="#FFC107" variant="Bold" className="sm:w-[18px] sm:h-[18px]" />
|
||
<div className="text-xs sm:text-sm">
|
||
<span className="font-medium">{average}</span>
|
||
<span className="text-[#7F7F7F]"> / 5</span>
|
||
</div>
|
||
</div>
|
||
<div className="mt-3 sm:mt-4 text-xs text-[#7F7F7F] leading-5 sm:leading-6 text-justify">
|
||
شما هم درباره این کالا نظر خود را ثبت کنید. نظر شما پس از بررسی و تایید نمایش داده میشود.
|
||
</div>
|
||
<Button className="w-full mt-4 sm:mt-5 text-xs sm:text-sm" onClick={() => setOpen(true)}>ثبت دیدگاه</Button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<AddComment open={open} close={() => setOpen(false)} />
|
||
</div>
|
||
)
|
||
}
|
||
|
||
export default Reviews
|
||
|
||
|