Added navigation menu in header.
This commit is contained in:
parent
8917e4890e
commit
34fda5760d
206
src/App.js
206
src/App.js
@ -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>
|
||||
|
BIN
user_profile.db
BIN
user_profile.db
Binary file not shown.
Loading…
Reference in New Issue
Block a user