// Central de Gestão - Multi-empresa const { useState: useState_C, useMemo: useMemo_C } = React; function CentralGestao({ data, onOpenEmpresa, onCreateEmpresa, onDeleteEmpresa, onEditEmpresa }) { const isMobile = useIsMobile(); const [busca, setBusca] = useState_C(''); const [empresaExcluir, setEmpresaExcluir] = useState_C(null); const [view, setView] = useState_C('cards'); // cards | tabela const [dashFiltros, setDashFiltros] = useState_C({ periodo: '6m', // '1m' | '3m' | '6m' | '12m' | 'custom' segmento: 'todos', status: 'todos', dataIni: '', dataFim: '' }); const toast = useToast(); const hoje = todayISO(); const empresasComStats = useMemo_C(() => { return data.empresas.map(e => { const ls = data.lancamentos[e.id] || []; const stats = empresaStats(e, ls, hoje); return { ...e, stats, qtdLanc: ls.length }; }); }, [data.empresas, data.lancamentos, hoje]); // Lista única de segmentos para o filtro const segmentos = useMemo_C(() => [...new Set(data.empresas.map(e => e.segmento).filter(Boolean))].sort(), [data.empresas]); // Empresas que entram no DASHBOARD (KPIs + charts), filtradas por segmento e status const dashEmpresas = useMemo_C(() => empresasComStats.filter(e => (dashFiltros.segmento === 'todos' || e.segmento === dashFiltros.segmento) && (dashFiltros.status === 'todos' || e.stats.statusEmpresa === dashFiltros.status) ), [empresasComStats, dashFiltros.segmento, dashFiltros.status]); const hasDashFilter = dashFiltros.periodo !== '6m' || dashFiltros.segmento !== 'todos' || dashFiltros.status !== 'todos' || dashFiltros.dataIni || dashFiltros.dataFim; function clearDashFiltros() { setDashFiltros({ periodo: '6m', segmento: 'todos', status: 'todos', dataIni: '', dataFim: '' }); } // Lista de empresas (grade) — usa a toolbar própria (busca) + filtros do dashboard const filtradas = dashEmpresas .filter(e => !busca || e.nome.toLowerCase().includes(busca.toLowerCase()) || e.cnpj.includes(busca) || (e.documento && e.documento.replace(/\D/g, '').includes(busca.replace(/\D/g, '')))); // KPIs globais (reagem aos filtros do dashboard) const kpiTotalEmp = dashEmpresas.length; const kpiVencidas = dashEmpresas.filter(e => e.stats.statusEmpresa === 'vencido').length; const kpiVencendo = dashEmpresas.filter(e => e.stats.statusEmpresa === 'vencendo').length; const kpiEmDia = dashEmpresas.filter(e => e.stats.statusEmpresa === 'em-dia').length; const totalReceber = dashEmpresas.reduce((s, e) => s + e.stats.aReceber, 0); const totalPagar = dashEmpresas.reduce((s, e) => s + e.stats.aPagar, 0); const totalVencido = dashEmpresas.reduce((s, e) => s + e.stats.vencidos, 0); const saldoConsolidado = dashEmpresas.reduce((s, e) => s + e.stats.saldo, 0); // Charts data const statusDist = [ { label: 'Em dia', value: kpiEmDia, color: '#3b82f6' }, { label: 'Vencendo', value: kpiVencendo, color: '#f59e0b' }, { label: 'Vencido', value: kpiVencidas, color: '#ef4444' }, ]; // Entradas x Saídas — período selecionado no filtro const meses = useMemo_C(() => { const arr = []; if (dashFiltros.periodo === 'custom' && dashFiltros.dataIni && dashFiltros.dataFim) { const start = new Date(dashFiltros.dataIni + 'T00:00:00'); const end = new Date(dashFiltros.dataFim + 'T00:00:00'); let cur = new Date(start.getFullYear(), start.getMonth(), 1); const last = new Date(end.getFullYear(), end.getMonth(), 1); let guard = 0; while (cur <= last && guard < 120) { arr.push({ label: cur.toLocaleDateString('pt-BR', { month: 'short' }).replace('.', ''), comp: `${String(cur.getMonth() + 1).padStart(2, '0')}/${cur.getFullYear()}` }); cur = new Date(cur.getFullYear(), cur.getMonth() + 1, 1); guard++; } return arr; } const qtdMeses = { '1m': 1, '3m': 3, '6m': 6, '12m': 12 }[dashFiltros.periodo] ?? 6; const d = new Date(); for (let i = qtdMeses - 1; i >= 0; i--) { const dt = new Date(d.getFullYear(), d.getMonth() - i, 1); arr.push({ label: dt.toLocaleDateString('pt-BR', { month: 'short' }).replace('.', ''), comp: `${String(dt.getMonth() + 1).padStart(2, '0')}/${dt.getFullYear()}` }); } return arr; }, [dashFiltros.periodo, dashFiltros.dataIni, dashFiltros.dataFim]); const seriesData = useMemo_C(() => { const allLancs = dashEmpresas.flatMap(e => data.lancamentos[e.id] || []); const ent = meses.map(m => allLancs.filter(l => l.competencia === m.comp && l.tipo === 'entrada').reduce((s, l) => s + l.valor, 0)); const sai = meses.map(m => allLancs.filter(l => l.competencia === m.comp && l.tipo === 'saida').reduce((s, l) => s + l.valor, 0)); return [ { name: 'Entradas', color: '#16a34a', points: ent }, { name: 'Saídas', color: '#dc2626', points: sai }, ]; }, [dashEmpresas, meses, data.lancamentos]); return (
{/* Header */}
Central de Gestão

Visão Geral de Empresas

Gerencie suas {data.empresas.length} empresas em um só lugar
exportConsolidadoXLSX(data.empresas, data.lancamentos, data.portadores, data.centrosCusto)}> Exportar Consolidado onCreateEmpresa()}>Nova Empresa
{/* KPIs */}
s + (data.lancamentos[e.id] || []).filter(l => l.tipo === 'entrada' && !l.pago).length, 0)} lançamentos`} /> s + (data.lancamentos[e.id] || []).filter(l => l.tipo === 'saida' && !l.pago).length, 0)} lançamentos`} /> = 0 ? '#16a34a' : '#dc2626'} sub="Realizado (pago/recebido)" />
{/* Barra de filtros do dashboard */}
setDashFiltros({ ...dashFiltros, periodo: e.target.value })} style={{ minWidth: isMobile ? 0 : 140 }} options={[ { value: "1m", label: "1 mês" }, { value: "3m", label: "3 meses" }, { value: "6m", label: "6 meses" }, { value: "12m", label: "12 meses" }, { value: "custom", label: "Personalizado" } ]} /> {dashFiltros.periodo === 'custom' && ( <> setDashFiltros({ ...dashFiltros, dataIni: e.target.value })} /> setDashFiltros({ ...dashFiltros, dataFim: e.target.value })} /> )} setDashFiltros({ ...dashFiltros, segmento: e.target.value })} style={{ minWidth: isMobile ? 0 : 140 }} options={[ { value: "todos", label: "Todos" }, ...segmentos.map(s => ({ value: s, label: s })) ]} /> setDashFiltros({ ...dashFiltros, status: e.target.value })} style={{ minWidth: isMobile ? 0 : 140 }} options={[ { value: "todos", label: "Todos" }, { value: "em-dia", label: "Em dia" }, { value: "vencendo", label: "Vencendo" }, { value: "vencido", label: "Vencido" } ]} /> {hasDashFilter && Limpar filtros}
{/* Charts row */}
Entradas vs Saídas
{meses.length} {meses.length === 1 ? 'mês' : 'meses'} · {dashFiltros.segmento === 'todos' ? 'todas as empresas' : dashFiltros.segmento}{dashFiltros.status !== 'todos' ? ` · ${statusColor(dashFiltros.status)?.label || dashFiltros.status}` : ''}
m.label)} height={220} />
Status das Empresas
Distribuição por situação financeira
{statusDist.map((s, i) => (
{s.label} {s.value}
))}
{/* Alert de vencidos */} {totalVencido > 0 && (
{kpiVencidas} empresa{kpiVencidas !== 1 && 's'} com {formatBRL(totalVencido)} em pagamentos vencidos. Resolva o quanto antes.
setDashFiltros(f => ({ ...f, status: 'vencido' }))}>Ver vencidas
)} {/* Toolbar de empresas */}

Empresas

setBusca(e.target.value)} placeholder="Buscar por nome ou CNPJ..." style={{ border: 'none', outline: 'none', fontSize: 13, padding: '8px 4px', width: 240, fontFamily: 'inherit', background: 'transparent' }} />
{/* Grade de empresas */} {view === 'cards' ? (
{filtradas.map(e => onOpenEmpresa(e.id)} onEdit={() => onEditEmpresa(e)} onDelete={() => setEmpresaExcluir(e)} />)}
) : (
{filtradas.map(e => ( onOpenEmpresa(e.id)}> ))}
Empresa Documento Segmento Status A Receber A Pagar Vencidos Saldo
{e.nome} {e.tipoPessoa === 'pf' ? 'PF' : 'PJ'}
{e.documento || e.cnpj} {e.segmento} {formatBRL(e.stats.aReceber)} {formatBRL(e.stats.aPagar)} 0 ? '#dc2626' : 'var(--c-text-muted)', fontWeight: e.stats.vencidos > 0 ? 600 : 400, fontVariantNumeric: 'tabular-nums' }}>{formatBRL(e.stats.vencidos)} {formatBRL(e.stats.saldo)}
)} {filtradas.length === 0 && ( onCreateEmpresa()}>Nova Empresa } /> )} 0 ? `Esta empresa possui ${(data.lancamentos[empresaExcluir.id] || []).length} lançamento(s) que serão excluídos permanentemente. Deseja continuar com a exclusão de "${empresaExcluir.nome}"?` : `Deseja realmente excluir a empresa "${empresaExcluir.nome}"? Esta ação não poderá ser desfeita.` : '' } onConfirmar={async () => { if (empresaExcluir) { await onDeleteEmpresa(empresaExcluir.id); setEmpresaExcluir(null); } }} onCancelar={() => setEmpresaExcluir(null)} />
); } const th = { padding: '12px 16px', textAlign: 'left', fontSize: 11, fontWeight: 600, color: 'var(--c-text-muted)', textTransform: 'uppercase', letterSpacing: '0.04em' }; const td = { padding: '12px 16px' }; function EmpresaCard({ empresa, onOpen, onEdit, onDelete }) { const s = empresa.stats; const c = statusColor(s.statusEmpresa); const initial = empresa.nome.charAt(0).toUpperCase(); const [menuOpen, setMenuOpen] = React.useState(false); return (
{ e.currentTarget.style.borderColor = 'var(--c-primary)'; e.currentTarget.style.transform = 'translateY(-1px)'; }} onMouseLeave={e => { e.currentTarget.style.borderColor = 'var(--c-border)'; e.currentTarget.style.transform = 'none'; setMenuOpen(false); }} > {/* status bar */}
{initial}
{empresa.nome} {empresa.tipoPessoa === 'pf' ? 'PF' : 'PJ'}
{empresa.documento || empresa.cnpj}
{menuOpen && (
)}
{empresa.segmento}
A Receber
{formatBRL(s.aReceber)}
A Pagar
{formatBRL(s.aPagar)}
{s.cntVencido > 0 && (
{s.cntVencido} pendência{s.cntVencido > 1 ? 's' : ''} vencida{s.cntVencido > 1 ? 's' : ''} · {formatBRL(s.vencidos)}
)}
{empresa.qtdLanc} lançamentos Abrir
); } Object.assign(window, { CentralGestao });