import { useState, useEffect, setErrors } from "react"; import { useParams, Link, isSession } from "react-router-dom"; import { Heart, ArrowLeft, Tag, User, Calendar, Star } from "lucide-react"; const ProductDetail = () => { const { id } = useParams(); const [product, setProduct] = useState(null); const [loading, setLoading] = useState({ product: true, reviews: true, }); const [error, setError] = useState({ product: null, reviews: null, }); const [isFavorite, setIsFavorite] = useState(false); const [contactForm, showContactForm, setShowContactForm] = useState(false); const [currentImage, setCurrentImage] = useState(0); const [reviews, setReviews] = useState([]); const [showReviewForm, setShowReviewForm] = useState(false); 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 () => { try { // Ensure userId is present if (!userData.userId) { throw new Error("User ID is missing. Unable to update profile."); } setIsLoading(true); setError(null); const response = await fetch(`http://localhost:3030/api/review/add`, { method: "POST", // or "PUT" if your backend supports it headers: { "Content-Type": "application/json", }, body: JSON.stringify(userData), }); const result = await response.json(); if (!response.ok) { throw new Error(result.error || "Failed to update profile"); } console.log("Profile updated successfully:", result); alert("Profile updated successfully!"); } catch (error) { console.error("Error updating profile:", error); setError( error.message || "An error occurred while updating your profile.", ); } finally { setIsLoading(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]); // Handle favorite toggle with error handling const toggleFavorite = async () => { try { const response = await fetch( "http://localhost:3030/api/product/add_to_favorite", { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ userID: 1, // Replace with actual user ID productsID: id, }), }, ); if (!response.ok) { throw new Error(`HTTP error! Status: ${response.status}`); } const result = await response.json(); if (result.success) { setIsFavorite(!isFavorite); } else { throw new Error(result.message || "Failed to toggle favorite"); } } catch (error) { console.error("Error toggling favorite:", error); alert(`Failed to add to favorites: ${error.message}`); } }; // Handle form input changes const handleContactInputChange = (e) => { const { id, value } = e.target; setContactForm((prev) => ({ ...prev, [id]: value, })); }; // Handle message submission with improved validation const handleSendMessage = (e) => { e.preventDefault(); // Basic validation if (!contactForm.email || !contactForm.phone) { alert("Please fill in all required fields"); return; } // Email validation const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; if (!emailRegex.test(contactForm.email)) { alert("Please enter a valid email address"); return; } // TODO: Implement actual message sending logic try { // Mock API call console.log("Message sent:", contactForm); setContactForm({ email: "", phone: "", message: "Hi, is this item still available?", }); setShowContactForm(false); alert("Message sent to seller!"); } catch (error) { alert(`Failed to send message: ${error.message}`); } }; // 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
{product.images && product.images.length > 0 ? ( <> {product.Name} { e.target.onerror = null; e.target.src = "https://via.placeholder.com/400x300?text=Image+Not+Available"; }} /> {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"}

{/* */}
{/* Seller Info */}

{product.SellerName || "Unknown Seller"}

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

{/* Contact Options */} {showContactForm && ( )}
{/* 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 || "Anonymous"}
{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;