Setup project structure, dependencies, and basic configuration for the ComFi application. Includes initial setup for Vite, React, TypeScript, Tailwind CSS, and essential development tools. Defines core types and provides a basic README for local development.
468 lines
25 KiB
TypeScript
468 lines
25 KiB
TypeScript
|
|
import React, { useState, useMemo } from 'react';
|
|
import { FinancialReportType, Expense, Receivable } from '../types';
|
|
import { Download, Printer, Filter, ChevronRight, X, Calendar, Building2, CheckCircle2, FileText } from 'lucide-react';
|
|
import { useToast } from '../contexts/ToastContext';
|
|
import { CustomSelect } from './CustomSelect';
|
|
|
|
interface FinancialReportsViewProps {
|
|
expenses: Expense[];
|
|
receivables: Receivable[];
|
|
}
|
|
|
|
const ReportTab = ({ active, label, onClick }: { active: boolean, label: string, onClick: () => void }) => (
|
|
<button
|
|
onClick={onClick}
|
|
className={`px-5 py-2.5 rounded-xl text-sm font-medium transition-all duration-300 ${
|
|
active
|
|
? 'bg-primary-500 text-white shadow-lg shadow-primary-200'
|
|
: 'text-slate-500 hover:bg-slate-100'
|
|
}`}
|
|
>
|
|
{label}
|
|
</button>
|
|
);
|
|
|
|
const TableRow = ({ label, value, indent = 0, isTotal = false, isHeader = false }: { label: string, value: string | React.ReactNode, indent?: number, isTotal?: boolean, isHeader?: boolean }) => (
|
|
<div className={`flex justify-between items-center py-3 border-b border-slate-50 hover:bg-slate-50 transition-colors px-4
|
|
${isHeader ? 'bg-slate-50 font-bold text-slate-800 border-t mt-2' : ''}
|
|
${isTotal ? 'bg-slate-50/50 font-bold' : ''}`}>
|
|
<span className={`text-slate-700 ${indent === 1 ? 'pl-4' : indent === 2 ? 'pl-8' : ''} ${isTotal ? 'text-slate-900' : ''}`}>
|
|
{label}
|
|
</span>
|
|
<span className={`${isTotal ? 'text-primary-600' : 'text-slate-600'} ${isHeader ? 'text-slate-800' : ''}`}>{value}</span>
|
|
</div>
|
|
);
|
|
|
|
export const FinancialReportsView: React.FC<FinancialReportsViewProps> = ({ expenses, receivables }) => {
|
|
const { addToast } = useToast();
|
|
const [activeTab, setActiveTab] = useState<FinancialReportType>('DRE');
|
|
const [showFilters, setShowFilters] = useState(false);
|
|
const [filters, setFilters] = useState({
|
|
period: 'mensal',
|
|
costCenter: 'Todos'
|
|
});
|
|
|
|
const handleExport = () => {
|
|
addToast({ type: 'info', title: 'Gerando PDF...', message: 'O download iniciará em instantes.', duration: 2000 });
|
|
setTimeout(() => {
|
|
addToast({ type: 'success', title: 'Exportação Concluída', message: `Relatório ${activeTab} salvo com sucesso.` });
|
|
}, 2000);
|
|
};
|
|
|
|
// --- ACCOUNTING ENGINE (Cálculos Reais) ---
|
|
const reportData = useMemo(() => {
|
|
// 1. Data Preparation
|
|
const paidRevenue = receivables.filter(r => r.status === 'paid').reduce((sum, r) => sum + r.value, 0);
|
|
const pendingRevenue = receivables.filter(r => r.status === 'pending').reduce((sum, r) => sum + r.value, 0);
|
|
const totalRevenue = paidRevenue + pendingRevenue; // Competência
|
|
|
|
const paidExpenses = expenses.filter(e => e.status === 'paid');
|
|
const pendingExpenses = expenses.filter(e => e.status === 'pending');
|
|
|
|
// Categorização de Despesas Pagas
|
|
const taxExpenses = paidExpenses.filter(e => e.category === 'Impostos').reduce((sum, e) => sum + e.amount, 0);
|
|
const costExpenses = paidExpenses.filter(e => e.category === 'Operacional').reduce((sum, e) => sum + e.amount, 0); // Mocking Op as CMV/CPV
|
|
const adminExpenses = paidExpenses.filter(e => e.category === 'Administrativo' || e.category === 'TI').reduce((sum, e) => sum + e.amount, 0);
|
|
const salesExpenses = paidExpenses.filter(e => e.category === 'Marketing').reduce((sum, e) => sum + e.amount, 0);
|
|
const personnelExpenses = paidExpenses.filter(e => e.category === 'Pessoal').reduce((sum, e) => sum + e.amount, 0);
|
|
|
|
// Totais
|
|
const totalDeductions = taxExpenses; // Simplificação
|
|
const netRevenue = paidRevenue - totalDeductions;
|
|
const grossProfit = netRevenue - costExpenses;
|
|
const totalOpExpenses = adminExpenses + salesExpenses + personnelExpenses;
|
|
const netIncome = grossProfit - totalOpExpenses;
|
|
|
|
// 2. Balance Sheet (BP) Calculations (Estimated)
|
|
// Assets
|
|
const cashAndEquivalents = 50000 + (netIncome > 0 ? netIncome : 0); // Mock Start Cash + Profit
|
|
const accountsReceivable = pendingRevenue;
|
|
const fixedAssets = 150000; // Mocked Fixed Assets (Computers, Furniture)
|
|
const totalCurrentAssets = cashAndEquivalents + accountsReceivable;
|
|
const totalNonCurrentAssets = fixedAssets;
|
|
const totalAssets = totalCurrentAssets + totalNonCurrentAssets;
|
|
|
|
// Liabilities
|
|
const accountsPayable = pendingExpenses.reduce((sum, e) => sum + e.amount, 0);
|
|
const loansShortTerm = 20000; // Mock
|
|
const loansLongTerm = 100000; // Mock
|
|
const totalCurrentLiabilities = accountsPayable + loansShortTerm;
|
|
const totalNonCurrentLiabilities = loansLongTerm;
|
|
|
|
// Equity
|
|
const shareCapital = 50000; // Mock
|
|
const retainedEarnings = totalAssets - (totalCurrentLiabilities + totalNonCurrentLiabilities + shareCapital); // Balancing figure
|
|
const totalEquity = shareCapital + retainedEarnings;
|
|
|
|
// 3. Cash Flow (DFC) - Direct Method Simplified
|
|
const cashInflow = paidRevenue;
|
|
const cashOutflowOp = paidExpenses.reduce((sum, e) => sum + e.amount, 0);
|
|
const netCashOperating = cashInflow - cashOutflowOp;
|
|
|
|
// 4. Value Added (DVA)
|
|
const inputs = costExpenses + adminExpenses + salesExpenses; // Consumo de terceiros
|
|
const grossValueAdded = paidRevenue - inputs;
|
|
const netValueAdded = grossValueAdded; // Assuming no depreciation for simplicity
|
|
|
|
return {
|
|
dre: {
|
|
grossRevenue: paidRevenue,
|
|
taxes: taxExpenses,
|
|
netRevenue,
|
|
costs: costExpenses,
|
|
grossProfit,
|
|
adminExpenses,
|
|
salesExpenses,
|
|
personnelExpenses,
|
|
netIncome
|
|
},
|
|
bp: {
|
|
cashAndEquivalents,
|
|
accountsReceivable,
|
|
totalCurrentAssets,
|
|
fixedAssets,
|
|
totalAssets,
|
|
accountsPayable,
|
|
loansShortTerm,
|
|
totalCurrentLiabilities,
|
|
loansLongTerm,
|
|
shareCapital,
|
|
retainedEarnings,
|
|
totalEquityAndLiabilities: totalCurrentLiabilities + totalNonCurrentLiabilities + totalEquity
|
|
},
|
|
dfc: {
|
|
netCashOperating,
|
|
cashInflow,
|
|
cashOutflowOp
|
|
},
|
|
dva: {
|
|
grossRevenue: paidRevenue,
|
|
inputs,
|
|
grossValueAdded,
|
|
personnelExpenses,
|
|
taxExpenses,
|
|
rentals: 0,
|
|
equityRemuneration: netIncome
|
|
}
|
|
};
|
|
}, [expenses, receivables]);
|
|
|
|
const formatCurrency = (val: number) => val.toLocaleString('pt-BR', { style: 'currency', currency: 'BRL' });
|
|
const formatNegative = (val: number) => `(${formatCurrency(val)})`;
|
|
|
|
const periodLabel = filters.period === 'anual' ? '2024' : filters.period === 'trimestral' ? '1º Trimestre 2024' : 'Maio/2024';
|
|
|
|
const renderContent = () => {
|
|
switch (activeTab) {
|
|
case 'DRE':
|
|
return (
|
|
<div className="bg-white rounded-2xl border border-slate-100 p-0 overflow-hidden animate-fade-in max-w-4xl mx-auto">
|
|
<div className="p-6 border-b border-slate-100 flex justify-between items-center">
|
|
<div>
|
|
<h3 className="text-lg font-bold text-slate-800">Demonstração do Resultado do Exercício (DRE)</h3>
|
|
<p className="text-slate-400 text-sm">Período: {periodLabel} | Centro de Custo: {filters.costCenter}</p>
|
|
</div>
|
|
<div className="w-10 h-10 bg-primary-50 rounded-lg flex items-center justify-center text-primary-500"><FileText size={20}/></div>
|
|
</div>
|
|
|
|
<TableRow label="RECEITA OPERACIONAL BRUTA" value="" isHeader />
|
|
<TableRow label="Receita de Serviços / Vendas" value={formatCurrency(reportData.dre.grossRevenue)} indent={1} />
|
|
|
|
<TableRow label="DEDUÇÕES DA RECEITA BRUTA" value="" isHeader />
|
|
<TableRow label="(-) Impostos sobre Vendas" value={formatNegative(reportData.dre.taxes)} indent={1} />
|
|
|
|
<TableRow label="= RECEITA OPERACIONAL LÍQUIDA" value={formatCurrency(reportData.dre.netRevenue)} isTotal />
|
|
|
|
<TableRow label="CUSTOS OPERACIONAIS" value="" isHeader />
|
|
<TableRow label="(-) Custos dos Serviços Prestados (CSP)" value={formatNegative(reportData.dre.costs)} indent={1} />
|
|
|
|
<TableRow label="= LUCRO BRUTO" value={formatCurrency(reportData.dre.grossProfit)} isTotal />
|
|
|
|
<TableRow label="DESPESAS OPERACIONAIS" value="" isHeader />
|
|
<TableRow label="(-) Despesas com Pessoal" value={formatNegative(reportData.dre.personnelExpenses)} indent={1} />
|
|
<TableRow label="(-) Despesas Administrativas & TI" value={formatNegative(reportData.dre.adminExpenses)} indent={1} />
|
|
<TableRow label="(-) Despesas Comerciais / Mkt" value={formatNegative(reportData.dre.salesExpenses)} indent={1} />
|
|
|
|
<div className="p-4 bg-primary-50 mt-4 flex justify-between font-bold text-primary-700 rounded-b-2xl">
|
|
<span>= LUCRO / PREJUÍZO LÍQUIDO</span>
|
|
<span>{formatCurrency(reportData.dre.netIncome)}</span>
|
|
</div>
|
|
</div>
|
|
);
|
|
|
|
case 'BP':
|
|
return (
|
|
<div className="space-y-6 animate-fade-in">
|
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-8">
|
|
{/* ATIVO */}
|
|
<div className="bg-white rounded-2xl border border-slate-100 p-0 overflow-hidden h-fit">
|
|
<div className="bg-slate-50 p-4 border-b border-slate-100 font-bold text-slate-700">ATIVO</div>
|
|
|
|
<TableRow label="ATIVO CIRCULANTE" value={formatCurrency(reportData.bp.totalCurrentAssets)} isHeader />
|
|
<TableRow label="Caixa e Equivalentes" value={formatCurrency(reportData.bp.cashAndEquivalents)} indent={1} />
|
|
<TableRow label="Contas a Receber (Clientes)" value={formatCurrency(reportData.bp.accountsReceivable)} indent={1} />
|
|
|
|
<TableRow label="ATIVO NÃO CIRCULANTE" value={formatCurrency(reportData.bp.fixedAssets)} isHeader />
|
|
<TableRow label="Imobilizado (Móveis/Equip.)" value={formatCurrency(reportData.bp.fixedAssets)} indent={1} />
|
|
|
|
<div className="p-4 bg-primary-50 mt-4 flex justify-between font-bold text-primary-700">
|
|
<span>TOTAL DO ATIVO</span>
|
|
<span>{formatCurrency(reportData.bp.totalAssets)}</span>
|
|
</div>
|
|
</div>
|
|
|
|
{/* PASSIVO */}
|
|
<div className="bg-white rounded-2xl border border-slate-100 p-0 overflow-hidden h-fit">
|
|
<div className="bg-slate-50 p-4 border-b border-slate-100 font-bold text-slate-700">PASSIVO E PATRIMÔNIO LÍQUIDO</div>
|
|
|
|
<TableRow label="PASSIVO CIRCULANTE" value={formatCurrency(reportData.bp.totalCurrentLiabilities)} isHeader />
|
|
<TableRow label="Fornecedores a Pagar" value={formatCurrency(reportData.bp.accountsPayable)} indent={1} />
|
|
<TableRow label="Empréstimos Curto Prazo" value={formatCurrency(reportData.bp.loansShortTerm)} indent={1} />
|
|
|
|
<TableRow label="PASSIVO NÃO CIRCULANTE" value={formatCurrency(reportData.bp.loansLongTerm)} isHeader />
|
|
<TableRow label="Empréstimos Longo Prazo" value={formatCurrency(reportData.bp.loansLongTerm)} indent={1} />
|
|
|
|
<TableRow label="PATRIMÔNIO LÍQUIDO" value={formatCurrency(reportData.bp.shareCapital + reportData.bp.retainedEarnings)} isHeader />
|
|
<TableRow label="Capital Social" value={formatCurrency(reportData.bp.shareCapital)} indent={1} />
|
|
<TableRow label="Lucros/Prejuízos Acumulados" value={formatCurrency(reportData.bp.retainedEarnings)} indent={1} />
|
|
|
|
<div className="p-4 bg-primary-50 mt-4 flex justify-between font-bold text-primary-700">
|
|
<span>TOTAL PASSIVO + PL</span>
|
|
<span>{formatCurrency(reportData.bp.totalEquityAndLiabilities)}</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
|
|
case 'DFC':
|
|
return (
|
|
<div className="bg-white rounded-2xl border border-slate-100 p-0 overflow-hidden animate-fade-in max-w-4xl mx-auto">
|
|
<div className="p-6 border-b border-slate-100">
|
|
<h3 className="text-lg font-bold text-slate-800">Demonstração do Fluxo de Caixa (Método Direto)</h3>
|
|
<p className="text-slate-400 text-sm">Período: {periodLabel}</p>
|
|
</div>
|
|
|
|
<TableRow label="ATIVIDADES OPERACIONAIS" value="" isHeader />
|
|
<TableRow label="(+) Recebimento de Clientes" value={formatCurrency(reportData.dfc.cashInflow)} indent={1} />
|
|
<TableRow label="(-) Pagamento a Fornecedores/Despesas" value={formatNegative(reportData.dfc.cashOutflowOp)} indent={1} />
|
|
<TableRow label="(=) Caixa Líquido das Atividades Operacionais" value={formatCurrency(reportData.dfc.netCashOperating)} isTotal indent={1} />
|
|
|
|
<TableRow label="ATIVIDADES DE INVESTIMENTO" value="" isHeader />
|
|
<TableRow label="(-) Aquisição de Imobilizado" value={formatCurrency(0)} indent={1} />
|
|
<TableRow label="(=) Caixa Líquido das Atividades de Investimento" value={formatCurrency(0)} isTotal indent={1} />
|
|
|
|
<TableRow label="ATIVIDADES DE FINANCIAMENTO" value="" isHeader />
|
|
<TableRow label="(+) Novos Empréstimos" value={formatCurrency(0)} indent={1} />
|
|
<TableRow label="(=) Caixa Líquido das Atividades de Financiamento" value={formatCurrency(0)} isTotal indent={1} />
|
|
|
|
<div className={`p-4 mt-4 flex justify-between font-bold rounded-b-2xl ${reportData.dfc.netCashOperating >= 0 ? 'bg-green-50 text-green-800' : 'bg-red-50 text-red-800'}`}>
|
|
<span>AUMENTO/REDUÇÃO LÍQUIDA DE CAIXA</span>
|
|
<span>{formatCurrency(reportData.dfc.netCashOperating)}</span>
|
|
</div>
|
|
</div>
|
|
);
|
|
|
|
case 'DLPA':
|
|
return (
|
|
<div className="bg-white rounded-2xl border border-slate-100 p-0 overflow-hidden animate-fade-in max-w-4xl mx-auto">
|
|
<div className="p-6 border-b border-slate-100">
|
|
<h3 className="text-lg font-bold text-slate-800">Demonstração de Lucros ou Prejuízos Acumulados (DLPA)</h3>
|
|
</div>
|
|
<TableRow label="Saldo Inicial" value={formatCurrency(reportData.bp.retainedEarnings - reportData.dre.netIncome)} />
|
|
<TableRow label="(+) Ajustes de Exercícios Anteriores" value={formatCurrency(0)} />
|
|
<TableRow label="(+) Lucro Líquido do Exercício" value={formatCurrency(reportData.dre.netIncome)} isTotal />
|
|
<TableRow label="(-) Transferências para Reservas" value={formatCurrency(0)} />
|
|
<TableRow label="(-) Dividendos Distribuídos" value={formatCurrency(0)} />
|
|
<div className="p-4 bg-primary-50 mt-4 flex justify-between font-bold text-primary-700">
|
|
<span>SALDO FINAL</span>
|
|
<span>{formatCurrency(reportData.bp.retainedEarnings)}</span>
|
|
</div>
|
|
</div>
|
|
);
|
|
|
|
case 'DMPL':
|
|
return (
|
|
<div className="bg-white rounded-2xl border border-slate-100 p-0 overflow-hidden animate-fade-in max-w-5xl mx-auto overflow-x-auto">
|
|
<div className="p-6 border-b border-slate-100">
|
|
<h3 className="text-lg font-bold text-slate-800">Demonstração das Mutações do Patrimônio Líquido (DMPL)</h3>
|
|
</div>
|
|
<table className="w-full text-left text-sm">
|
|
<thead className="bg-slate-50 text-slate-700 font-bold">
|
|
<tr>
|
|
<th className="p-4">Histórico</th>
|
|
<th className="p-4 text-right">Capital Social</th>
|
|
<th className="p-4 text-right">Reservas de Lucro</th>
|
|
<th className="p-4 text-right">Lucros Acumulados</th>
|
|
<th className="p-4 text-right">Total</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody className="divide-y divide-slate-100">
|
|
<tr>
|
|
<td className="p-4 font-medium text-slate-700">Saldo Inicial</td>
|
|
<td className="p-4 text-right">{formatCurrency(reportData.bp.shareCapital)}</td>
|
|
<td className="p-4 text-right">R$ 0,00</td>
|
|
<td className="p-4 text-right">{formatCurrency(reportData.bp.retainedEarnings - reportData.dre.netIncome)}</td>
|
|
<td className="p-4 text-right font-bold">{formatCurrency(reportData.bp.shareCapital + (reportData.bp.retainedEarnings - reportData.dre.netIncome))}</td>
|
|
</tr>
|
|
<tr>
|
|
<td className="p-4 font-medium text-slate-700">Lucro Líquido do Período</td>
|
|
<td className="p-4 text-right">-</td>
|
|
<td className="p-4 text-right">-</td>
|
|
<td className="p-4 text-right text-green-600">{formatCurrency(reportData.dre.netIncome)}</td>
|
|
<td className="p-4 text-right font-bold text-green-600">{formatCurrency(reportData.dre.netIncome)}</td>
|
|
</tr>
|
|
</tbody>
|
|
<tfoot className="bg-slate-50 font-bold text-slate-800">
|
|
<tr>
|
|
<td className="p-4">Saldo Final</td>
|
|
<td className="p-4 text-right">{formatCurrency(reportData.bp.shareCapital)}</td>
|
|
<td className="p-4 text-right">R$ 0,00</td>
|
|
<td className="p-4 text-right">{formatCurrency(reportData.bp.retainedEarnings)}</td>
|
|
<td className="p-4 text-right text-primary-600">{formatCurrency(reportData.bp.shareCapital + reportData.bp.retainedEarnings)}</td>
|
|
</tr>
|
|
</tfoot>
|
|
</table>
|
|
</div>
|
|
);
|
|
|
|
case 'DRA':
|
|
return (
|
|
<div className="bg-white rounded-2xl border border-slate-100 p-0 overflow-hidden animate-fade-in max-w-4xl mx-auto">
|
|
<div className="p-6 border-b border-slate-100">
|
|
<h3 className="text-lg font-bold text-slate-800">Demonstração do Resultado Abrangente (DRA)</h3>
|
|
</div>
|
|
<TableRow label="Lucro Líquido do Exercício" value={formatCurrency(reportData.dre.netIncome)} isTotal />
|
|
<TableRow label="Outros Resultados Abrangentes" value="" isHeader />
|
|
<TableRow label="(+/-) Ajustes de Avaliação Patrimonial" value={formatCurrency(0)} indent={1} />
|
|
<TableRow label="(+/-) Variação Cambial de Investimentos" value={formatCurrency(0)} indent={1} />
|
|
<div className="p-4 bg-primary-50 mt-4 flex justify-between font-bold text-primary-700">
|
|
<span>RESULTADO ABRANGENTE TOTAL</span>
|
|
<span>{formatCurrency(reportData.dre.netIncome)}</span>
|
|
</div>
|
|
</div>
|
|
);
|
|
|
|
case 'DVA':
|
|
return (
|
|
<div className="bg-white rounded-2xl border border-slate-100 p-0 overflow-hidden animate-fade-in max-w-4xl mx-auto">
|
|
<div className="p-6 border-b border-slate-100">
|
|
<h3 className="text-lg font-bold text-slate-800">Demonstração do Valor Adicionado (DVA)</h3>
|
|
</div>
|
|
|
|
<TableRow label="1. RECEITAS" value={formatCurrency(reportData.dva.grossRevenue)} isHeader />
|
|
<TableRow label="Vendas de Mercadorias, Produtos e Serviços" value={formatCurrency(reportData.dva.grossRevenue)} indent={1} />
|
|
|
|
<TableRow label="2. INSUMOS ADQUIRIDOS DE TERCEIROS" value={formatNegative(reportData.dva.inputs)} isHeader />
|
|
<TableRow label="Custos Operacionais e Materiais" value={formatNegative(reportData.dva.inputs)} indent={1} />
|
|
|
|
<TableRow label="3. VALOR ADICIONADO BRUTO (1-2)" value={formatCurrency(reportData.dva.grossValueAdded)} isTotal />
|
|
|
|
<TableRow label="4. RETENÇÕES" value={formatCurrency(0)} isHeader />
|
|
<TableRow label="Depreciação, Amortização e Exaustão" value={formatCurrency(0)} indent={1} />
|
|
|
|
<TableRow label="5. VALOR ADICIONADO LÍQUIDO (3-4)" value={formatCurrency(reportData.dva.grossValueAdded)} isTotal />
|
|
|
|
<div className="bg-slate-50 p-4 border-b border-slate-100 border-t font-bold text-slate-800 mt-4">6. DISTRIBUIÇÃO DO VALOR ADICIONADO</div>
|
|
|
|
<TableRow label="Pessoal (Salários e Benefícios)" value={formatCurrency(reportData.dva.personnelExpenses)} indent={1} />
|
|
<TableRow label="Impostos, Taxas e Contribuições" value={formatCurrency(reportData.dva.taxExpenses)} indent={1} />
|
|
<TableRow label="Remuneração de Capitais de Terceiros (Aluguéis/Juros)" value={formatCurrency(reportData.dva.rentals)} indent={1} />
|
|
<TableRow label="Remuneração de Capitais Próprios (Lucros)" value={formatCurrency(reportData.dva.equityRemuneration)} indent={1} />
|
|
|
|
<div className="p-4 bg-primary-50 mt-4 flex justify-between font-bold text-primary-700">
|
|
<span>TOTAL DISTRIBUÍDO</span>
|
|
<span>{formatCurrency(reportData.dva.personnelExpenses + reportData.dva.taxExpenses + reportData.dva.rentals + reportData.dva.equityRemuneration)}</span>
|
|
</div>
|
|
</div>
|
|
);
|
|
|
|
default:
|
|
return null;
|
|
}
|
|
};
|
|
|
|
return (
|
|
<div className="space-y-6">
|
|
<div className="flex flex-col md:flex-row justify-between items-start md:items-center gap-4">
|
|
<div>
|
|
<h1 className="text-2xl font-bold text-slate-800">Demonstrações Contábeis</h1>
|
|
<p className="text-slate-500">Relatórios gerados em tempo real com base nos lançamentos.</p>
|
|
</div>
|
|
<div className="flex gap-2">
|
|
<button
|
|
onClick={() => setShowFilters(!showFilters)}
|
|
className={`flex items-center gap-2 px-4 py-2 border rounded-xl transition-colors ${showFilters ? 'bg-slate-100 border-slate-300 text-slate-800' : 'bg-white border-slate-200 text-slate-600 hover:bg-slate-50'}`}
|
|
>
|
|
<Filter size={16} />
|
|
{showFilters ? 'Ocultar Filtros' : 'Filtros'}
|
|
</button>
|
|
<button onClick={handleExport} className="flex items-center gap-2 px-4 py-2 bg-primary-500 text-white rounded-xl hover:bg-primary-600 shadow-lg shadow-primary-200/50">
|
|
<Download size={16} /> Exportar
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Filter Panel */}
|
|
{showFilters && (
|
|
<div className="bg-white p-6 rounded-2xl border border-slate-100 shadow-sm grid grid-cols-1 md:grid-cols-3 gap-6 animate-slide-down">
|
|
<div>
|
|
<label className="block text-xs font-semibold text-slate-500 mb-2 uppercase flex items-center gap-2">
|
|
<Calendar size={14} /> Período
|
|
</label>
|
|
<div className="relative">
|
|
<CustomSelect
|
|
value={filters.period}
|
|
onChange={(val) => setFilters({...filters, period: val})}
|
|
options={[
|
|
{ value: 'mensal', label: 'Mensal (Mês Atual)' },
|
|
{ value: 'trimestral', label: 'Trimestral' },
|
|
{ value: 'semestral', label: 'Semestral' },
|
|
{ value: 'anual', label: 'Anual (Acumulado)' }
|
|
]}
|
|
/>
|
|
</div>
|
|
</div>
|
|
<div>
|
|
<label className="block text-xs font-semibold text-slate-500 mb-2 uppercase flex items-center gap-2">
|
|
<Building2 size={14} /> Centro de Custo
|
|
</label>
|
|
<div className="relative">
|
|
<CustomSelect
|
|
value={filters.costCenter}
|
|
onChange={(val) => setFilters({...filters, costCenter: val})}
|
|
options={[
|
|
{ value: 'Todos', label: 'Todos' },
|
|
{ value: 'Administrativo', label: 'Administrativo' },
|
|
{ value: 'Comercial', label: 'Comercial / Vendas' },
|
|
{ value: 'Operacional', label: 'Operacional' },
|
|
{ value: 'TI', label: 'Tecnologia (TI)' }
|
|
]}
|
|
/>
|
|
</div>
|
|
</div>
|
|
<div className="flex items-end">
|
|
<button className="w-full py-2.5 bg-slate-800 text-white rounded-xl hover:bg-slate-900 transition-colors font-medium flex items-center justify-center gap-2">
|
|
<CheckCircle2 size={16}/> Aplicar Filtros
|
|
</button>
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
{/* Tabs */}
|
|
<div className="flex flex-wrap gap-2 pb-2">
|
|
<ReportTab active={activeTab === 'DRE'} label="DRE" onClick={() => setActiveTab('DRE')} />
|
|
<ReportTab active={activeTab === 'BP'} label="Balanço (BP)" onClick={() => setActiveTab('BP')} />
|
|
<ReportTab active={activeTab === 'DFC'} label="Fluxo de Caixa (DFC)" onClick={() => setActiveTab('DFC')} />
|
|
<ReportTab active={activeTab === 'DLPA'} label="DLPA" onClick={() => setActiveTab('DLPA')} />
|
|
<ReportTab active={activeTab === 'DMPL'} label="DMPL" onClick={() => setActiveTab('DMPL')} />
|
|
<ReportTab active={activeTab === 'DRA'} label="DRA" onClick={() => setActiveTab('DRA')} />
|
|
<ReportTab active={activeTab === 'DVA'} label="DVA" onClick={() => setActiveTab('DVA')} />
|
|
</div>
|
|
|
|
{renderContent()}
|
|
</div>
|
|
);
|
|
};
|