bigwolfe
Add demo token endpoint and read-only frontend handling
ffcd038
import { useEffect, useState } from 'react';
import { BrowserRouter, Routes, Route, Navigate, useNavigate, useLocation } from 'react-router-dom';
import { MainApp } from './pages/MainApp';
import { Login } from './pages/Login';
import { Settings } from './pages/Settings';
import { isAuthenticated, getCurrentUser, setAuthTokenFromHash, ensureDemoToken, isDemoSession } from './services/auth';
import { AuthLoadingSkeleton } from './components/AuthLoadingSkeleton';
import { Toaster } from './components/ui/toaster';
import './App.css';
// Protected route wrapper with auth check
function ProtectedRoute({ children }: { children: React.ReactNode }) {
const navigate = useNavigate();
const location = useLocation();
const [isChecking, setIsChecking] = useState(true);
const [hasToken, setHasToken] = useState<boolean>(isAuthenticated());
// T110: Check if user is authenticated on mount
useEffect(() => {
const checkAuth = async () => {
// Check for OAuth callback token in URL hash
const tokenExtracted = setAuthTokenFromHash();
if (tokenExtracted) {
console.log('OAuth token extracted from URL hash');
setHasToken(true);
setIsChecking(false);
return;
}
if (!isAuthenticated()) {
const demoReady = await ensureDemoToken();
if (!demoReady) {
setHasToken(false);
setIsChecking(false);
return;
}
}
setHasToken(true);
if (isDemoSession()) {
setIsChecking(false);
return;
}
const token = localStorage.getItem('auth_token');
// Skip validation for local dev token
if (token === 'local-dev-token') {
setIsChecking(false);
return;
}
try {
// Verify the token is valid by calling getCurrentUser
await getCurrentUser();
setIsChecking(false);
} catch {
// Token is invalid (401), redirect to login
console.warn('Authentication failed, redirecting to login');
localStorage.removeItem('auth_token');
setHasToken(false);
setIsChecking(false);
if (location.pathname !== '/login') {
navigate('/login', { replace: true, state: { from: location } });
}
}
};
checkAuth();
}, [navigate, location]);
if (isChecking) {
return <AuthLoadingSkeleton />;
}
if (!hasToken) {
return <Navigate to="/login" replace />;
}
return <>{children}</>;
}
function App() {
return (
<>
<BrowserRouter>
<Routes>
<Route path="/login" element={<Login />} />
<Route
path="/"
element={
<ProtectedRoute>
<MainApp />
</ProtectedRoute>
}
/>
<Route
path="/settings"
element={
<ProtectedRoute>
<Settings />
</ProtectedRoute>
}
/>
</Routes>
</BrowserRouter>
<Toaster />
</>
);
}
export default App;