import { Link, useNavigate } from "react-router-dom"; import { useState, useEffect, useRef } from "react"; import { Tag, ChevronLeft, ChevronRight, Bookmark, Loader } from "lucide-react"; import FloatingAlert from "../components/FloatingAlert"; // adjust path if needed const Home = () => { const navigate = useNavigate(); const [listings, setListings] = useState([]); const [recommended, setRecommended] = useState([]); const [history, setHistory] = useState([]); const [error, setError] = useState(null); const [showAlert, setShowAlert] = useState(false); const [isLoading, setIsLoading] = useState({ recommendations: true, listings: true, history: true, }); const recommendationsFetched = useRef(false); const historyFetched = useRef(false); //After user data storing the session. const storedUser = JSON.parse(sessionStorage.getItem("user")); const toggleFavorite = async (id) => { try { 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); // Close alert after 3 seconds setTimeout(() => setShowAlert(false), 3000); } console.log(`Add Product -> Favorites: ${id}`); } catch (error) { console.error("Error adding favorite:", error); } }; const addHistory = async (id) => { try { await fetch("http://localhost:3030/api/history/addHistory", { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ userID: storedUser.ID, productID: id, }), }); } catch (error) { console.error("Error adding to history:", error); } }; // Fetch recommended products useEffect(() => { const fetchRecommendedProducts = async () => { // Skip if already fetched or no user data if (recommendationsFetched.current || !storedUser || !storedUser.ID) return; setIsLoading((prev) => ({ ...prev, recommendations: true })); try { recommendationsFetched.current = true; // Mark as fetched before the API call const response = await fetch( "http://localhost:3030/api/engine/recommended", { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ id: storedUser.ID, }), }, ); if (!response.ok) throw new Error("Failed to fetch recommendations"); const data = await response.json(); if (data.success) { setRecommended( data.data.map((product) => ({ id: product.ProductID, title: product.ProductName, price: product.Price, category: product.Category, image: product.ProductImage, seller: product.SellerName, datePosted: product.DateUploaded, isFavorite: false, })), ); } else { throw new Error(data.message || "Error fetching recommendations"); } } catch (error) { console.error("Error fetching recommendations:", error); setError(error.message); // Reset the flag if there's an error so it can try again recommendationsFetched.current = false; } finally { setIsLoading((prev) => ({ ...prev, recommendations: false })); } }; fetchRecommendedProducts(); }, [storedUser]); // Keep dependency // Fetch all products useEffect(() => { const fetchProducts = async () => { setIsLoading((prev) => ({ ...prev, listings: true })); try { const response = await fetch( "http://localhost:3030/api/product/getProduct", ); if (!response.ok) throw new Error("Failed to fetch products"); const data = await response.json(); if (data.success) { setListings( data.data.map((product) => ({ id: product.ProductID, title: product.ProductName, price: product.Price, category: product.Category, image: product.ProductImage, seller: product.SellerName, datePosted: product.DateUploaded, isFavorite: false, })), ); } else { throw new Error(data.message || "Error fetching products"); } } catch (error) { console.error("Error fetching products:", error); setError(error.message); } finally { setIsLoading((prev) => ({ ...prev, listings: false })); } }; fetchProducts(); }, []); // Fetch user history useEffect(() => { const fetchUserHistory = async () => { // Skip if already fetched or no user data if (historyFetched.current || !storedUser || !storedUser.ID) return; setIsLoading((prev) => ({ ...prev, history: true })); try { historyFetched.current = true; // Mark as fetched before the API call const response = await fetch( "http://localhost:3030/api/history/getHistory", { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ id: storedUser.ID, }), }, ); if (!response.ok) throw new Error("Failed to fetch history"); const data = await response.json(); if (data.success) { setHistory( data.data.map((product) => ({ id: product.ProductID, title: product.ProductName, price: product.Price, category: product.Category, image: product.ProductImage, seller: product.SellerName, datePosted: product.DateUploaded, })), ); } else { throw new Error(data.message || "Error fetching history"); } } catch (error) { console.error("Error fetching history:", error); setError(error.message); // Reset the flag if there's an error so it can try again historyFetched.current = false; } finally { setIsLoading((prev) => ({ ...prev, history: false })); } }; fetchUserHistory(); }, [storedUser]); // Keep dependency const handleSelling = () => { navigate("/selling"); }; // Loading indicator component const LoadingSection = () => (
); // Product card component to reduce duplication const ProductCard = ({ product, addToHistory = false }) => ( addHistory(product.id) : undefined} className="bg-white border border-gray-200 hover:shadow-md transition-shadow w-70 flex-shrink-0 relative" >
{product.title}

{product.title}

${product.price}
{product.category}
{product.datePosted} {product.seller}
); // Scrollable product list component to reduce duplication const ScrollableProductList = ({ containerId, products, children, isLoading, addToHistory = false, }) => (
{children}
{isLoading ? ( ) : products.length > 0 ? ( products.map((product) => ( )) ) : (
No products available
)}
); return (
{/* Hero Section with School Background */}
University of Calgary

Buy and Sell on Campus

The marketplace exclusively for university students. Find everything you need or sell what you don't.

{/* Floating Alert */} {showAlert && ( setShowAlert(false)} /> )} {/* Recommendations Section */}

Recommended For You

{/* Recent Listings Section */}

Recent Listings

{/* History Section */} {(history.length > 0 || isLoading.history) && (

Your Browsing History

)}
{/* Footer */}
); }; export default Home;