Added navigation menu in header.

This commit is contained in:
Josh 2025-05-02 15:39:51 +00:00
parent 8917e4890e
commit 34fda5760d
2 changed files with 168 additions and 38 deletions

View File

@ -1,5 +1,14 @@
import React, { useState, useEffect } from 'react';
import { Routes, Route, Navigate, useNavigate, useLocation } from 'react-router-dom';
import {
Routes,
Route,
Navigate,
useNavigate,
useLocation,
Link,
} from 'react-router-dom';
// Import all components from the components folder
import PremiumRoute from './components/PremiumRoute.js';
import SessionExpiredHandler from './components/SessionExpiredHandler.js';
import GettingStarted from './components/GettingStarted.js';
@ -18,16 +27,10 @@ function App() {
const navigate = useNavigate();
const location = useLocation();
// Track whether user is authenticated
const [isAuthenticated, setIsAuthenticated] = useState(false);
// Track the user object, including is_premium
const [user, setUser] = useState(null);
// We might also track a "loading" state so we don't redirect prematurely
const [isLoading, setIsLoading] = useState(true);
// Hide the "Upgrade to Premium" CTA on certain premium routes
const premiumPaths = [
'/milestone-tracker',
'/paywall',
@ -37,35 +40,30 @@ function App() {
];
const showPremiumCTA = !premiumPaths.includes(location.pathname);
// On first mount, rehydrate user if there's a token
// Rehydrate user if there's a token
useEffect(() => {
const token = localStorage.getItem('token');
if (!token) {
setIsLoading(false);
return; // No token => not authenticated
return;
}
// If we have a token, let's validate it and fetch user data
// Validate token/fetch user
fetch('https://dev1.aptivaai.com/api/user-profile', {
headers: {
Authorization: `Bearer ${token}`,
},
headers: { Authorization: `Bearer ${token}` },
})
.then((res) => {
if (!res.ok) {
// e.g. 401 means token invalid/expired
throw new Error('Token invalid or expired');
throw new Error('Token invalid/expired');
}
return res.json();
})
.then((profile) => {
// We have a valid user profile -> set states
setUser(profile);
setIsAuthenticated(true);
})
.catch((err) => {
console.error(err);
// If invalid, remove the token to avoid loops
localStorage.removeItem('token');
})
.finally(() => {
@ -73,8 +71,15 @@ function App() {
});
}, []);
// Logout
const handleLogout = () => {
localStorage.removeItem('token');
setIsAuthenticated(false);
setUser(null);
navigate('/signin');
};
if (isLoading) {
// Optionally show a loading spinner or placeholder
return (
<div className="flex h-screen items-center justify-center">
<p>Loading...</p>
@ -86,10 +91,138 @@ function App() {
<div className="flex min-h-screen flex-col bg-gray-50 text-gray-800">
{/* Header */}
<header className="flex items-center justify-between border-b bg-white px-6 py-4 shadow-sm">
<h1 className="text-lg font-semibold">
AptivaAI - Career Guidance Platform (beta)
</h1>
{showPremiumCTA && (
<div className="flex items-center space-x-8">
<h1 className="text-lg font-semibold">
AptivaAI - Career Guidance Platform (beta)
</h1>
{/* Navigation Menu */}
{isAuthenticated && (
<nav>
<ul className="flex space-x-4">
{/* Free sections */}
<li>
<Link
className="text-blue-600 hover:text-blue-800"
to="/getting-started"
>
Getting Started
</Link>
</li>
<li>
<Link
className="text-blue-600 hover:text-blue-800"
to="/interest-inventory"
>
Interest Inventory
</Link>
</li>
<li>
<Link
className="text-blue-600 hover:text-blue-800"
to="/dashboard"
>
Dashboard
</Link>
</li>
<li>
<Link
className="text-blue-600 hover:text-blue-800"
to="/profile"
>
Profile
</Link>
</li>
{/* Premium sections (greyed out if not is_premium) */}
<li>
{user?.is_premium ? (
<Link
className="text-blue-600 hover:text-blue-800"
to="/milestone-tracker"
>
Milestone Tracker
</Link>
) : (
<span className="text-gray-400 cursor-not-allowed">
Milestone Tracker{' '}
<span className="text-green-600">
(Premium Subscribers Only)
</span>
</span>
)}
</li>
<li>
{user?.is_premium ? (
<Link
className="text-blue-600 hover:text-blue-800"
to="/financial-profile"
>
Financial Profile
</Link>
) : (
<span className="text-gray-400 cursor-not-allowed">
Financial Profile{' '}
<span className="text-green-600">
(Premium Subscribers Only)
</span>
</span>
)}
</li>
<li>
{user?.is_premium ? (
<Link
className="text-blue-600 hover:text-blue-800"
to="/multi-scenario"
>
Multi Scenario
</Link>
) : (
<span className="text-gray-400 cursor-not-allowed">
Multi Scenario{' '}
<span className="text-green-600">
(Premium Subscribers Only)
</span>
</span>
)}
</li>
<li>
{user?.is_premium ? (
<Link
className="text-blue-600 hover:text-blue-800"
to="/premium-onboarding"
>
Premium Onboarding
</Link>
) : (
<span className="text-gray-400 cursor-not-allowed">
Premium Onboarding{' '}
<span className="text-green-600">
(Premium Subscribers Only)
</span>
</span>
)}
</li>
{/* Logout */}
<li>
<button
className="text-red-600 hover:text-red-800"
onClick={handleLogout}
>
Logout
</button>
</li>
</ul>
</nav>
)}
</div>
{/* "Upgrade to Premium" button if not premium and on a free path */}
{showPremiumCTA && isAuthenticated && !user?.is_premium && (
<button
className="rounded bg-blue-600 px-5 py-2 text-sm font-medium text-white transition-colors hover:bg-blue-700"
onClick={() => navigate('/paywall')}
@ -102,22 +235,19 @@ function App() {
{/* Main Content */}
<main className="flex-1 p-6">
<Routes>
{/* Default to /signin if no path */}
{/* Default to /signin */}
<Route path="/" element={<Navigate to="/signin" />} />
{/* Public routes */}
<Route
path="/signin"
element={
<SignIn
setIsAuthenticated={setIsAuthenticated}
setUser={setUser}
/>
<SignIn setIsAuthenticated={setIsAuthenticated} setUser={setUser} />
}
/>
<Route path="/signup" element={<SignUp />} />
{/* Paywall (accessible to all) */}
{/* Paywall (public) */}
<Route path="/paywall" element={<Paywall />} />
{/* Authenticated routes */}
@ -128,7 +258,7 @@ function App() {
<Route path="/dashboard" element={<Dashboard />} />
<Route path="/profile" element={<UserProfile />} />
{/* Premium-only routes use <PremiumRoute> */}
{/* Premium-only routes */}
<Route
path="/milestone-tracker"
element={
@ -145,14 +275,6 @@ function App() {
</PremiumRoute>
}
/>
<Route
path="/premium-onboarding"
element={
<PremiumRoute user={user}>
<OnboardingContainer />
</PremiumRoute>
}
/>
<Route
path="/multi-scenario"
element={
@ -161,10 +283,18 @@ function App() {
</PremiumRoute>
}
/>
<Route
path="/premium-onboarding"
element={
<PremiumRoute user={user}>
<OnboardingContainer />
</PremiumRoute>
}
/>
</>
)}
{/* Fallback if route not found */}
{/* 404 / Fallback */}
<Route path="*" element={<Navigate to="/signin" />} />
</Routes>
</main>

Binary file not shown.