From 1b53833159580322225727be209e36a0885562c2 Mon Sep 17 00:00:00 2001 From: hamid zarghami Date: Wed, 29 Oct 2025 16:38:38 +0330 Subject: [PATCH] reviews --- src/app/product/components/Reviews.tsx | 94 +++++++++++++++----- src/app/product/components/SingleProduct.tsx | 2 +- src/app/product/hooks/useProductData.ts | 8 ++ src/app/product/service/Service.ts | 8 ++ src/app/profile/types/ProfileTypes.ts | 5 +- 5 files changed, 90 insertions(+), 27 deletions(-) diff --git a/src/app/product/components/Reviews.tsx b/src/app/product/components/Reviews.tsx index 3df9bb3..c4ea09b 100644 --- a/src/app/product/components/Reviews.tsx +++ b/src/app/product/components/Reviews.tsx @@ -3,33 +3,42 @@ 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 { Product } from '@/types/product.types' import AddComment from './AddComment' +import { useGetProductComments } from '../hooks/useProductData' +import PageLoading from '@/components/PageLoading' +import moment from 'moment-jalaali' interface ReviewsProps { product: Product - reviews?: Review[] } -const Reviews: FC = ({ reviews = [] }) => { +const Reviews: FC = ({ product }) => { + const { data: commentsData, isLoading } = useGetProductComments(product._id) const [sort, setSort] = useState<'new' | 'helpful'>('new') const [open, setOpen] = useState(false) - const sortedReviews = useMemo(() => { + + const comments = useMemo(() => commentsData?.results?.comments || [], [commentsData?.results?.comments]) + + const sortedComments = useMemo(() => { if (sort === 'new') { - return [...reviews].sort((a, b) => new Date(b.date).getTime() - new Date(a.date).getTime()) + return [...comments].sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime()) } - return [...reviews].sort((a, b) => b.helpful - a.helpful) - }, [sort, reviews]) + return [...comments].sort((a, b) => (b.status === 'approved' ? 1 : 0) - (a.status === 'approved' ? 1 : 0)) + }, [sort, comments]) + + const approvedComments = useMemo(() => { + return comments.filter(comment => comment.status === 'approved') + }, [comments]) 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]) + if (approvedComments.length === 0) return '0.0' + const sum = approvedComments.reduce((acc, comment) => acc + comment.rate, 0) + return (sum / approvedComments.length).toFixed(1) + }, [approvedComments]) - const formatDate = (dateString: string) => { - const date = new Date(dateString) - return date.toLocaleDateString('fa-IR') + if (isLoading) { + return } return ( @@ -66,29 +75,67 @@ const Reviews: FC = ({ reviews = [] }) => {
- {sortedReviews.length > 0 ? ( - sortedReviews.map((review, idx) => ( -
+ {sortedComments.length > 0 ? ( + sortedComments.map((comment, idx) => ( +
- {review.rating.toFixed(1)} + {comment.rate.toFixed(1)}
- {review.isVerified && ( + {comment.status === 'approved' && ( خریدار )} - {formatDate(review.date)} + {moment(comment.createdAt, 'jYYYY/jMM/jDD HH:mm:ss').format('jYYYY/jMM/jD')} - {review.user.name} + {comment.user.fullName}
+ {comment.title && ( +
+ {comment.title} +
+ )} + + {(comment.advantage && comment.advantage.length > 0) || (comment.disAdvantage && comment.disAdvantage.length > 0) ? ( +
+ {comment.advantage && comment.advantage.length > 0 && ( +
+
نکات مثبت:
+
    + {comment.advantage.map((item, index) => ( +
  • + + {item} +
  • + ))} +
+
+ )} + + {comment.disAdvantage && comment.disAdvantage.length > 0 && ( +
+
نکات منفی:
+
    + {comment.disAdvantage.map((item, index) => ( +
  • + + {item} +
  • + ))} +
+
+ )} +
+ ) : null} +
- {review.comment} + {comment.content}
- {idx !== sortedReviews.length - 1 &&
} + {idx !== sortedComments.length - 1 &&
}
)) ) : ( @@ -125,3 +172,4 @@ const Reviews: FC = ({ reviews = [] }) => { export default Reviews + diff --git a/src/app/product/components/SingleProduct.tsx b/src/app/product/components/SingleProduct.tsx index f0833e9..782b553 100644 --- a/src/app/product/components/SingleProduct.tsx +++ b/src/app/product/components/SingleProduct.tsx @@ -75,7 +75,7 @@ const SingleProduct = ({ id }: SingleProductProps) => { - +
diff --git a/src/app/product/hooks/useProductData.ts b/src/app/product/hooks/useProductData.ts index 78fa521..a02971c 100644 --- a/src/app/product/hooks/useProductData.ts +++ b/src/app/product/hooks/useProductData.ts @@ -56,3 +56,11 @@ export const useSaveReport = () => { mutationFn: api.saveReport, }); }; + +export const useGetProductComments = (productId: number) => { + return useQuery({ + queryKey: ["product-comments", productId], + queryFn: () => api.getProductComments(productId), + enabled: !!productId, + }); +}; diff --git a/src/app/product/service/Service.ts b/src/app/product/service/Service.ts index 620da37..ac14d69 100644 --- a/src/app/product/service/Service.ts +++ b/src/app/product/service/Service.ts @@ -9,6 +9,7 @@ import { ProductQuestionsResponse, SaveReportTypes, } from "../types/Types"; +import { CommentsResponse } from "@/app/profile/types/ProfileTypes"; export const getProduct = async ( id: string @@ -74,3 +75,10 @@ export const saveReport = async (params: SaveReportTypes) => { ); return data; }; + +export const getProductComments = async ( + productId: number +): Promise => { + const { data } = await axios.get(`/product/${productId}/comments`); + return data; +}; diff --git a/src/app/profile/types/ProfileTypes.ts b/src/app/profile/types/ProfileTypes.ts index f587bf8..7110a4f 100644 --- a/src/app/profile/types/ProfileTypes.ts +++ b/src/app/profile/types/ProfileTypes.ts @@ -225,7 +225,7 @@ export interface CommentCategory { theme: string; description: string; leaf: boolean; - parent: string; + parent: string | null; } export interface CommentSpecification { @@ -254,10 +254,9 @@ export interface CommentProduct { imagesUrl: CommentImagesUrl; isFake: string; voice: string | null; - specifications: CommentSpecification[]; + specifications: unknown[]; brand: CommentBrand; category: CommentCategory; - createdAt: string; } export interface Comment {