import React, { useState, useEffect, useCallback } from 'react'; import { useNavigate, Link } from 'react-router-dom'; import AddPurchase from '../components/AddPurchase'; import PurchaseList from '../components/PurchaseList'; import PortfolioChart from '../components/PortfolioChart'; import BTCCandlestickChart from '../components/BTCCandlestickChart'; const API = process.env.REACT_APP_API_URL || 'http://localhost:8000'; const styles = { app: { maxWidth: '900px', margin: '0 auto', padding: '1.5rem' }, header: { display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '1.5rem' }, logo: { fontSize: '1.4rem', fontWeight: 700, color: '#f7931a' }, logoutBtn: { background: 'none', border: '1px solid #555', color: '#aaa', borderRadius: '8px', padding: '0.4rem 1rem', cursor: 'pointer' }, adminBtn: { background: 'none', border: '1px solid #f7931a', color: '#f7931a', borderRadius: '8px', padding: '0.4rem 1rem', cursor: 'pointer', textDecoration: 'none', fontSize: '1rem' }, headerBtns: { display: 'flex', gap: '0.5rem', alignItems: 'center' }, statsGrid: { display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: '1rem', marginBottom: '1.5rem' }, statCard: { background: '#1a1a1a', padding: '1rem', borderRadius: '12px', border: '1px solid #333' }, statLabel: { color: '#888', fontSize: '0.8rem', marginBottom: '0.3rem' }, statValue: { fontSize: '1.2rem', fontWeight: 700 }, positive: { color: '#6bff8e' }, negative: { color: '#ff6b6b' }, neutral: { color: '#f7931a' }, tabs: { display: 'flex', gap: '0.5rem', marginBottom: '1rem' }, tab: { padding: '0.45rem 1.1rem', borderRadius: '8px', border: '1px solid #444', background: 'none', color: '#888', cursor: 'pointer', fontSize: '0.9rem' }, tabActive: { padding: '0.45rem 1.1rem', borderRadius: '8px', border: '1px solid #f7931a', background: 'rgba(247,147,26,0.1)', color: '#f7931a', cursor: 'pointer', fontSize: '0.9rem', fontWeight: 700 }, }; function StatCard({ label, value, highlight }) { return (
{label}
{value}
); } export default function Dashboard() { const [stats, setStats] = useState(null); const [purchases, setPurchases] = useState([]); const [candles, setCandles] = useState(null); const [candlesAll, setCandlesAll] = useState(null); const [fullscreenChart, setFullscreenChart] = useState(false); const [chartView, setChartView] = useState('both'); // 'both' | 'portfolio' | 'history' const navigate = useNavigate(); const authHeaders = () => ({ Authorization: `Bearer ${localStorage.getItem('token')}`, }); const fetchData = useCallback(async () => { try { const [statsRes, purchasesRes, candlesRes] = await Promise.all([ fetch(`${API}/stats`, { headers: authHeaders() }), fetch(`${API}/purchases`, { headers: authHeaders() }), fetch(`${API}/candles?days=365`, { headers: authHeaders() }), ]); if (statsRes.status === 401) { localStorage.removeItem('token'); navigate('/login'); return; } setStats(await statsRes.json()); setPurchases(await purchasesRes.json()); setCandles(await candlesRes.json()); } catch { // silently fail — network may be unavailable } }, [navigate]); const fetchAllCandles = useCallback(async () => { try { const res = await fetch(`${API}/candles?days=all`, { headers: authHeaders() }); if (res.ok) setCandlesAll(await res.json()); } catch { // silently fail } }, []); useEffect(() => { fetchData(); }, [fetchData]); const isAdmin = localStorage.getItem('is_admin') === 'true'; const handleLogout = () => { localStorage.removeItem('token'); localStorage.removeItem('is_admin'); navigate('/login'); }; const handleToggleFullscreen = useCallback(() => { if (!fullscreenChart && !candlesAll) fetchAllCandles(); setFullscreenChart(f => !f); }, [fullscreenChart, candlesAll, fetchAllCandles]); const plHighlight = stats ? stats.profit_loss >= 0 ? 'positive' : 'negative' : 'neutral'; // Fullscreen uses all-candles data once loaded, otherwise falls back to 365-day set const activeCandles = (fullscreenChart && candlesAll) ? candlesAll : candles; return (
₿ BTC Portfolio
{isAdmin && Manage Users}
{stats && (
= 0 ? '+' : ''}€${stats.profit_loss.toLocaleString()}`} highlight={plHighlight} />
)}
{[['both', 'Both'], ['portfolio', 'Portfolio'], ['history', 'BTC Candles']].map(([key, label]) => ( ))}
{(chartView === 'both' || chartView === 'portfolio') && } {(chartView === 'both' || chartView === 'history') && ( )}
); }