'use client'; import { Button } from '@/components/ui/button'; import { Card, CardContent } from '@/components/ui/card'; import { Checkbox } from '@/components/ui/checkbox'; import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle, DialogTrigger, } from '@/components/ui/dialog'; import { Drawer, DrawerClose, DrawerContent, DrawerDescription, DrawerHeader, DrawerTitle, DrawerTrigger, } from '@/components/ui/drawer'; import { Input } from '@/components/ui/input'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from '@/components/ui/select'; import { DataGridPremium, GridColDef, GridToolbar, } from '@mui/x-data-grid-premium'; import { LicenseInfo } from '@mui/x-license-pro'; import { ArrowDown, ArrowUp, ArrowUpDown, Download, Maximize2, Minimize2, Search, X, } from 'lucide-react'; import * as React from 'react'; import * as XLSX from 'xlsx'; // Garantir que a licença seja aplicada no componente if (typeof window !== 'undefined') { try { const PERPETUAL_LICENSE_KEY = 'e0d9bb8070ce0054c9d9ecb6e82cb58fTz0wLEU9MzI0NzIxNDQwMDAwMDAsUz1wcmVtaXVtLExNPXBlcnBldHVhbCxLVj0y'; LicenseInfo.setLicenseKey(PERPETUAL_LICENSE_KEY); console.log('✅ Licença MUI X aplicada no componente Analítico'); } catch (error) { console.warn('⚠️ Erro ao aplicar licença no componente:', error); } } interface AnaliticoItem { codigo_grupo: string; codigo_subgrupo: string; codigo_fornecedor: string; nome_fornecedor: string; id: number; codfilial: string; recnum: number; data_competencia: string; data_vencimento: string; data_pagamento: string; data_caixa: string; codigo_conta: string; conta: string; codigo_centrocusto: string; centro_custo?: string; valor: number; historico: string; historico2: string; created_at: string; updated_at: string; // Campos adicionais do Oracle entidade?: string; tipo_parceiro?: string; valor_previsto?: number; valor_confirmado?: number; valor_pago?: number; numero_lancamento?: number; ano_mes_comp?: string; codgrupo?: string; // Novos campos data_lancamento?: string; data_compensacao?: string; data_pagto?: string; } interface AnaliticoProps { filtros: { dataInicio: string; dataFim: string; centroCusto?: string; codigoGrupo?: string; codigoSubgrupo?: string; codigoConta?: string; linhaSelecionada?: string; excluirCentroCusto?: string; excluirCodigoConta?: string; codigosCentrosCustoSelecionados?: string; codigosContasSelecionadas?: string; }; } // Componente de filtro customizado estilo Excel interface ExcelFilterProps { column: GridColDef; data: any[]; filteredData: any[]; // Dados filtrados para mostrar apenas valores disponíveis onFilterChange: (field: string, values: string[]) => void; onSortChange: (field: string, direction: 'asc' | 'desc' | null) => void; currentFilter?: string[]; currentSort?: 'asc' | 'desc' | null; } const ExcelFilter: React.FC = ({ column, data, filteredData, onFilterChange, onSortChange, currentFilter = [], currentSort = null, }) => { const [isOpen, setIsOpen] = React.useState(false); const [searchTerm, setSearchTerm] = React.useState(''); const [selectedValues, setSelectedValues] = React.useState(currentFilter); const [selectAll, setSelectAll] = React.useState(false); // Sincronizar selectedValues com currentFilter quando ele mudar React.useEffect(() => { setSelectedValues(currentFilter); }, [currentFilter]); // Obter valores únicos da coluna baseado nos dados filtrados const uniqueValues = React.useMemo(() => { const values = filteredData .map((row) => { const value = row[column.field]; if (value === null || value === undefined) return ''; return String(value); }) .filter( (value, index, self) => self.indexOf(value) === index && value !== '' ) .sort(); return values; }, [filteredData, column.field]); // Filtrar valores baseado na busca const filteredValues = React.useMemo(() => { if (!searchTerm) return uniqueValues; return uniqueValues.filter((value) => value.toLowerCase().includes(searchTerm.toLowerCase()) ); }, [uniqueValues, searchTerm]); const handleSelectAll = (checked: boolean) => { if (checked) { setSelectedValues(filteredValues); setSelectAll(true); } else { setSelectedValues([]); setSelectAll(false); } }; const handleValueToggle = (value: string, checked: boolean) => { let newValues: string[]; if (checked) { newValues = [...selectedValues, value]; } else { newValues = selectedValues.filter((v) => v !== value); } setSelectedValues(newValues); setSelectAll( newValues.length === filteredValues.length && filteredValues.length > 0 ); }; const handleApply = () => { onFilterChange(column.field, selectedValues); setIsOpen(false); }; const handleClear = () => { setSelectedValues([]); setSelectAll(false); onFilterChange(column.field, []); setIsOpen(false); }; const handleSort = (direction: 'asc' | 'desc') => { onSortChange(column.field, direction); setIsOpen(false); }; return ( Filtrar por "{column.headerName}"
{/* Opções de ordenação */}
Ordenar
{/* Barra de pesquisa */}
setSearchTerm(e.target.value)} className="pl-8 h-8 text-sm" />
{/* Lista de valores com checkboxes */}
{filteredValues.map((value) => (
handleValueToggle(value, checked) } />
))}
{/* Botões de ação */}
); }; export default function AnaliticoComponent({ filtros }: AnaliticoProps) { const [data, setData] = React.useState([]); const [loading, setLoading] = React.useState(false); const [globalFilter, setGlobalFilter] = React.useState(''); const [open, setOpen] = React.useState(false); const [drawerOpen, setDrawerOpen] = React.useState(false); const [columnFilters, setColumnFilters] = React.useState< Record >({}); const [columnSorts, setColumnSorts] = React.useState< Record >({}); const [conditions, setConditions] = React.useState([ { column: '', operator: 'contains', value: '' }, ]); // Estado para armazenar filtros externos (vindos do teste.tsx) const [filtrosExternos, setFiltrosExternos] = React.useState(filtros); // Funções para gerenciar filtros customizados const handleColumnFilterChange = React.useCallback( (field: string, values: string[]) => { setColumnFilters((prev) => ({ ...prev, [field]: values, })); }, [] ); const handleColumnSortChange = React.useCallback( (field: string, direction: 'asc' | 'desc' | null) => { setColumnSorts((prev) => ({ ...prev, [field]: direction, })); }, [] ); // Função para contar filtros aplicados (apenas filtros internos do modal customizado) const getFilterCount = React.useCallback(() => { let count = 0; // Contar filtros de coluna (filtros do modal customizado) count += Object.keys(columnFilters).length; // Contar filtro global (se aplicável) if (globalFilter && globalFilter.trim() !== '') { count += 1; } return count; }, [columnFilters, globalFilter]); // Função para limpar todos os filtros internos (mantém filtros externos) const clearAllFilters = React.useCallback(() => { setColumnFilters({}); setColumnSorts({}); setGlobalFilter(''); }, []); // Atualizar filtros externos quando os props mudarem React.useEffect(() => { console.log('🔄 Analítico - useEffect dos filtros chamado'); console.log('📋 Filtros recebidos via props:', filtros); setFiltrosExternos(filtros); }, [filtros]); const fetchData = React.useCallback(async () => { console.log('🔄 Analítico - fetchData chamado'); console.log('📋 Filtros externos recebidos:', filtrosExternos); if (!filtrosExternos.dataInicio || !filtrosExternos.dataFim) { console.log('⚠️ Sem dataInicio ou dataFim, limpando dados'); setData([]); return; } setLoading(true); try { const params = new URLSearchParams(); if (filtrosExternos.dataInicio) { params.append('dataInicio', filtrosExternos.dataInicio); } if (filtrosExternos.dataFim) { params.append('dataFim', filtrosExternos.dataFim); } if (filtrosExternos.centroCusto) { params.append('centroCusto', filtrosExternos.centroCusto); } if (filtrosExternos.codigoGrupo) { params.append('codigoGrupo', filtrosExternos.codigoGrupo); } if (filtrosExternos.codigoConta) { params.append('codigoConta', filtrosExternos.codigoConta); } if (filtrosExternos.excluirCentroCusto) { params.append('excluirCentroCusto', filtrosExternos.excluirCentroCusto); } if (filtrosExternos.excluirCodigoConta) { params.append('excluirCodigoConta', filtrosExternos.excluirCodigoConta); } if (filtrosExternos.codigosCentrosCustoSelecionados) { params.append( 'codigosCentrosCustoSelecionados', filtrosExternos.codigosCentrosCustoSelecionados ); } if (filtrosExternos.codigosContasSelecionadas) { params.append( 'codigosContasSelecionadas', filtrosExternos.codigosContasSelecionadas ); } const url = `/api/analitico-oracle?${params.toString()}`; console.log('🌐 Fazendo requisição para:', url); const response = await fetch(url); if (response.ok) { const result = await response.json(); console.log('✅ Resposta da API recebida:', result.length, 'registros'); console.log('📝 Primeiros 2 registros:', result.slice(0, 2)); console.log('🔍 Verificando campos específicos:', { data_lancamento: result[0]?.data_lancamento, data_compensacao: result[0]?.data_compensacao, data_vencimento: result[0]?.data_vencimento, data_caixa: result[0]?.data_caixa, data_pagto: result[0]?.data_pagto, entidade: result[0]?.entidade, tipo_parceiro: result[0]?.tipo_parceiro, centro_custo: result[0]?.centro_custo, valor: result[0]?.valor, tipo_valor: typeof result[0]?.valor, }); setData(result as AnaliticoItem[]); } else { console.error('❌ Erro ao buscar dados:', await response.text()); } } catch (error) { console.error('❌ Erro ao buscar dados:', error); } finally { setLoading(false); } }, [filtrosExternos]); React.useEffect(() => { fetchData(); }, [fetchData]); // Filtrar dados baseado nos filtros de coluna const filteredData = React.useMemo(() => { if (!data || data.length === 0) return data; return data .filter((row) => { return Object.entries(columnFilters).every(([field, filterValues]) => { if (!filterValues || filterValues.length === 0) return true; const cellValue = (row as any)[field]; const stringValue = cellValue === null || cellValue === undefined ? '' : String(cellValue); return filterValues.includes(stringValue); }); }) .map((row, index) => ({ ...row, id: `filtered-${row.id || row.recnum || index}`, // Garantir ID único e estável })); }, [data, columnFilters]); // Função para renderizar header com filtro Excel const renderHeaderWithFilter = React.useCallback( (column: GridColDef) => { return (params: any) => (
{column.headerName}
); }, [ data, filteredData, columnFilters, columnSorts, handleColumnFilterChange, handleColumnSortChange, ] ); // Definir colunas do DataGridPro na ordem solicitada const columns = React.useMemo(() => { const dateCellRenderer = (params: any) => { if (!params.value) return '-'; try { return new Date(params.value).toLocaleDateString('pt-BR'); } catch (error) { return params.value; } }; const currencyCellRenderer = (params: any, showZero: boolean = false) => { const value = params.value; if (value === null || value === undefined || value === '') return '-'; if (!showZero && value === 0) return '-'; const numValue = typeof value === 'string' ? parseFloat(value) : Number(value); if (isNaN(numValue)) return '-'; const formatted = new Intl.NumberFormat('pt-BR', { style: 'currency', currency: 'BRL', }).format(numValue); return ( {formatted} ); }; const baseColumns = [ { field: 'ano_mes_comp', headerName: 'Ano/Mês Comp', width: 110, sortable: true, resizable: true, renderCell: (params: any) => params.value || '-', }, { field: 'numero_lancamento', headerName: 'NumLanc', width: 100, sortable: true, resizable: true, renderCell: (params: any) => params.value || '-', }, { field: 'data_lancamento', headerName: 'Dt Lanc', width: 95, sortable: true, resizable: true, renderCell: dateCellRenderer, }, { field: 'data_vencimento', headerName: 'Dt Venc', width: 95, sortable: true, resizable: true, renderCell: dateCellRenderer, }, { field: 'data_pagto', headerName: 'Dt Pagto', width: 95, sortable: true, resizable: true, renderCell: dateCellRenderer, }, { field: 'tipo_parceiro', headerName: 'Tipo Parc', width: 95, sortable: true, resizable: true, renderCell: (params: any) => params.value || '-', }, { field: 'codigo_fornecedor', headerName: 'Cod. Fornec', width: 100, sortable: true, resizable: true, }, { field: 'nome_fornecedor', headerName: 'Fornecedor', width: 200, sortable: true, resizable: true, }, { field: 'valor', headerName: 'Vl.Realizado', type: 'number' as const, width: 120, sortable: true, resizable: true, renderCell: (params: any) => currencyCellRenderer(params, true), }, { field: 'valor_pago', headerName: 'Vl.Pago', type: 'number' as const, width: 100, sortable: true, resizable: true, renderCell: (params: any) => currencyCellRenderer(params, false), }, { field: 'valor_previsto', headerName: 'Vl.Pr', type: 'number' as const, width: 85, sortable: true, resizable: true, renderCell: (params: any) => currencyCellRenderer(params, false), }, { field: 'valor_confirmado', headerName: 'Vl.Confirmado', type: 'number' as const, width: 125, sortable: true, resizable: true, renderCell: (params: any) => currencyCellRenderer(params, false), }, { field: 'entidade', headerName: 'Entidade', width: 90, sortable: true, resizable: true, renderCell: (params: any) => params.value || '-', }, { field: 'codigo_conta', headerName: 'Cod.Conta', width: 100, sortable: true, resizable: true, }, { field: 'conta', headerName: 'Conta', width: 200, sortable: true, resizable: true, }, { field: 'codigo_centrocusto', headerName: 'Cod.CC', width: 90, sortable: true, resizable: true, }, { field: 'centro_custo', headerName: 'Centro Custo', width: 180, sortable: true, resizable: true, renderCell: (params: any) => params.value || '-', }, { field: 'historico', headerName: 'Histórico', width: 250, sortable: true, resizable: true, }, { field: 'historico2', headerName: 'Histórico 2', width: 250, sortable: true, resizable: true, }, ]; // Adicionar renderHeader com filtro Excel para todas as colunas return baseColumns.map((col) => ({ ...col, renderHeader: renderHeaderWithFilter(col), })); }, [renderHeaderWithFilter]); // Ordenar dados baseado na ordenação de coluna const sortedAndFilteredData = React.useMemo(() => { if (!filteredData || filteredData.length === 0) return filteredData; const sortField = Object.keys(columnSorts).find( (field) => columnSorts[field] !== null ); if (!sortField || !columnSorts[sortField]) return filteredData; return [...filteredData].sort((a, b) => { const aValue = (a as any)[sortField]; const bValue = (b as any)[sortField]; // Converter para string para comparação const aString = aValue === null || aValue === undefined ? '' : String(aValue); const bString = bValue === null || bValue === undefined ? '' : String(bValue); if (columnSorts[sortField] === 'asc') { return aString.localeCompare(bString); } else { return bString.localeCompare(aString); } }); }, [filteredData, columnSorts]); // Calcular valor total dos dados filtrados const valorTotal = React.useMemo(() => { return sortedAndFilteredData.reduce( (sum, item) => sum + (Number(item.valor) || 0), 0 ); }, [sortedAndFilteredData]); // Limpar filtros de colunas que não têm mais valores disponíveis React.useEffect(() => { const updatedFilters = { ...columnFilters }; let hasChanges = false; Object.keys(columnFilters).forEach((field) => { const currentFilterValues = columnFilters[field] || []; if (currentFilterValues.length === 0) return; // Obter valores únicos disponíveis para esta coluna nos dados filtrados const availableValues = filteredData .map((row) => { const value = (row as any)[field]; return value === null || value === undefined ? '' : String(value); }) .filter( (value, index, self) => self.indexOf(value) === index && value !== '' ); // Filtrar apenas os valores que ainda estão disponíveis const validFilterValues = currentFilterValues.filter((value) => availableValues.includes(value) ); if (validFilterValues.length !== currentFilterValues.length) { if (validFilterValues.length === 0) { delete updatedFilters[field]; } else { updatedFilters[field] = validFilterValues; } hasChanges = true; } }); if (hasChanges) { setColumnFilters(updatedFilters); } }, [filteredData, columnFilters]); // Exportação XLSX - Exporta exatamente as colunas e valores da grid const exportToExcel = () => { if (sortedAndFilteredData.length === 0) return; // Funções auxiliares para formatar valores exatamente como na grid const formatDateValue = (value: any): string => { if (!value) return '-'; try { return new Date(value).toLocaleDateString('pt-BR'); } catch (error) { return value; } }; const formatCurrencyValue = ( value: any, showZero: boolean = false ): string | number => { if (value === null || value === undefined || value === '') return '-'; const numValue = typeof value === 'string' ? parseFloat(value) : Number(value); if (isNaN(numValue)) return '-'; if (!showZero && numValue === 0) return '-'; // Para Excel, retornar o número formatado como string (mantém o formato de moeda) return new Intl.NumberFormat('pt-BR', { style: 'currency', currency: 'BRL', }).format(numValue); }; const formatCellValue = (column: GridColDef, item: any): any => { const value = item[column.field]; // Se a coluna tem renderCell, aplicar a mesma lógica if (column.renderCell) { // Para datas if (column.field.includes('data_')) { return formatDateValue(value); } // Para valores monetários if (column.field === 'valor') { return formatCurrencyValue(value, true); } if ( column.field === 'valor_previsto' || column.field === 'valor_confirmado' || column.field === 'valor_pago' ) { return formatCurrencyValue(value, false); } // Para campos que retornam "-" se vazios if ( column.field === 'centro_custo' || column.field === 'entidade' || column.field === 'tipo_parceiro' || column.field === 'ano_mes_comp' || column.field === 'numero_lancamento' ) { return value || '-'; } } // Para datas sem renderCell explícito (mas que são datas) if (column.field.includes('data_')) { return formatDateValue(value); } // Valor padrão return value ?? ''; }; // Criar dados de exportação usando as colunas da grid na ordem exata // e depois adicionar os campos faltantes da interface const exportData = sortedAndFilteredData.map((item) => { const row: Record = {}; // Primeiro: adicionar as colunas da grid na ordem exata columns.forEach((column) => { const headerName = column.headerName || column.field; row[headerName] = formatCellValue(column, item); }); // Segundo: adicionar colunas que devem ser exportadas mas não exibidas na grid const colunasOcultas: Array<{ field: string; label: string; format?: (value: any) => any; }> = [ { field: 'data_compensacao', label: 'Dt Comp', format: formatDateValue, }, { field: 'data_caixa', label: 'Dt Caixa', format: formatDateValue, }, ]; colunasOcultas.forEach(({ field, label, format }) => { const value = (item as any)[field]; if (value !== undefined && value !== null) { row[label] = format ? format(value) : value; } else { row[label] = '-'; } }); // Terceiro: adicionar campos faltantes da interface que não estão na grid const camposFaltantes: Array<{ field: string; label: string; format?: (value: any) => any; }> = [ { field: 'codigo_grupo', label: 'Código Grupo' }, { field: 'codigo_subgrupo', label: 'Código Subgrupo' }, { field: 'codfilial', label: 'Código Filial' }, { field: 'recnum', label: 'Recnum' }, { field: 'data_competencia', label: 'Data Competência', format: formatDateValue, }, { field: 'data_pagamento', label: 'Data Pagamento', format: formatDateValue, }, { field: 'created_at', label: 'Criado Em', format: formatDateValue }, { field: 'updated_at', label: 'Atualizado Em', format: formatDateValue, }, { field: 'codgrupo', label: 'Cod Grupo' }, ]; camposFaltantes.forEach(({ field, label, format }) => { const value = (item as any)[field]; if (value !== undefined && value !== null) { row[label] = format ? format(value) : value; } else { row[label] = ''; } }); return row; }); const wb = XLSX.utils.book_new(); const ws = XLSX.utils.json_to_sheet(exportData); const resumoData = [ { Métrica: 'Total de Registros', Valor: sortedAndFilteredData.length }, { Métrica: 'Valor Total', Valor: valorTotal }, { Métrica: 'Filtros Aplicados', Valor: Object.keys(columnFilters).length > 0 ? 'Sim' : 'Não', }, ]; const wsResumo = XLSX.utils.json_to_sheet(resumoData); XLSX.utils.book_append_sheet(wb, ws, 'Dados Analíticos'); XLSX.utils.book_append_sheet(wb, wsResumo, 'Resumo'); const now = new Date(); const timestamp = now.toISOString().slice(0, 19).replace(/:/g, '-'); const fileName = `analitico_${timestamp}.xlsx`; XLSX.writeFile(wb, fileName); }; // Aplicar filtros avançados const applyFilters = () => { // Implementar lógica de filtros avançados se necessário setOpen(false); }; const clearFilters = () => { setConditions([{ column: '', operator: 'contains', value: '' }]); setGlobalFilter(''); }; // Função para renderizar o conteúdo principal do componente (reutilizável) const renderAnaliticoContent = (isMaximized: boolean = false) => { return ( <> {/* Filtros Externos Ativos - Apenas quando maximizado */} {isMaximized && (filtrosExternos.dataInicio || filtrosExternos.centroCusto || filtrosExternos.codigoGrupo || filtrosExternos.codigoConta) && (
Filtros aplicados pela tabela DRE Gerencial:
{filtrosExternos.dataInicio && filtrosExternos.dataFim && ( Período: {filtrosExternos.dataInicio} a{' '} {filtrosExternos.dataFim} )} {filtrosExternos.centroCusto && ( Centro: {filtrosExternos.centroCusto} )} {filtrosExternos.codigoGrupo && ( Grupo: {filtrosExternos.codigoGrupo} )} {filtrosExternos.codigoConta && ( Conta: {filtrosExternos.codigoConta} )}
)} {/* Controls - Apenas quando maximizado */} {isMaximized && (
{data.length > 0 && ( )}
)} {/* DataGridPro */}
Total de Registros:{' '} {sortedAndFilteredData.length}
Valor Total:{' '} {new Intl.NumberFormat('pt-BR', { style: 'currency', currency: 'BRL', }).format(valorTotal)}
row.id || `row-${row.recnum || Math.random()}` } sx={{ height: '100%', width: '100%', '& .MuiDataGrid-root': { border: 'none', }, '& .MuiDataGrid-columnHeaders': { backgroundColor: '#f9fafb', borderBottom: '1px solid #e5e7eb', }, '& .MuiDataGrid-columnHeader': { backgroundColor: '#f9fafb !important', fontWeight: 600, fontSize: '0.875rem', }, '& .MuiDataGrid-cell': { borderBottom: '1px solid #f0f0f0', fontSize: '0.875rem', }, '& .MuiDataGrid-virtualScroller': { scrollbarWidth: 'thin', '&::-webkit-scrollbar': { width: '8px', height: '8px', }, '&::-webkit-scrollbar-track': { background: '#f1f1f1', }, '&::-webkit-scrollbar-thumb': { background: '#888', borderRadius: '4px', }, '&::-webkit-scrollbar-thumb:hover': { background: '#555', }, }, '& .MuiDataGrid-toolbarContainer': { backgroundColor: '#f8fafc', borderBottom: '1px solid #e5e7eb', padding: '8px 16px', }, '& .MuiDataGrid-columnHeaderMenuContainer': { display: 'none !important', }, '& .MuiDataGrid-columnHeaderMenuButton': { display: 'none !important', }, '& .MuiDataGrid-columnHeaderSortIcon': { display: 'none !important', }, '& .MuiDataGrid-footerContainer': { display: 'none !important', }, '& .MuiDataGrid-columnHeaderTitleContainer': { width: '100%', display: 'flex', alignItems: 'center', justifyContent: 'space-between', }, }} />
); }; return (
{/* Header Section */}

Análise Analítica {filtros.linhaSelecionada ? ` - ${filtros.linhaSelecionada}` : ''}

Relatório detalhado de transações

{/* Filtros Externos Ativos - Centralizado */} {(filtrosExternos.dataInicio || filtrosExternos.centroCusto || filtrosExternos.codigoGrupo || filtrosExternos.codigoConta) && (
Filtros aplicados pela tabela DRE Gerencial:
{filtrosExternos.dataInicio && filtrosExternos.dataFim && ( Período: {filtrosExternos.dataInicio} a{' '} {filtrosExternos.dataFim} )} {filtrosExternos.centroCusto && ( Centro: {filtrosExternos.centroCusto} )} {filtrosExternos.codigoGrupo && ( Grupo: {filtrosExternos.codigoGrupo} )} {filtrosExternos.codigoConta && ( Conta: {filtrosExternos.codigoConta} )}
)} {/* Controls */}
{/* ) => setGlobalFilter(e.target.value) } className="w-64 bg-white border-gray-300 focus:border-blue-500 focus:ring-blue-500" /> */} {globalFilter && ( )}
{data.length > 0 && ( )}
Análise Analítica {filtros.linhaSelecionada ? ` - ${filtros.linhaSelecionada}` : ''} Relatório detalhado de transações - Versão Maximizada
{renderAnaliticoContent(true)}
{/* Conteúdo Principal - Versão Normal */} {renderAnaliticoContent(false)} {/* Advanced Filters Dialog */} Filtros Avançados

Estes filtros são aplicados sobre os dados já filtrados pela tabela DRE Gerencial.

{conditions.map((cond, idx) => (
{!( cond.operator === 'empty' || cond.operator === 'notEmpty' ) && (
) => { const next = [...conditions]; next[idx].value = e.target.value; setConditions(next); }} placeholder="Digite o valor" className="w-full bg-white border-gray-300" />
)} {conditions.length > 1 && (
)}
))}
); }