import { useState, useEffect } from "react"; import { useParams, Link } from "react-router-dom"; import { Heart, ArrowLeft, Tag, User, Calendar, Star, Phone, Mail, } from "lucide-react"; import FloatingAlert from "../components/FloatingAlert"; // adjust path if needed const ProductDetail = () => { const { id } = useParams(); const [product, setProduct] = useState(null); const [loading, setLoading] = useState({ product: true, reviews: true, submitting: false, }); const [error, setError] = useState({ product: null, reviews: null, submit: null, }); const [isFavorite, setIsFavorite] = useState(false); const [showContactOptions, setShowContactOptions] = useState(false); const [currentImage, setCurrentImage] = useState(0); const [reviews, setReviews] = useState([]); const [showReviewForm, setShowReviewForm] = useState(false); const [showAlert, setShowAlert] = useState(false); const storedUser = JSON.parse(sessionStorage.getItem("user")); const toggleFavorite = async (id) => { const response = await fetch( "http://localhost:3030/api/product/addFavorite", { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ userID: storedUser.ID, productID: id, }), }, ); const data = await response.json(); if (data.success) { setShowAlert(true); } console.log(`Add Product -> History: ${id}`); }; const [reviewForm, setReviewForm] = useState({ rating: 3, comment: "", name: "", }); // Add this function to handle review input changes const handleReviewInputChange = (e) => { const { id, value } = e.target; setReviewForm((prev) => ({ ...prev, [id]: value, })); }; // Add this function to handle star rating selection const handleRatingChange = (rating) => { setReviewForm((prev) => ({ ...prev, rating, })); }; const handleSubmitReview = async (e) => { e.preventDefault(); // Prevent form default behavior try { setLoading((prev) => ({ ...prev, submitting: true })); setError((prev) => ({ ...prev, submit: null })); const reviewData = { productId: id, rating: reviewForm.rating, comment: reviewForm.comment, userId: storedUser.ID, }; const response = await fetch( `http://localhost:3030/api/review/addReview`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(reviewData), }, ); const result = await response.json(); // Check if API returned an error message even with 200 status if (!result.success) { throw new Error(result.message || "Failed to submit review"); } alert("Review submitted successfully!"); setReviewForm({ rating: 3, comment: "", name: "", }); setShowReviewForm(false); try { setLoading((prev) => ({ ...prev, reviews: true })); const reviewsResponse = await fetch( `http://localhost:3030/api/review/${id}`, ); const reviewsResult = await reviewsResponse.json(); if (reviewsResult.success) { setReviews(reviewsResult.data || []); setError((prev) => ({ ...prev, reviews: null })); } else { throw new Error(reviewsResult.message || "Error fetching reviews"); } } catch (reviewsError) { console.error("Error fetching reviews:", reviewsError); setError((prev) => ({ ...prev, reviews: reviewsError.message })); } finally { setLoading((prev) => ({ ...prev, reviews: false })); } } catch (error) { console.error("Error submitting review:", error); alert(`Error: ${error.message}`); setError((prev) => ({ ...prev, submit: error.message, })); } finally { setLoading((prev) => ({ ...prev, submitting: false })); } }; // Fetch product data useEffect(() => { const fetchProduct = async () => { try { setLoading((prev) => ({ ...prev, product: true })); const response = await fetch(`http://localhost:3030/api/product/${id}`); if (!response.ok) { throw new Error(`HTTP error! Status: ${response.status}`); } const result = await response.json(); if (result.success) { setProduct(result.data); setError((prev) => ({ ...prev, product: null })); } else { throw new Error(result.message || "Error fetching product"); } } catch (error) { console.error("Error fetching product:", error); setError((prev) => ({ ...prev, product: error.message })); } finally { setLoading((prev) => ({ ...prev, product: false })); } }; fetchProduct(); }, [id]); // Fetch reviews data useEffect(() => { const fetchReviews = async () => { try { setLoading((prev) => ({ ...prev, reviews: true })); const response = await fetch(`http://localhost:3030/api/review/${id}`); if (!response.ok) { throw new Error(`HTTP error! Status: ${response.status}`); } const result = await response.json(); if (result.success) { setReviews(result.data || []); setError((prev) => ({ ...prev, reviews: null })); } else { throw new Error(result.message || "Error fetching reviews"); } } catch (error) { console.error("Error fetching reviews:", error); setError((prev) => ({ ...prev, reviews: error.message })); setReviews([]); } finally { setLoading((prev) => ({ ...prev, reviews: false })); } }; fetchReviews(); }, [id]); // Image navigation const nextImage = () => { if (product?.images?.length > 0) { setCurrentImage((prev) => prev === product.images.length - 1 ? 0 : prev + 1, ); } }; const prevImage = () => { if (product?.images?.length > 0) { setCurrentImage((prev) => prev === 0 ? product.images.length - 1 : prev - 1, ); } }; const selectImage = (index) => { setCurrentImage(index); }; // Function to render stars based on rating const renderStars = (rating) => { const stars = []; for (let i = 1; i <= 5; i++) { stars.push( , ); } return stars; }; // Render loading state for the entire page if (loading.product) { return (
); } // Render error state for product if (error.product) { return (

Error Loading Product

{error.product}

Back to Listings
); } // Safety check for product if (!product) { return (

Product Not Found

Back to Listings
); } // Render product details return (
Back
{showAlert && ( setShowAlert(false)} /> )}
{product.images && product.images.length > 0 ? ( <> {product.Name} { e.target.onerror = null; e.target.src = "https://via.placeholder.com/400x300"; }} /> {product.images.length > 1 && (
{currentImage + 1}/{product.images.length}
)} ) : (
No Image Available
)}
{product.images && product.images.length > 1 && (
{product.images.map((image, index) => (
selectImage(index)} > {`${product.Name} { e.target.onerror = null; e.target.src = "https://via.placeholder.com/100x100?text=Error"; }} />
))}
)}

{product.Name || "Unnamed Product"}

$ {typeof product.Price === "number" ? product.Price.toFixed(2) : product.Price}
{product.Category && (
{product.Category}
)} {product.Date && (
Posted on {product.Date}
)}

{product.Description || "No description available"}

{showContactOptions && (
{product.SellerPhone && ( Call Seller )} {product.SellerEmail && ( Email Seller )}
)}
{/* Seller Info */}

{product.SellerName || "Unknown Seller"}

Member since {product.SellerJoinDate || "N/A"}

{/* Reviews Section */}

Reviews

{loading.reviews ? (
) : error.reviews ? (
Error loading reviews: {error.reviews}
) : reviews.length === 0 ? (
No reviews yet for this product
) : (
{reviews.map((review) => (
{review.ReviewerName}
{review.ReviewDate ? new Date(review.ReviewDate).toLocaleDateString() : "Unknown date"}
{renderStars(review.Rating || 0)} {review.Rating || 0}/5
{review.Comment || "No comment provided"}
))}
)}
{/* Review Popup Form */} {showReviewForm && (

Write a Review

{[1, 2, 3, 4, 5].map((star) => ( ))} {reviewForm.rating}/5
)}
); }; export default ProductDetail;