feat: Add new emoji assets and an UpdateBanner component.
Some checks failed
Build and Release / build-and-release (push) Failing after 3m28s
Some checks failed
Build and Release / build-and-release (push) Failing after 3m28s
This commit is contained in:
112
packages/shared/src/App.jsx
Normal file
112
packages/shared/src/App.jsx
Normal file
@@ -0,0 +1,112 @@
|
||||
import React, { useState, useEffect, useRef } 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';
|
||||
|
||||
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();
|
||||
|
||||
useEffect(() => {
|
||||
let cancelled = false;
|
||||
|
||||
async function restoreSession() {
|
||||
// Already have keys in sessionStorage — current session is active
|
||||
if (sessionStorage.getItem('privateKey') && sessionStorage.getItem('signingKey')) {
|
||||
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);
|
||||
// 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; };
|
||||
}, []);
|
||||
|
||||
// Redirect once after auth state is determined (not on every route change)
|
||||
const hasRedirected = useRef(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (authState === 'loading' || hasRedirected.current) return;
|
||||
hasRedirected.current = true;
|
||||
|
||||
const isAuthPage = location.pathname === '/' || location.pathname === '/register';
|
||||
|
||||
if (authState === 'authenticated' && isAuthPage) {
|
||||
navigate('/chat', { replace: true });
|
||||
} else if (authState === 'unauthenticated' && !isAuthPage) {
|
||||
navigate('/', { replace: true });
|
||||
}
|
||||
}, [authState]);
|
||||
|
||||
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;
|
||||
Reference in New Issue
Block a user