import { useState, useEffect } from "react"; import { BrowserRouter as Router, Routes, Route, Navigate, useLocation, } from "react-router-dom"; import Navbar from "./components/Navbar"; import Home from "./pages/Home"; import Settings from "./pages/Settings"; import Selling from "./pages/Selling"; import Transactions from "./pages/Transactions"; import Favorites from "./pages/Favorites"; import ProductDetail from "./pages/ProductDetail"; import SearchPage from "./pages/SearchPage"; import Dashboard from "./pages/Dashboard"; // The single consolidated dashboard component import DashboardNav from "./components/DashboardNav"; import { verifyIsAdmin } from "./api/admin"; function App() { // Authentication state - initialize from localStorage if available const [isAuthenticated, setIsAuthenticated] = useState(() => { return sessionStorage.getItem("isAuthenticated") === "true"; }); const [user, setUser] = useState(() => { const savedUser = sessionStorage.getItem("user"); return savedUser ? JSON.parse(savedUser) : null; }); // UI state for login/signup form const [isSignUp, setIsSignUp] = useState(false); const [showImage, setShowImage] = useState(true); const [error, setError] = useState(""); const [isLoading, setIsLoading] = useState(false); // Product recommendation states const [isGeneratingRecommendations, setIsGeneratingRecommendations] = useState(false); const [recommendations, setRecommendations] = useState([]); // Admin state const [isAdmin, setIsAdmin] = useState(false); const [showAdminDashboard, setShowAdminDashboard] = useState(false); // Check URL to determine if we're in admin mode useEffect(() => { // If URL contains /admin, set showAdminDashboard to true if (window.location.pathname.includes("/admin")) { setShowAdminDashboard(true); } }, []); // New verification states const [verificationStep, setVerificationStep] = useState("initial"); // 'initial', 'code-sent', 'verifying' const [tempUserData, setTempUserData] = useState(null); // Auto-hide image on smaller screens useEffect(() => { const handleResize = () => { if (window.innerWidth < 768) { setShowImage(false); } else { setShowImage(true); } }; handleResize(); window.addEventListener("resize", handleResize); return () => window.removeEventListener("resize", handleResize); }, []); useEffect(() => { if (isAuthenticated && user) { sendSessionDataToServer(); } }, [isAuthenticated, user]); // Generate product recommendations when user logs in useEffect(() => { if (isAuthenticated && user) { generateProductRecommendations(); } }, [isAuthenticated, user]); // Generate product recommendations const generateProductRecommendations = async () => { setIsGeneratingRecommendations(true); // Add a short delay to simulate calculation time await new Promise((resolve) => setTimeout(resolve, 500)); console.log("Generating product recommendations for user:", user.ID); setIsGeneratingRecommendations(false); }; useEffect(() => { const userInfo = sessionStorage.getItem("user") ? JSON.parse(sessionStorage.getItem("user")) : ""; const id = userInfo?.ID; verifyIsAdmin(id).then((data) => { setIsAdmin(data.isAdmin); }); }, [user]); const handleShowAdminDashboard = () => { setShowAdminDashboard(true); // Update URL without reloading page window.history.pushState({}, "", "/admin"); }; const handleCloseAdminDashboard = () => { setShowAdminDashboard(false); // Update URL without reloading page window.history.pushState({}, "", "/"); }; // Send verification code const sendVerificationCode = async (userData) => { try { setIsLoading(true); setError(""); console.log("Sending verification code to:", userData.email); // Make API call to send verification code const response = await fetch( "http://localhost:3030/api/user/send-verification", { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ email: userData.email, // Add any other required fields }), }, ); if (!response.ok) { throw new Error("Failed to send verification code"); } const result = await response.json(); if (result.success) { // Store temporary user data setTempUserData(userData); // Move to verification step setVerificationStep("code-sent"); console.log("Verification code sent successfully"); return true; } else { setError(result.message || "Failed to send verification code"); return false; } } catch (err) { console.error("Error sending verification code:", err); setError("Failed to send verification code. Please try again."); return false; } finally { setIsLoading(false); } }; // Verify code const verifyCode = async (code) => { try { setIsLoading(true); setError(""); console.log("Verifying code:", code); // Make API call to verify code const response = await fetch( "http://localhost:3030/api/user/verify-code", { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ email: tempUserData.email, code: code, }), }, ); if (!response.ok) { throw new Error("Failed to verify code"); } const result = await response.json(); if (result.success) { console.log("Code verified successfully"); // Proceed to complete signup return await completeSignUp(tempUserData); } else { setError(result.message || "Invalid verification code"); return false; } } catch (err) { console.error("Error verifying code:", err); setError("Failed to verify code. Please try again."); return false; } finally { setIsLoading(false); } }; // Complete signup const completeSignUp = async (userData) => { try { setIsLoading(true); setError(""); console.log("Completing signup for:", userData.email); console.log(userData); // Make API call to complete signup const response = await fetch( "http://localhost:3030/api/user/complete-signup", { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify(userData), }, ); if (!response.ok) { throw new Error("Failed to complete signup"); } const result = await response.json(); console.log(result); if (result.success) { // Create user object from API response const newUser = { ID: result.userID || result.ID, name: result.name || userData.name, email: result.email || userData.email, UCID: result.UCID || userData.ucid, }; // Set authenticated user setUser(newUser); setIsSignUp(false); //setIsAuthenticated(true); // Save to localStorage to persist across refreshes sessionStorage.setItem("isAuthenticated", "true"); sessionStorage.setItem("user", JSON.stringify(newUser)); // After successful signup, send session data to server sendSessionDataToServer(); // Reset verification steps setVerificationStep("initial"); setTempUserData(null); console.log("Signup completed successfully"); // Generate recommendations for the new user generateProductRecommendations(); return true; } else { setError(result.message || "Failed to complete signup"); return false; } } catch (err) { console.error("Error completing signup:", err); setError("Failed to complete signup. Please try again."); return false; } finally { setIsLoading(false); } }; const handleSubmit = async (e) => { e.preventDefault(); setIsLoading(true); setError(""); // Get form data directly from the form const formData = new FormData(e.target); const formValues = Object.fromEntries(formData.entries()); // Validate email and password if (!formValues.email || !formValues.password) { setError("Email and password are required"); setIsLoading(false); return; } else if (!formValues.email.endsWith("@ucalgary.ca")) { setError("Please use your UCalgary email address (@ucalgary.ca)"); setIsLoading(false); return; } try { if (isSignUp) { // Handle Sign Up with verification console.log("Sign Up Form Data:", formValues); // Create a user object with the form data const newUser = { name: formValues.name, email: formValues.email, UCID: formValues.ucid, phone: formValues.phone, password: formValues.password, // This will be needed for the final signup address: formValues.address, // Add this line client: 1, admin: 0, }; // Send verification code await sendVerificationCode(newUser); } else { // Handle Login with API console.log("Login Attempt:", { email: formValues.email, password: formValues.password, }); // Make API call to localhost:3030/find_user const response = await fetch( "http://localhost:3030/api/user/do_login", { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ email: formValues.email, password: formValues.password, }), }, ); if (!response.ok) { throw new Error("Network response was not ok"); } const userData = await response.json(); if (userData && userData.found) { // Create user object const userObj = { ID: userData.userID, name: userData.name, email: userData.email, // Add any other user data returned from the API }; // Set authenticated user with data from API setUser(userObj); setIsAuthenticated(true); // Save to localStorage to persist across refreshes sessionStorage.setItem("isAuthenticated", "true"); sessionStorage.setItem("user", JSON.stringify(userObj)); console.log("Login successful for:", userData.email); // Start generating recommendations with a slight delay // This will happen in the useEffect, but we set a loading state to show to the user setIsGeneratingRecommendations(true); } else { // Show error message for invalid credentials setError("Invalid email or password"); console.log("Login failed: Invalid credentials"); } } } catch (err) { console.error("Authentication error:", err); setError("Authentication failed. Please try again later."); } finally { setIsLoading(false); } }; // Handle code verification submission const handleVerifySubmit = async (e) => { e.preventDefault(); const code = e.target.verificationCode.value; if (!code) { setError("Verification code is required"); return; } await verifyCode(code); }; const handleLogout = () => { // Clear authentication state setIsAuthenticated(false); setUser(null); setVerificationStep("initial"); setTempUserData(null); setRecommendations([]); setShowAdminDashboard(false); // Clear localStorage sessionStorage.removeItem("user"); sessionStorage.removeItem("isAuthenticated"); sessionStorage.removeItem("userRecommendations"); console.log("User logged out"); }; const toggleAuthMode = () => { setIsSignUp(!isSignUp); setError(""); // Clear errors when switching modes setVerificationStep("initial"); // Reset verification step }; // Resend verification code const handleResendCode = async () => { if (tempUserData) { await sendVerificationCode(tempUserData); } }; // Back to signup form const handleBackToSignup = () => { setVerificationStep("initial"); setError(""); }; const sendSessionDataToServer = async () => { try { // Retrieve data from sessionStorage const user = JSON.parse(sessionStorage.getItem("user")); if (!user || !isAuthenticated) { console.log("User is not authenticated"); return; } // Prepare the data to send const requestData = { userId: user.ID, // or user.ID depending on your user structure email: user.email, isAuthenticated, }; // Send data to Python server (replace with your actual server URL) const response = await fetch("http://0.0.0.0:5000/api/user/session", { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify(requestData), }); // Check the response if (response.ok) { const result = await response.json(); console.log("Server response:", result); } else { console.error("Failed to send session data to the server"); } } catch (error) { console.error("Error sending session data:", error); } }; // Loading overlay component const LoadingOverlay = () => (
{isSignUp ? verificationStep === "initial" ? "Set up your new account" : "Enter the verification code sent to your email" : "Sign in to your account"}
{isSignUp ? "Already have an account?" : "Don't have an account?"}{" "}