Files
DiscordClone/packages/shared/src/App.jsx
2026-02-16 13:08:39 -06:00

115 lines
3.8 KiB
JavaScript

import React, { useState, useEffect } from 'react';
import { Routes, Route, Navigate, useLocation, useNavigate } from 'react-router-dom';
import Login from './pages/Login';
import Register from './pages/Register';
import Chat from './pages/Chat';
import { usePlatform } from './platform';
import { useSearch } from './contexts/SearchContext';
const THIRTY_DAYS_MS = 30 * 24 * 60 * 60 * 1000;
function AuthGuard({ children }) {
const [authState, setAuthState] = useState('loading'); // 'loading' | 'authenticated' | 'unauthenticated'
const location = useLocation();
const navigate = useNavigate();
const { session, settings } = usePlatform();
const searchCtx = useSearch();
useEffect(() => {
let cancelled = false;
async function restoreSession() {
// Already have keys in sessionStorage — current session is active
if (sessionStorage.getItem('privateKey') && sessionStorage.getItem('signingKey')) {
searchCtx?.initialize();
if (!cancelled) setAuthState('authenticated');
return;
}
// Try restoring from safeStorage
if (session) {
try {
const savedSession = await session.load();
if (savedSession && savedSession.savedAt && (Date.now() - savedSession.savedAt) < THIRTY_DAYS_MS) {
// Restore to localStorage + sessionStorage
localStorage.setItem('userId', savedSession.userId);
localStorage.setItem('username', savedSession.username);
if (savedSession.publicKey) localStorage.setItem('publicKey', savedSession.publicKey);
sessionStorage.setItem('signingKey', savedSession.signingKey);
sessionStorage.setItem('privateKey', savedSession.privateKey);
if (savedSession.searchDbKey) sessionStorage.setItem('searchDbKey', savedSession.searchDbKey);
searchCtx?.initialize();
// Restore user preferences from file-based backup into localStorage
if (settings) {
try {
const savedPrefs = await settings.get(`userPrefs_${savedSession.userId}`);
if (savedPrefs && typeof savedPrefs === 'object') {
localStorage.setItem(`userPrefs_${savedSession.userId}`, JSON.stringify(savedPrefs));
}
} catch {}
}
if (!cancelled) setAuthState('authenticated');
return;
}
// Expired — clear stale session
if (savedSession && savedSession.savedAt) {
await session.clear();
}
} catch (err) {
console.error('Session restore failed:', err);
}
}
if (!cancelled) setAuthState('unauthenticated');
}
restoreSession();
return () => { cancelled = true; };
}, []);
useEffect(() => {
if (authState === 'loading') return;
const isAuthPage = location.pathname === '/' || location.pathname === '/register';
const hasSession = sessionStorage.getItem('privateKey') && sessionStorage.getItem('signingKey');
if (hasSession && isAuthPage) {
navigate('/chat', { replace: true });
} else if (!hasSession && !isAuthPage) {
navigate('/', { replace: true });
}
}, [authState, location.pathname]);
if (authState === 'loading') {
return (
<div style={{
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
height: '100vh',
backgroundColor: 'var(--bg-primary, #313338)',
color: 'var(--text-normal, #dbdee1)',
fontSize: '16px',
}}>
Loading...
</div>
);
}
return children;
}
function App() {
return (
<AuthGuard>
<Routes>
<Route path="/" element={<Login />} />
<Route path="/register" element={<Register />} />
<Route path="/chat" element={<Chat />} />
</Routes>
</AuthGuard>
);
}
export default App;