import { Button } from "~/components/ui/button"; import { Review } from "./Review"; import { useState, useEffect, useRef } from "react"; import { ChevronLeft, ChevronRight, Pencil, X, Star } from "lucide-react"; import longArrow from "~/assets/icons/product/longArrow.svg"; import { useServiceGetComments, useServiceCreateComment, useServiceSubmitRating, } from "~/utils/RequestHandler"; import { Drawer, DrawerContent, DrawerHeader, DrawerTitle } from "../ui/drawer"; import AppTextArea from "~/components/AppTextArea"; import { useRootData } from "~/hooks/use-root-data"; import { useToast } from "~/hooks/use-toast"; import { ProductComment } from "src/api/types"; import { formatDate } from "~/utils/helpers"; import { LoginRequiredDialog } from "../LoginRequiredDialog"; // Pagination component const Pagination = ({ currentPage, totalPages, onPageChange, }: { currentPage: number; totalPages: number; onPageChange: (page: number) => void; }) => { return (
{[...Array(totalPages)].map((_, index) => { const pageNumber = index + 1; // Show current page, first, last, and pages around current if ( pageNumber === 1 || pageNumber === totalPages || (pageNumber >= currentPage - 1 && pageNumber <= currentPage + 1) ) { return ( ); } // Show ellipsis for gaps if ( (pageNumber === 2 && currentPage > 3) || (pageNumber === totalPages - 1 && currentPage < totalPages - 2) ) { return ...; } return null; })}
); }; export const ReviewList = ({ productId }: { productId: string }) => { const [page, setPage] = useState(1); const perPage = 10; // Show 3 comments per page as requested const { data, isLoading, error } = useServiceGetComments(page, productId); if (isLoading) return (
در حال بارگذاری نظرات...
); if (error) return (
خطا در بارگذاری نظرات
); if (!data || !data.results || data.results.length === 0) return (
نظری ثبت نشده است
); const totalPages = !data.count ? 1 : Math.ceil(data.count / perPage); return (
{data.results?.map((comment: ProductComment, index: number) => ( ))}
); }; export const ReviewSection = ({ productId, isOwner = false, }: { productId: string; isOwner?: boolean; }) => { // Get product ID from the URL if not provided const resolvedProductId = productId || window.location.pathname.split("/").pop() || ""; // Get total comment count using the same service const { data } = useServiceGetComments(1, resolvedProductId); const commentCount = data?.count || 0; return (

نظر خریداران {commentCount ? `(${commentCount})` : null}

{!isOwner && }
); }; const SubmitReviewDrawer = ({ productId }: { productId: string }) => { const [submitReviewDrawer, setSubmitReviewDrawer] = useState(false); const [rating, setRating] = useState(null); const [comment, setComment] = useState(""); const [hoverRating, setHoverRating] = useState(null); const [isSubmitting, setIsSubmitting] = useState(false); const [error, setError] = useState(null); const { toast } = useToast(); const [isLoginModalOpen, setIsLoginModalOpen] = useState(false); const textareaRef = useRef(null); const drawerContentRef = useRef(null); const [keyboardHeight, setKeyboardHeight] = useState(0); // Get authentication token from localStorage const { user } = useRootData(); const authToken = user?.access_token ? user.access_token.replace(/^"|"$/g, "") : ""; // Get the mutations const createCommentMutation = useServiceCreateComment(); const submitRatingMutation = useServiceSubmitRating(); // Handle keyboard open/close using visualViewport API useEffect(() => { if (!submitReviewDrawer) return; const viewport = window.visualViewport; if (!viewport) return; const handleViewportResize = () => { // Calculate keyboard height from the difference between window height and viewport height const newKeyboardHeight = window.innerHeight - viewport.height; setKeyboardHeight(Math.max(0, newKeyboardHeight)); // Scroll textarea into view when keyboard opens if (newKeyboardHeight > 0 && textareaRef.current) { setTimeout(() => { textareaRef.current?.scrollIntoView({ behavior: "smooth", block: "center", }); }, 100); } }; viewport.addEventListener("resize", handleViewportResize); viewport.addEventListener("scroll", handleViewportResize); return () => { viewport.removeEventListener("resize", handleViewportResize); viewport.removeEventListener("scroll", handleViewportResize); }; }, [submitReviewDrawer]); // Handle star rating click const handleRatingClick = (newRating: number) => { setRating(newRating); }; // Handle star hover effects const handleRatingHover = (hoveredRating: number | null) => { setHoverRating(hoveredRating); }; // Handle comment input change const handleCommentChange = (e: React.ChangeEvent) => { setComment(e.target.value); }; // Handle form submission const handleSubmit = async () => { // Check if user is authenticated if (!authToken) { setError("لطفا ابتدا وارد حساب کاربری خود شوید."); return; } // Form validation if (!rating) { setError("لطفا به این محصول امتیاز دهید."); return; } if (!comment || comment.trim().length < 1) { setError("لطفا نظر خود را درباره این محصول بنویسید."); return; } setError(null); setIsSubmitting(true); try { // Submit rating first await submitRatingMutation.mutateAsync({ product_id: productId, rating: rating, }); // Then submit comment await createCommentMutation.mutateAsync({ product: productId, comment: comment, parent: null, }); // Reset form and close drawer on success setComment(""); setRating(null); setSubmitReviewDrawer(false); // Show success toast toast({ title: "نظر شما با موفقیت ثبت شد", description: "نظر شما بعد از بررسی به زودی اضافه خواهد شد.", }); } catch { console.error("Error submitting review:"); setError("خطا در ثبت نظر. لطفا مجددا تلاش کنید."); } finally { setIsSubmitting(false); } }; // Determine the star fill based on rating and hover state const getStarFill = (starPosition: number) => { const currentRating = hoverRating !== null ? hoverRating : rating; return currentRating !== null && starPosition <= currentRating ? "fill-current" : ""; }; return ( <>
setSubmitReviewDrawer(false)} /> ثبت نظر و امتیاز
0 ? `${keyboardHeight + 16}px` : undefined }} > {/* Rating section */}

به این محصول امتیاز دهید:

{[1, 2, 3, 4, 5].map((starPosition) => ( handleRatingClick(starPosition)} onMouseEnter={() => handleRatingHover(starPosition)} onMouseLeave={() => handleRatingHover(null)} /> ))}
longArrow
{/* Comment section - Using AppTextArea instead of AppInput */}
{/* Error message */} {error && (
{error}
)} {/* Submit button */}
); };