arbritage/pages/Dashboard.tsx

165 lines
10 KiB
TypeScript
Raw Normal View History

2026-01-26 14:20:25 +00:00
import React from 'react';
import { useCRM } from '../context/CRMContext';
import { useNavigate } from 'react-router-dom';
import clsx from 'clsx';
import { TrendingUp, TrendingDown, DollarSign, Activity, ArrowRight, Package } from 'lucide-react';
const Dashboard: React.FC = () => {
const { orders, inventory, suppliers } = useCRM();
const navigate = useNavigate();
// Financial Calculation
const activeOrders = orders.filter(o => o.status === 'Pending' || o.status === 'Paid');
const totalInvested = activeOrders.reduce((acc, o) => acc + o.totalCostWithOverhead, 0);
// Mocking a growth metric for demonstration
const totalProfitHistory = orders.filter(o => o.status === 'Received').reduce((acc, o) => acc + o.estimatedProfit, 0);
const inventoryValue = inventory.reduce((acc, i) => acc + ((Number(i.marketPriceBRL) || 0) * (Number(i.quantity) || 0)), 0);
// "Am I winning?" - Net Result (Mocked relative to investment for delta)
const netResultDelta = totalInvested > 0 ? (totalProfitHistory / totalInvested) * 100 : 0;
const isWinning = netResultDelta >= 0;
return (
<div className="space-y-6 animate-in fade-in duration-500 pb-20">
{/* HERDER: "Am I winning?" Context */}
<div className="flex items-end justify-between border-b border-white/5 pb-4">
<div>
<h2 className="text-xl font-bold text-white tracking-tight">Visão Geral</h2>
<p className="text-sm text-slate-500">Performance financeira e operacional.</p>
</div>
<div className="text-right">
<p className="text-[10px] uppercase font-bold text-slate-500 tracking-widest">Resultado Líquido (YTD)</p>
<div className={clsx("text-2xl font-bold flex items-center justify-end gap-2", isWinning ? "text-emerald-400" : "text-rose-400")}>
{isWinning ? <TrendingUp size={24} /> : <TrendingDown size={24} />}
R$ {totalProfitHistory.toLocaleString('pt-BR')}
</div>
</div>
</div>
{/* HIGH PRECISION METRICS GRID */}
<div className="grid grid-cols-1 md:grid-cols-4 gap-4">
{/* Metric 1: Capital Allocation */}
<div className="glass-card p-5 rounded-xl border border-white/10 relative overflow-hidden">
<div className="flex justify-between items-start mb-2">
<p className="text-[10px] font-bold text-slate-500 uppercase tracking-widest">Capital Alocado</p>
<DollarSign size={14} className="text-slate-600" />
</div>
<h3 className="text-xl font-bold text-white tracking-tight">R$ {totalInvested.toLocaleString('pt-BR')}</h3>
<div className="mt-3 flex items-center gap-2">
<span className="text-[10px] font-bold text-emerald-400 bg-emerald-400/5 px-1.5 py-0.5 rounded border border-emerald-400/10">+12% vs. mês ant.</span>
</div>
</div>
{/* Metric 2: Stock Value (Liquidity) */}
<div className="glass-card p-5 rounded-xl border border-white/10 relative overflow-hidden">
<div className="flex justify-between items-start mb-2">
<p className="text-[10px] font-bold text-slate-500 uppercase tracking-widest">Valor em Estoque</p>
<Package size={14} className="text-slate-600" />
</div>
<h3 className="text-xl font-bold text-white tracking-tight">R$ {inventoryValue.toLocaleString('pt-BR')}</h3>
<div className="mt-3 flex items-center gap-2">
<span className="text-[10px] font-bold text-slate-400 bg-white/5 px-1.5 py-0.5 rounded border border-white/5">Giro: 15 dias</span>
</div>
</div>
{/* Metric 3: Margin */}
<div className="glass-card p-5 rounded-xl border border-white/10 relative overflow-hidden">
<div className="flex justify-between items-start mb-2">
<p className="text-[10px] font-bold text-slate-500 uppercase tracking-widest">Margem Média</p>
<Activity size={14} className="text-slate-600" />
</div>
<h3 className="text-xl font-bold text-white tracking-tight">24.5%</h3>
<div className="mt-3 flex items-center gap-2">
<span className="text-[10px] font-bold text-rose-400 bg-rose-400/5 px-1.5 py-0.5 rounded border border-rose-400/10">-2.1% (Pressão de Custo)</span>
</div>
</div>
{/* Metric 4: Active Orders */}
<div className="glass-card p-5 rounded-xl border border-white/10 relative overflow-hidden">
<div className="flex justify-between items-start mb-2">
<p className="text-[10px] font-bold text-slate-500 uppercase tracking-widest">Ordens Ativas</p>
<Activity size={14} className="text-slate-600" />
</div>
<h3 className="text-xl font-bold text-white tracking-tight">{activeOrders.length}</h3>
<div className="mt-3 flex items-center gap-2">
<button className="text-[10px] font-bold text-indigo-400 hover:text-indigo-300 flex items-center gap-1 transition-colors">
Ver detalhes <ArrowRight size={10} />
</button>
</div>
</div>
</div>
{/* DATA DENSITY TABLE (Bloomberg Style) */}
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
{/* ORDER FLOW */}
<div className="lg:col-span-2 glass-card rounded-xl border border-white/10 overflow-hidden flex flex-col min-h-[400px]">
<div className="px-6 py-4 border-b border-white/5 flex justify-between items-center bg-white/[0.01]">
<h3 className="text-sm font-bold text-white uppercase tracking-wider">Fluxo de Pedidos</h3>
<button onClick={() => navigate('/orders')} className="text-[10px] text-indigo-400 hover:text-white transition-colors font-bold uppercase tracking-wider">Expandir</button>
</div>
<table className="w-full text-left border-collapse">
<thead className="bg-black/20 text-[10px] font-bold text-slate-500 uppercase tracking-widest border-b border-white/5">
<tr>
<th className="px-6 py-3 font-semibold">ID</th>
<th className="px-6 py-3 font-semibold">Fornecedor</th>
<th className="px-6 py-3 font-semibold text-right">Valor</th>
<th className="px-6 py-3 font-semibold text-right">Status</th>
</tr>
</thead>
<tbody className="divide-y divide-white/5 text-sm">
{orders.length === 0 ? (
<tr><td colSpan={4} className="p-8 text-center text-slate-600 italic text-xs">Sem dados recentes.</td></tr>
) : (
orders.slice(0, 8).map(o => (
<tr key={o.id} className="hover:bg-white/[0.02] transition-colors">
<td className="px-6 py-3 font-mono text-slate-400 text-xs">{o.id.substring(0, 8)}...</td>
<td className="px-6 py-3 font-medium text-slate-200">{o.supplierName}</td>
<td className="px-6 py-3 text-right font-mono text-slate-300">R$ {o.totalCostWithOverhead.toLocaleString('pt-BR')}</td>
<td className="px-6 py-3 text-right">
<span className={clsx(
"text-[10px] font-bold px-1.5 py-0.5 rounded border",
o.status === 'Received' ? "text-emerald-400 border-emerald-400/20 bg-emerald-400/5" :
o.status === 'Pending' ? "text-amber-400 border-amber-400/20 bg-amber-400/5" :
"text-slate-500 border-slate-500/20 bg-slate-500/5"
)}>
{o.status.toUpperCase()}
</span>
</td>
</tr>
))
)}
</tbody>
</table>
</div>
{/* SUPPLIER PERFORMANCE (Compact List) */}
<div className="glass-card rounded-xl border border-white/10 overflow-hidden h-full">
<div className="px-6 py-4 border-b border-white/5 bg-white/[0.01]">
<h3 className="text-sm font-bold text-white uppercase tracking-wider">Top Fornecedores</h3>
</div>
<div className="divide-y divide-white/5">
{suppliers.slice(0, 6).map((s, i) => (
<div key={s.id} className="px-6 py-3 flex items-center justify-between hover:bg-white/[0.02] transition-colors group cursor-pointer">
<div className="flex items-center gap-3">
<span className="text-xs font-mono text-slate-600 w-4">{i + 1}</span>
<div>
<p className="text-sm font-bold text-slate-200 group-hover:text-white transition-colors">{s.name}</p>
<p className="text-[10px] text-slate-500">Eletrônicos PY</p>
</div>
</div>
<div className="text-right">
<p className="text-xs font-mono text-emerald-400">+ R$ 45k</p>
</div>
</div>
))}
</div>
</div>
</div>
</div>
);
};
export default Dashboard;