import React, { useState, useEffect, useMemo } from 'react'; import { Routes, Route, Navigate, useNavigate, useLocation, Link, } from 'react-router-dom'; import { Button } from './components/ui/button.js'; import { cn } from './utils/cn.js'; import PromptModal from './components/ui/PromptModal.js'; import PremiumRoute from './components/PremiumRoute.js'; import SessionExpiredHandler from './components/SessionExpiredHandler.js'; import SignInLanding from './components/SignInLanding.js'; import SignIn from './components/SignIn.js'; import SignUp from './components/SignUp.js'; import PlanningLanding from './components/PlanningLanding.js'; import CareerExplorer from './components/CareerExplorer.js'; import PreparingLanding from './components/PreparingLanding.js'; import EducationalProgramsPage from './components/EducationalProgramsPage.js'; import EnhancingLanding from './components/EnhancingLanding.js'; import RetirementLanding from './components/RetirementLanding.js'; import InterestInventory from './components/InterestInventory.js'; import UserProfile from './components/UserProfile.js'; import FinancialProfileForm from './components/FinancialProfileForm.js'; import CareerProfileList from './components/CareerProfileList.js'; import CareerProfileForm from './components/CareerProfileForm.js'; import CollegeProfileList from './components/CollegeProfileList.js'; import CollegeProfileForm from './components/CollegeProfileForm.js'; import CareerRoadmap from './components/CareerRoadmap.js'; import Paywall from './components/Paywall.js'; import OnboardingContainer from './components/PremiumOnboarding/OnboardingContainer.js'; import RetirementPlanner from './components/RetirementPlanner.js'; import ResumeRewrite from './components/ResumeRewrite.js'; import LoanRepaymentPage from './components/LoanRepaymentPage.js'; import usePageContext from './utils/usePageContext.js'; import ChatDrawer from './components/ChatDrawer.js'; import ChatCtx from './contexts/ChatCtx.js'; import BillingResult from './components/BillingResult.js'; import SupportModal from './components/SupportModal.js'; import ForgotPassword from './components/ForgotPassword.js'; import ResetPassword from './components/ResetPassword.js'; import { clearToken } from './auth/authMemory.js'; export const ProfileCtx = React.createContext(); function ResetPasswordGate() { const location = useLocation(); useEffect(() => { try { localStorage.removeItem('token'); localStorage.removeItem('id'); // If you cache other auth-ish flags, clear them here too } catch {} // no navigate here; we want to render the reset UI }, [location.pathname]); return ; } function App() { const navigate = useNavigate(); const location = useLocation(); const { pageContext, snapshot: routeSnapshot } = usePageContext(); const [drawerOpen, setDrawerOpen] = useState(false); const [drawerPane, setDrawerPane] = useState('support'); const [retireProps, setRetireProps] = useState(null); const [supportOpen, setSupportOpen] = useState(false); const [userEmail, setUserEmail] = useState(''); const AUTH_HOME = '/signin-landing'; /* ------------------------------------------ ChatDrawer – route-aware tool handlers ------------------------------------------ */ const uiToolHandlers = useMemo(() => { if (pageContext === "CareerExplorer") { return { // __tool:addCareerToComparison:{"socCode":"15-2051","careerName":"Data Scientist"} addCareerToComparison: ({ socCode, careerName }) => { console.log('[dispatch]', socCode, careerName); window.dispatchEvent( new CustomEvent("add-career", { detail: { socCode, careerName } }) ); }, // __tool:openCareerModal:{"socCode":"15-2051"} openCareerModal: ({ socCode }) => { window.dispatchEvent( new CustomEvent("open-career", { detail: { socCode } }) ); } }; } return {}; // every other page exposes no UI tools }, [pageContext]); // Retirement bot is only relevant on these pages const canShowRetireBot = pageContext === 'RetirementPlanner' || pageContext === 'RetirementLanding'; // Auth states const [isAuthenticated, setIsAuthenticated] = useState(false); const [user, setUser] = useState(null); const [chatSnapshot, setChatSnapshot] = useState(null); // Loading state while verifying token const [isLoading, setIsLoading] = useState(true); // User states const [financialProfile, setFinancialProfile] = useState(null); const [scenario, setScenario] = useState(null); // Logout warning modal const [showLogoutWarning, setShowLogoutWarning] = useState(false); // Check if user can access premium const canAccessPremium = user?.is_premium || user?.is_pro_premium; const isAuthScreen = React.useMemo(() => { const p = location.pathname; return ( p === '/signin' || p === '/signup' || p === '/forgot-password' || p.startsWith('/reset-password') ); }, [location.pathname]); const showAuthedNav = isAuthenticated && !isAuthScreen; // List of premium paths for your CTA logic const premiumPaths = [ '/career-roadmap', '/paywall', '/financial-profile', '/retirement-planner', '/premium-onboarding', '/enhancing', '/retirement', '/resume-optimizer', ]; const showPremiumCTA = !premiumPaths.some(p => location.pathname.startsWith(p) ); // Helper to see if user is mid–premium-onboarding function isOnboardingInProgress() { try { const stored = JSON.parse(localStorage.getItem('premiumOnboardingState') || '{}'); // If step < 4 (example), user is in progress return stored.step && stored.step < 4; } catch (e) { return false; } } /* ===================== Support Modal Email ===================== */ useEffect(() => { setUserEmail(user?.email || ''); }, [user]); /* Multi-tab signout listener */ useEffect(() => { const onStorage = (e) => { if (e.key === 'token' && !e.newValue) { // another tab cleared the token clearToken(); setIsAuthenticated(false); setUser(null); navigate('/signin?session=expired'); } }; window.addEventListener('storage', onStorage); return () => window.removeEventListener('storage', onStorage); }, [navigate]); // ============================== // 1) Single Rehydrate UseEffect (cookie mode) // ============================== useEffect(() => { let cancelled = false; (async () => { const isAuthRoute = location.pathname === '/signin' || location.pathname === '/signup' || location.pathname === '/forgot-password' || location.pathname.startsWith('/reset-password'); if (isAuthRoute) { try { localStorage.removeItem('token'); localStorage.removeItem('id'); } catch {} if (!cancelled) { setIsAuthenticated(false); setUser(null); setIsLoading(false); } return; } try { // Cookie goes automatically; shim sends credentials:'include' const res = await fetch('/api/user-profile', { credentials: 'include' }); if (!res.ok) throw new Error('unauthorized'); const profile = await res.json(); if (cancelled) return; setUser(profile); setFinancialProfile(profile); setIsAuthenticated(true); } catch { if (cancelled) return; setIsAuthenticated(false); setUser(null); } finally { if (!cancelled) setIsLoading(false); } })(); return () => { cancelled = true; }; }, [location.pathname]); // ========================== // 2) Logout Handler + Modal // ========================== const handleLogoutClick = () => { if (isOnboardingInProgress()) { // Show a modal to confirm losing onboarding data setShowLogoutWarning(true); } else { // No onboarding => just logout confirmLogout(); } }; const confirmLogout = async () => { // Clear any sensitive values from Web Storage [ 'token', 'id', 'careerSuggestionsCache', 'lastSelectedCareerProfileId', 'selectedCareer', 'aiClickCount', 'aiClickDate', 'aiRecommendations', 'premiumOnboardingState', 'financialProfile' ].forEach(k => { try { localStorage.removeItem(k); } catch {} }); // Clear in-memory token try { await fetch('/api/logout', { method: 'POST', credentials: 'include' }); } catch {} try { clearToken(); } catch {} // Reset React state/context setFinancialProfile(null); setScenario(null); setIsAuthenticated(false); setUser(null); setShowLogoutWarning(false); // Navigate to Sign In navigate('/signin'); }; const cancelLogout = () => { setShowLogoutWarning(false); }; // ==================================== // 3) If still verifying the token, show loading // ==================================== if (isLoading) { return (

Loading...

); } // ===================== // Main Render / Layout // ===================== return ( { setDrawerPane('support'); setDrawerOpen(true); }, openRetire : (props) => { if (!canShowRetireBot) { console.warn('Retirement bot disabled on this page'); return; } setRetireProps(props); setDrawerPane('retire'); setDrawerOpen(true); } }}>
{/* Header */}

AptivaAI - Career Guidance Platform

{showAuthedNav && ( <> {/* NAV MENU */} {/* LOGOUT + UPGRADE BUTTONS */}
{showPremiumCTA && !canAccessPremium && ( )} setSupportOpen(false)} userEmail={userEmail} /> {/* LOGOUT BUTTON */} {/* SHOW WARNING MODAL IF needed */} {showLogoutWarning && ( )}
)}
{/* MAIN CONTENT */}
{/* Default */} } /> } /> {/* Public (guest-only) routes */} ) : ( ) } /> : } /> : } /> } /> {/* Authenticated routes */} {isAuthenticated && ( <> } /> } /> } /> } /> } /> } /> } /> } /> } /> {/* Premium-wrapped */} } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> )} {/* 404 / Fallback */} } />
{/* Session Handler (Optional) */}
); } export default App;