import { useEffect, useState, type ReactNode } from 'react'; import { Routes, Route, Navigate, useLocation, useNavigate } from 'react-router-dom'; import { IconContext } from '@phosphor-icons/react'; import { LoginPage } from './components/auth/LoginPage'; import { RegisterPage } from './components/auth/RegisterPage'; import { InviteAcceptPage } from './components/auth/InviteAcceptPage'; import { AppLayout } from './components/layout/AppLayout'; import { MobileYouPage } from './components/layout/MobileYouPage'; import { TitleBar } from './components/layout/TitleBar'; import { ChannelView } from './components/channel/ChannelView'; import Recovery from './pages/Recovery'; import { usePlatform } from './platform'; import { useSearch } from './contexts/SearchContext'; import { useSystemBars } from './hooks/useSystemBars'; import './global.css'; const THIRTY_DAYS_MS = 30 * 24 * 60 * 60 * 1000; type AuthState = 'loading' | 'authenticated' | 'unauthenticated'; function AuthGuard({ children }: { children: ReactNode }) { const [authState, setAuthState] = useState('loading'); const location = useLocation(); const navigate = useNavigate(); const { session, settings } = usePlatform(); const searchCtx = useSearch(); useSystemBars(null); useEffect(() => { let cancelled = false; async function restoreSession() { if (sessionStorage.getItem('privateKey') && sessionStorage.getItem('signingKey')) { searchCtx?.initialize(); if (!cancelled) setAuthState('authenticated'); return; } if (session) { try { const savedSession = await session.load(); if (savedSession && savedSession.savedAt && Date.now() - savedSession.savedAt < THIRTY_DAYS_MS) { 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.masterKey) sessionStorage.setItem('masterKey', savedSession.masterKey); if (savedSession.searchDbKey) sessionStorage.setItem('searchDbKey', savedSession.searchDbKey); searchCtx?.initialize(); 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; } if (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 === '/login' || location.pathname === '/register' || location.pathname === '/recovery' || location.pathname.startsWith('/invite/'); const hasSession = !!(sessionStorage.getItem('privateKey') && sessionStorage.getItem('signingKey')); // Invite accept runs regardless of session — if the viewer is // already logged in, the InviteAcceptPage itself will forward // them home after stashing the keys. Don't redirect them away. const isInvitePage = location.pathname.startsWith('/invite/'); if (hasSession && isAuthPage && !isInvitePage) { navigate('/channels/@me', { replace: true }); } else if (!hasSession && !isAuthPage) { navigate('/login', { replace: true }); } }, [authState, location.pathname]); if (authState === 'loading') { return (
Loading...
); } return <>{children}; } function DMHomePage() { return (

Welcome to Brycord

Select a conversation or start a new one

); } function ServerPage() { return (

Select a channel to start chatting

); } function App() { return ( } /> } /> } /> } /> }> } /> } /> } /> } /> } /> } /> ); } export default App;