import React, { useState, useEffect, useCallback } from 'react'; import { Link, useNavigate } from 'react-router-dom'; import { useTranslation } from 'react-i18next'; import { useAuth } from '../context/AuthContext'; import { dashboardService, accountService } from '../services/api'; import useFormatters from '../hooks/useFormatters'; import CashflowChart from '../components/dashboard/CashflowChart'; import BalanceProjectionChart from '../components/dashboard/BalanceProjectionChart'; import OverpaymentsAnalysis from '../components/dashboard/OverpaymentsAnalysis'; import CalendarWidget from '../components/dashboard/CalendarWidget'; import UpcomingWidget from '../components/dashboard/UpcomingWidget'; import OverdueWidget from '../components/dashboard/OverdueWidget'; const Dashboard = () => { const { user } = useAuth(); const { t, i18n } = useTranslation(); const { currency } = useFormatters(); const navigate = useNavigate(); // Estados const [loading, setLoading] = useState(true); const [cashflowLoading, setCashflowLoading] = useState(true); const [variancesLoading, setVariancesLoading] = useState(true); // Dados do dashboard const [summary, setSummary] = useState(null); const [cashflow, setCashflow] = useState(null); const [variances, setVariances] = useState(null); const [accounts, setAccounts] = useState([]); // Filtros dos gráficos const [cashflowMonths, setCashflowMonths] = useState(12); const [variancesMonths, setVariancesMonths] = useState(12); // Carregar resumo geral const loadSummary = useCallback(async () => { try { const [summaryData, accountsData] = await Promise.all([ dashboardService.getSummary(), accountService.getAll(), ]); setSummary(summaryData); setAccounts(accountsData.data || []); } catch (error) { console.error('Error loading summary:', error); } finally { setLoading(false); } }, []); // Carregar fluxo de caixa const loadCashflow = useCallback(async () => { setCashflowLoading(true); try { const data = await dashboardService.getCashflow(cashflowMonths); setCashflow(data); } catch (error) { console.error('Error loading cashflow:', error); } finally { setCashflowLoading(false); } }, [cashflowMonths]); // Carregar variações de pagamento const loadVariances = useCallback(async () => { setVariancesLoading(true); try { const data = await dashboardService.getPaymentVariances(variancesMonths); setVariances(data); } catch (error) { console.error('Error loading variances:', error); } finally { setVariancesLoading(false); } }, [variancesMonths]); useEffect(() => { loadSummary(); }, [loadSummary]); useEffect(() => { loadCashflow(); }, [loadCashflow]); useEffect(() => { loadVariances(); }, [loadVariances]); // Handlers const handleMonthsChange = (months) => { setCashflowMonths(months); }; const handleVariancesMonthsChange = (months) => { setVariancesMonths(months); }; const handleTransactionClick = (transactionId) => { navigate(`/transactions?highlight=${transactionId}`); }; // Componente de Stat Card modernizado const StatCard = ({ icon, label, value, valueColor = 'text-white', trend = null, trendUp = true, subValue = null, accentColor = '#3b82f6' }) => (

{label}

{loading ? (
) : (
{value}
)} {subValue && !loading && ( {subValue} )}
{trend !== null && !loading && (
{trend} {t('dashboard.vsLastMonth')}
)}
); // Componente de conta const AccountItem = ({ account }) => { const balance = parseFloat(account.current_balance); const isPositive = balance >= 0; const getAccountIcon = (type) => { const icons = { 'checking': 'bi-bank', 'savings': 'bi-piggy-bank', 'credit_card': 'bi-credit-card', 'investment': 'bi-graph-up-arrow', 'cash': 'bi-wallet2', }; return icons[type] || 'bi-wallet2'; }; return (
{account.name}
{account.bank_name || t(`accounts.types.${account.type}`)}
{currency(balance, account.currency || 'BRL')}
{!account.include_in_total && ( {t('accounts.notInTotal')} )}
); }; return (
{/* Header */}

{t('dashboard.welcome')}, {user?.name?.split(' ')[0]}! 👋

{new Date().toLocaleDateString(i18n.language === 'pt-BR' ? 'pt-BR' : i18n.language === 'es' ? 'es-ES' : 'en-US', { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' })}

{t('nav.transactions')} {t('nav.import')}
{/* Stats Cards Row - Multi-currency */}
0 ? Object.entries(summary.balances_by_currency).map(([curr, val]) => (
{currency(val, curr)}
)) : currency(0, 'BRL') } valueColor={ summary?.balances_by_currency ? Object.values(summary.balances_by_currency).reduce((a, b) => a + b, 0) >= 0 ? 'text-success' : 'text-danger' : 'text-success' } accentColor={ summary?.balances_by_currency ? Object.values(summary.balances_by_currency).reduce((a, b) => a + b, 0) >= 0 ? '#22c55e' : '#ef4444' : '#22c55e' } />
0 ? Object.entries(summary.current_month_by_currency.income).map(([curr, val]) => (
{currency(val, curr)}
)) : currency(0, summary?.primary_currency || 'BRL') } valueColor="text-success" accentColor="#22c55e" />
0 ? Object.entries(summary.current_month_by_currency.expense).map(([curr, val]) => (
{currency(val, curr)}
)) : currency(0, summary?.primary_currency || 'BRL') } valueColor="text-danger" accentColor="#ef4444" />
0 ? `⚠️ ${summary.overdue.count} ${t('dashboard.overdue')}` : null } accentColor="#f59e0b" />
{/* Calendário e Transações Futuras */}
{/* Transacciones Vencidas - Fila independiente */}
{/* Projeção de Saldo - Full Width */}
{/* Main Content Grid */}
{/* Coluna Principal - Fluxo de Caixa */}
{t('dashboard.cashflow')}
{[6, 12, 24].map(months => ( ))}
{/* Resumo do período */} {cashflow && !cashflowLoading && (
{t('dashboard.totalIncome')} {currency(cashflow.totals?.income || 0, summary?.primary_currency || 'EUR')}
{t('dashboard.totalExpenses')} {currency(cashflow.totals?.expense || 0, summary?.primary_currency || 'EUR')}
{t('dashboard.avgIncome')} {currency(cashflow.totals?.average_income || 0, summary?.primary_currency || 'EUR')}
{t('dashboard.avgExpense')} {currency(cashflow.totals?.average_expense || 0, summary?.primary_currency || 'EUR')}
)}
{/* Coluna Lateral - Contas */}
{t('dashboard.accountBalances')}
{t('common.viewAll')}
{loading ? (
{[1, 2, 3].map(i => (
))}
) : accounts.length === 0 ? (

{t('dashboard.noAccounts')}

{t('dashboard.createAccount')}
) : (
{accounts .filter(a => a.is_active) .sort((a, b) => Math.abs(b.current_balance) - Math.abs(a.current_balance)) .map(account => ( ))}
)}
{/* Análise de Sobrepagamentos - Full Width */}
{/* CSS inline para efeitos hover */}
); }; export default Dashboard;