Some checks failed
- Add buyPrice and buyDate to positions for PnL tracking - Implement backend analytics service for real-time portfolio performance - Add server-side security screener with filtering, sorting, and pagination - Update frontend UI with analytics summaries and sortable screener table - Optimize MOEX API calls with batch fetching and portfolio-specific caching - Add unit tests for analytics and screener services
113 lines
3.0 KiB
TypeScript
113 lines
3.0 KiB
TypeScript
import { Outlet, Link, useNavigate } from 'react-router-dom';
|
||
import { SearchBar } from './SearchBar';
|
||
import { useAuth } from '../hooks/useAuth';
|
||
|
||
export function Layout() {
|
||
const { isAuthenticated, user, logout } = useAuth();
|
||
const navigate = useNavigate();
|
||
|
||
async function handleLogout() {
|
||
await logout();
|
||
navigate('/');
|
||
}
|
||
|
||
return (
|
||
<div style={{ minHeight: '100vh', display: 'flex', flexDirection: 'column' }}>
|
||
<header
|
||
style={{
|
||
background: 'var(--color-surface)',
|
||
borderBottom: '1px solid #e0e0e0',
|
||
padding: '12px 24px',
|
||
display: 'flex',
|
||
alignItems: 'center',
|
||
gap: 24,
|
||
}}
|
||
>
|
||
<Link
|
||
to="/"
|
||
style={{
|
||
fontSize: 20,
|
||
fontWeight: 700,
|
||
color: 'var(--color-text)',
|
||
textDecoration: 'none',
|
||
}}
|
||
>
|
||
MoexVibe
|
||
</Link>
|
||
<SearchBar />
|
||
<Link
|
||
to="/portfolios"
|
||
style={{
|
||
fontSize: 14,
|
||
color: 'var(--color-text)',
|
||
textDecoration: 'none',
|
||
fontWeight: 500,
|
||
}}
|
||
>
|
||
Портфели
|
||
</Link>
|
||
<Link
|
||
to="/screener"
|
||
style={{
|
||
fontSize: 14,
|
||
color: 'var(--color-text)',
|
||
textDecoration: 'none',
|
||
fontWeight: 500,
|
||
}}
|
||
>
|
||
Скринер
|
||
</Link>
|
||
|
||
<div style={{ marginLeft: 'auto', display: 'flex', alignItems: 'center', gap: 12 }}>
|
||
{isAuthenticated ? (
|
||
<>
|
||
<Link
|
||
to="/profile"
|
||
style={{
|
||
fontSize: 14,
|
||
color: 'var(--color-text)',
|
||
textDecoration: 'none',
|
||
}}
|
||
>
|
||
{user?.name || user?.email}
|
||
</Link>
|
||
<button
|
||
onClick={handleLogout}
|
||
style={{
|
||
padding: '6px 16px',
|
||
background: 'transparent',
|
||
color: 'var(--color-text-secondary)',
|
||
border: '1px solid #e0e0e0',
|
||
borderRadius: 'var(--border-radius)',
|
||
fontSize: 14,
|
||
cursor: 'pointer',
|
||
}}
|
||
>
|
||
Выйти
|
||
</button>
|
||
</>
|
||
) : (
|
||
<Link
|
||
to="/login"
|
||
style={{
|
||
padding: '6px 16px',
|
||
background: 'var(--color-primary)',
|
||
color: '#fff',
|
||
textDecoration: 'none',
|
||
borderRadius: 'var(--border-radius)',
|
||
fontSize: 14,
|
||
fontWeight: 600,
|
||
}}
|
||
>
|
||
Войти
|
||
</Link>
|
||
)}
|
||
</div>
|
||
</header>
|
||
<main style={{ flex: 1, padding: 24, maxWidth: 1200, width: '100%', margin: '0 auto' }}>
|
||
<Outlet />
|
||
</main>
|
||
</div>
|
||
);
|
||
}
|