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]);
// ==============================
// 1) Single Rehydrate UseEffect
// ==============================
useEffect(() => {
// 🚫 Never hydrate auth while on the reset page
if (location.pathname.startsWith('/reset-password')) {
try {
localStorage.removeItem('token');
localStorage.removeItem('id');
} catch {}
setIsAuthenticated(false);
setUser(null);
setIsLoading(false);
return;
}
const token = localStorage.getItem('token');
if (!token) {
// No token => not authenticated
setIsLoading(false);
return;
}
// If we have a token, validate it by fetching user
fetch('/api/user-profile', {
headers: { Authorization: `Bearer ${token}` },
})
.then((res) => {
if (!res.ok) throw new Error('Token invalid on server side');
return res.json();
})
.then((profile) => {
// Successfully got user profile => user is authenticated
setUser(profile);
setIsAuthenticated(true);
})
.catch((err) => {
console.error(err);
// Invalid token => remove it, force sign in
localStorage.removeItem('token');
setIsAuthenticated(false);
setUser(null);
navigate('/signin?session=expired');
})
.finally(() => {
// Either success or fail, we're done loading
setIsLoading(false);
});
}, [navigate, 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 = () => {
localStorage.removeItem('token');
localStorage.removeItem('id');
localStorage.removeItem('careerSuggestionsCache');
localStorage.removeItem('lastSelectedCareerProfileId');
localStorage.removeItem('selectedCareer');
localStorage.removeItem('aiClickCount');
localStorage.removeItem('aiClickDate');
localStorage.removeItem('aiRecommendations');
localStorage.removeItem('premiumOnboardingState'); // ← NEW
localStorage.removeItem('financialProfile'); // ← if you cache it
setFinancialProfile(null); // ← reset any React-context copy
setScenario(null);
setIsAuthenticated(false);
setUser(null);
setShowLogoutWarning(false);
// Reset auth
setIsAuthenticated(false);
setUser(null);
setShowLogoutWarning(false);
navigate('/signin');
};
const cancelLogout = () => {
setShowLogoutWarning(false);
};
// ====================================
// 3) If still verifying the token, show loading
// ====================================
if (isLoading) {
return (
);
}
// =====================
// 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 */}
{/* MAIN CONTENT */}
{/* Default */}
}
/>
} />
{/* Public (guest-only) routes */}
) : (
)
}
/>
: }
/>
: }
/>
} />
{/* Authenticated routes */}
{isAuthenticated && (
<>
} />
} />
} />
} />
} />
} />
} />
} />
} />
{/* Premium-wrapped */}
}
/>
}
/>
}
/>
} />
} />
} />
} />
}
/>
}
/>
}
/>
}
/>
>
)}
{/* 404 / Fallback */}
}
/>
{/* Session Handler (Optional) */}
);
}
export default App;