import { useState, useEffect, useCallback } from 'react' import { motion } from 'framer-motion' import { Link } from 'react-router-dom' import { BarChart, Bar, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer, Legend, PieChart, Pie, Cell, } from 'recharts' import { Zap, RefreshCw, ArrowLeft, TrendingUp, TrendingDown, DollarSign, Receipt, PiggyBank, Activity, LayoutDashboard, } from 'lucide-react' interface FinancialData { vendas_mes: number vendas_ano: number despesas_mes: number despesas_ano: number lucro_mes: number lucro_ano: number categorias: { name: string; value: number }[] evolucao: { mes: string; receita: number; despesa: number }[] } const containerVariants = { hidden: { opacity: 0 }, show: { opacity: 1, transition: { staggerChildren: 0.05 } } } const itemVariants = { hidden: { opacity: 0, y: 20 }, show: { opacity: 1, y: 0 } } const PIE_COLORS = [ '#10b981', '#8b5cf6', '#f59e0b', '#3b82f6', '#ef4444', '#06b6d4', '#ec4899', '#84cc16', '#f97316', '#6366f1', '#14b8a6', '#e879f9', '#a3e635', '#fb923c', '#818cf8', ] const formatEUR = (v: number) => `${v.toLocaleString('pt-PT', { minimumFractionDigits: 0, maximumFractionDigits: 0 })}€` const formatMesLabel = (mes: string) => { const [, m] = mes.split('-') const nomes = ['', 'Jan', 'Fev', 'Mar', 'Abr', 'Mai', 'Jun', 'Jul', 'Ago', 'Set', 'Out', 'Nov', 'Dez'] return nomes[parseInt(m)] || mes } const StatCard = ({ label, value, icon: Icon, color, sub }: { label: string; value: string; icon: React.ElementType; color: string; sub?: string }) => (
{label}
{value}
{sub &&
{sub}
}
) const CustomTooltip = ({ active, payload, label }: any) => { if (!active || !payload?.length) return null return (

{label}

{payload.map((p: any, i: number) => (

{p.name}: {formatEUR(p.value)}

))}
) } export default function Financial() { const [data, setData] = useState(null) const [loading, setLoading] = useState(true) const [refreshing, setRefreshing] = useState(false) const fetchData = useCallback(async () => { setRefreshing(true) try { const response = await fetch('/api/financial') if (!response.ok) throw new Error('Failed') const json = await response.json() setData(json) } catch { console.error('Failed to fetch financial data') } finally { setLoading(false) setRefreshing(false) } }, []) useEffect(() => { fetchData() }, [fetchData]) if (loading) { return (

A carregar dados financeiros...

) } if (!data) return null const lucroColor = data.lucro_ano >= 0 ? 'text-emerald-400 bg-emerald-500/20' : 'text-red-400 bg-red-500/20' const lucroLabel = data.lucro_ano >= 0 ? 'Lucro' : 'Prejuizo' // Format evolution data for chart const chartData = data.evolucao.map(e => ({ mes: formatMesLabel(e.mes), Receita: e.receita, Despesa: e.despesa, })) return (
{/* Header */}

Financeiro

Vendas e Despesas {new Date().getFullYear()}

{lucroLabel}: {formatEUR(Math.abs(data.lucro_ano))} Monitor Dashboard
{/* Main Content */}
{/* Summary Cards */}
{/* Lucro cards */}
= 0 ? 'text-emerald-400' : 'text-red-400'}`} /> Resultado Mensal
= 0 ? 'text-emerald-400' : 'text-red-400'}`}> {data.lucro_mes >= 0 ? '+' : ''}{formatEUR(data.lucro_mes)}
= 0 ? 'text-emerald-400' : 'text-red-400'}`} /> Resultado Anual
= 0 ? 'text-emerald-400' : 'text-red-400'}`}> {data.lucro_ano >= 0 ? '+' : ''}{formatEUR(data.lucro_ano)}
{/* Charts */}
{/* Bar Chart - Monthly Evolution */}

Evolucao Mensal

`${v}€`} /> } />
{/* Pie Chart - Expense Distribution */}

Despesas por Categoria

{data.categorias.slice(0, 10).map((_, i) => ( ))} formatEUR(value || 0)} contentStyle={{ background: '#18181b', border: '1px solid rgba(255,255,255,0.1)', borderRadius: 12, fontSize: 12 }} itemStyle={{ color: '#e4e4e7' }} />
{/* Legend */}
{data.categorias.slice(0, 10).map((cat, i) => (
{cat.name}
{formatEUR(cat.value)}
))}
) }