diff --git a/backend/controllers/product.js b/backend/controllers/product.js index bd40907..0a85686 100644 --- a/backend/controllers/product.js +++ b/backend/controllers/product.js @@ -24,9 +24,19 @@ exports.addToFavorite = async (req, res) => { exports.getAllProducts = async (req, res) => { try { const [data, fields] = await db.execute(` - SELECT p.*, i.URL - FROM Product p - LEFT JOIN Image_URL i ON p.ProductID = i.ProductID + SELECT + P.ProductID, + P.Name AS ProductName, + P.Price, + P.Date AS DateUploaded, + U.Name AS SellerName, + I.URL AS ProductImage, + C.Name AS Category + FROM Product P + LEFT JOIN + (SELECT ProductID, URL FROM Image_URL LIMIT 1) I ON P.ProductID = I.ProductID + JOIN User U ON P.UserID = U.UserID + JOIN Category C ON P.CategoryID = C.CategoryID; `); res.json({ @@ -43,10 +53,10 @@ exports.getAllProducts = async (req, res) => { } }; -// Get a single product by ID along with image URLs exports.getProductById = async (req, res) => { const { id } = req.params; - console.log(id); + console.log("Received Product ID:", id); + try { const [data] = await db.execute( ` @@ -58,29 +68,42 @@ exports.getProductById = async (req, res) => { [id], ); + // Log raw data for debugging + console.log("Raw Database Result:", data); + if (data.length === 0) { + console.log("No product found with ID:", id); return res.status(404).json({ success: false, message: "Product not found", }); } - // Assuming that `data` contains product information and the image URLs + // Collect all image URLs + const images = data + .map((row) => row.image_url) + .filter((url) => url !== null); + + // Create product object with all details from first row and collected images const product = { - ...data[0], // First product found in the query - images: data.map((image) => image.image_url), // Collect all image URLs into an array + ...data[0], // Base product details + images: images, // Collected image URLs }; + // Log processed product for debugging + console.log("Processed Product:", product); + res.json({ success: true, message: "Product fetched successfully", data: product, }); } catch (error) { - console.error("Error fetching product:", error); + console.error("Full Error Details:", error); return res.status(500).json({ success: false, - error: "Database error occurred", + message: "Database error occurred", + error: error.message, }); } }; diff --git a/backend/routes/product.js b/backend/routes/product.js index aeea0d9..90c7914 100644 --- a/backend/routes/product.js +++ b/backend/routes/product.js @@ -1,16 +1,20 @@ +// routes/product.js const express = require("express"); const { addToFavorite, getAllProducts, getProductById, } = require("../controllers/product"); - const router = express.Router(); +// Add detailed logging middleware +router.use((req, res, next) => { + console.log(`Incoming ${req.method} request to ${req.path}`); + next(); +}); + router.post("/add_fav_product", addToFavorite); - router.get("/get_product", getAllProducts); - -router.post("/get_productID", getProductById); +router.get("/:id", getProductById); // Simplified route module.exports = router; diff --git a/frontend/src/pages/Home.jsx b/frontend/src/pages/Home.jsx index 4ae5a6e..5b3fb4b 100644 --- a/frontend/src/pages/Home.jsx +++ b/frontend/src/pages/Home.jsx @@ -21,14 +21,14 @@ const Home = () => { setListings( data.data.map((product) => ({ id: product.ProductID, - title: product.Name, + title: product.ProductName, // Use the alias from SQL price: product.Price, - category: product.CategoryID, - image: product.URL, + category: product.Category, // Ensure this gets the category name + image: product.ProductImage, // Use the alias for image URL condition: "New", // Modify based on actual data - seller: product.UserID, // Modify if seller info is available - datePosted: "Just now", - isFavorite: false, + seller: product.SellerName, // Fetch seller name properly + datePosted: product.DateUploaded, // Use the actual date + isFavorite: false, // Default state })), ); } else { diff --git a/frontend/src/pages/ProductDetail.jsx b/frontend/src/pages/ProductDetail.jsx index 95a5286..6ad1c10 100644 --- a/frontend/src/pages/ProductDetail.jsx +++ b/frontend/src/pages/ProductDetail.jsx @@ -5,6 +5,8 @@ import { Heart, ArrowLeft, Tag, User, Calendar } from "lucide-react"; const ProductDetail = () => { const { id } = useParams(); const [product, setProduct] = useState(null); + const [loading, setLoading] = useState(true); + const [error, setError] = useState(null); const [isFavorite, setIsFavorite] = useState(false); const [showContactForm, setShowContactForm] = useState(false); const [message, setMessage] = useState(""); @@ -14,19 +16,28 @@ const ProductDetail = () => { useEffect(() => { const fetchProduct = async () => { try { - const response = await fetch( - `http://localhost:3030/api/product/get_productID/${id}`, - ); - if (!response.ok) throw new Error("Failed to fetch product"); + setLoading(true); + const response = await fetch(`http://localhost:3030/api/product/${id}`); - const data = await response.json(); - if (data.success) { - setProduct(data.data); // Update the state with product details + if (!response.ok) { + throw new Error("Failed to fetch product"); + } + + const result = await response.json(); + console.log(result); + + if (result.success) { + setProduct(result.data); + setError(null); } else { - throw new Error(data.message || "Error fetching product"); + throw new Error(result.message || "Error fetching product"); } } catch (error) { console.error("Error fetching product:", error); + setError(error.message); + setProduct(null); + } finally { + setLoading(false); } }; @@ -34,14 +45,35 @@ const ProductDetail = () => { }, [id]); // Handle favorite toggle - const toggleFavorite = () => { - setIsFavorite(!isFavorite); + 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, + }), + }, + ); + + const result = await response.json(); + if (result.success) { + setIsFavorite(!isFavorite); + } + } catch (error) { + console.error("Error toggling favorite:", error); + } }; // Handle message submission const handleSendMessage = (e) => { e.preventDefault(); - // Handle message logic here (send to seller) + // TODO: Implement actual message sending logic console.log("Message sent:", message); setMessage(""); setShowContactForm(false); @@ -50,23 +82,53 @@ const ProductDetail = () => { // Image navigation const nextImage = () => { - setCurrentImage((prev) => - prev === product.images.length - 1 ? 0 : prev + 1, - ); + if (product && product.images) { + setCurrentImage((prev) => + prev === product.images.length - 1 ? 0 : prev + 1, + ); + } }; const prevImage = () => { - setCurrentImage((prev) => - prev === 0 ? product.images.length - 1 : prev - 1, - ); + if (product && product.images) { + setCurrentImage((prev) => + prev === 0 ? product.images.length - 1 : prev - 1, + ); + } }; const selectImage = (index) => { setCurrentImage(index); }; - if (!product) return
Loading...
; // Handle loading state + // Render loading state + if (loading) { + return ( +
+
+
+ ); + } + // Render error state + if (error) { + return ( +
+
+

Error Loading Product

+

{error}

+ + Back to Listings + +
+
+ ); + } + + // Render product details return (
@@ -82,15 +144,21 @@ const ProductDetail = () => {
- {product.title} + {product.images && product.images.length > 0 ? ( + {product.Name} + ) : ( +
+ No Image Available +
+ )}
- {product.images.length > 1 && ( + {product.images && product.images.length > 1 && (
{product.images.map((image, index) => (
{ > {`${product.title}
@@ -113,7 +181,7 @@ const ProductDetail = () => {

- {product.title} + {product.Name}

- ${product.price} + ${product.Price}
- {product.category} + {product.Category}
Condition: @@ -139,12 +207,12 @@ const ProductDetail = () => {
- Posted on {product.datePosted} + Posted on {product.Date}
-

{product.shortDescription}

+

{product.Description}

-
+ {/*

Description

-
{product.description}
+
{product.Description}
-
+
*/}
); };