diff --git a/src/app/DRE/analitico.tsx b/src/app/DRE/analitico.tsx index cab4e37..46e2a1c 100644 --- a/src/app/DRE/analitico.tsx +++ b/src/app/DRE/analitico.tsx @@ -6,10 +6,8 @@ import { getCoreRowModel, getSortedRowModel, getFilteredRowModel, - flexRender, } from "@tanstack/react-table"; import { useVirtualizer } from "@tanstack/react-virtual"; -import { Card, CardContent } from "@/components/ui/card"; import { Input } from "@/components/ui/input"; import { Button } from "@/components/ui/button"; import { @@ -26,7 +24,7 @@ import { SelectContent, SelectItem, } from "@/components/ui/select"; -import { ChevronUp, ChevronDown, Download } from "lucide-react"; +import { Download } from "lucide-react"; import * as XLSX from 'xlsx'; interface AnaliticoItem { @@ -69,7 +67,6 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { const [columnFilters, setColumnFilters] = React.useState([]); const [open, setOpen] = React.useState(false); const [conditions, setConditions] = React.useState([{ column: "", operator: "contains", value: "" }]); - const [isScrolled, setIsScrolled] = React.useState(false); const fetchData = React.useCallback(async () => { // Só faz a requisição se tiver dataInicio e dataFim @@ -230,15 +227,6 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { const virtualRows = rowVirtualizer.getVirtualItems(); - React.useEffect(() => { - const handleScroll = () => { - if (!parentRef.current) return; - setIsScrolled(parentRef.current.scrollTop > 0); - }; - const el = parentRef.current; - el?.addEventListener("scroll", handleScroll); - return () => el?.removeEventListener("scroll", handleScroll); - }, []); const applyFilters = () => { // Agrupar múltiplas condições por coluna @@ -325,322 +313,284 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { }; return ( - - -
-
-
- - - -
-
-

Análise Analítica

-

Relatório detalhado de transações

-
+
+ {/* Header Section */} +
+
+
+ + +
-
- ) => setGlobalFilter(e.target.value)} - className="w-64 bg-white border-gray-300 focus:border-blue-500 focus:ring-blue-500" - /> - - {data.length > 0 && ( - - )} +
+

Análise Analítica

+

Relatório detalhado de transações

+
+ + {/* Controls */} +
+ ) => setGlobalFilter(e.target.value)} + className="w-64 bg-white border-gray-300 focus:border-blue-500 focus:ring-blue-500" + /> + + {data.length > 0 && ( + + )} +
-
-
- - - {table.getHeaderGroups().map((hg) => ( - - {hg.headers.map((header) => { - const sorted = header.column.getIsSorted(); - return ( - - ); - })} - - ))} - - - {loading ? ( - - - - ) : virtualRows.length === 0 ? ( - - - - ) : ( - virtualRows.map((virtualRow) => { - const row = table.getRowModel().rows[virtualRow.index]; - return ( - - {row.getVisibleCells().map((cell, cellIndex) => ( - - ))} - - ); - }) - )} - -
-
- - {flexRender(header.column.columnDef.header, header.getContext())} - -
- {sorted === "asc" ? ( - - ) : sorted === "desc" ? ( - - ) : ( -
- - -
- )} -
-
-
-
-
- Carregando dados analíticos... -
-
-
-
- - - -
- Nenhum dado analítico encontrado para os filtros aplicados. -
-
-
- {flexRender(cell.column.columnDef.cell, cell.getContext())} -
-
-
- - {data.length > 0 && ( -
-
-
-
- - - -
-
-

- Total de Registros: {table.getRowModel().rows.length} -

-

Transações encontradas

-
-
-
-

- - Valor Total: {new Intl.NumberFormat('pt-BR', { - style: 'currency', - currency: 'BRL', - }).format(totalValor)} - -

-

Soma de todos os valores

-
-
-
- )} -
+ {/* Table Container */} +
+ {/* Table Header */} +
+
+
Data Comp.
+
Data Venc.
+
Data Caixa
+
Cód. Fornec.
+
Fornecedor
+
Cód. Centro
+
Cód. Conta
+
Conta
+
Valor
+
Recnum
+
+
- - - - Filtros Avançados - - -
- {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 && ( -
- -
- )} -
- ))} - -
- + {/* Table Body */} +
+ {loading ? ( +
+
+
+

Carregando dados...

-
+
+ ) : virtualRows.length === 0 ? ( +
+
+
+ + + +
+

Nenhum dado encontrado

+
+
+ ) : ( +
+ {virtualRows.map((virtualRow) => { + const row = table.getRowModel().rows[virtualRow.index]; + return ( +
+
{new Date(row.original.data_competencia).toLocaleDateString('pt-BR')}
+
{new Date(row.original.data_vencimento).toLocaleDateString('pt-BR')}
+
{new Date(row.original.data_caixa).toLocaleDateString('pt-BR')}
+
{row.original.codigo_fornecedor}
+
{row.original.nome_fornecedor}
+
{row.original.codigo_centrocusto}
+
{row.original.codigo_conta}
+
{row.original.conta}
+
+ {new Intl.NumberFormat('pt-BR', { style: 'currency', currency: 'BRL' }).format(row.original.valor)} +
+
{row.original.recnum}
+
+ ); + })} +
+ )} +
+
+ {/* Summary Footer */} + {data.length > 0 && ( +
+
+
+
+ + + +
+
+

+ Total de Registros: {table.getRowModel().rows.length} +

+

Transações encontradas

+
+
+
+

+ + Valor Total: {new Intl.NumberFormat('pt-BR', { + style: 'currency', + currency: 'BRL', + }).format(totalValor)} + +

+

Soma de todos os valores

+
+
+
+ )} - - +
+ )} +
+ ))} + +
+ - - - - - - +
+
+ + + + + + + +
); } \ No newline at end of file diff --git a/src/app/DRE/teste.tsx b/src/app/DRE/teste.tsx index f543065..272032c 100644 --- a/src/app/DRE/teste.tsx +++ b/src/app/DRE/teste.tsx @@ -1,8 +1,6 @@ 'use client'; -import { Button } from '@/components/ui/button'; -// Removed unused table imports -import { ArrowDown, ArrowUp, ArrowUpDown, LoaderPinwheel } from 'lucide-react'; +import { LoaderPinwheel } from 'lucide-react'; import { useEffect, useState } from 'react'; import AnaliticoComponent from './analitico'; @@ -32,13 +30,6 @@ interface HierarchicalRow { percentuaisPorMes?: Record; } -type SortField = 'descricao' | 'valor'; -type SortDirection = 'asc' | 'desc'; - -interface SortConfig { - field: SortField; - direction: SortDirection; -} export default function Teste() { const [data, setData] = useState([]); @@ -51,10 +42,6 @@ export default function Teste() { const [expandedCentros, setExpandedCentros] = useState>( new Set() ); - const [sortConfig, setSortConfig] = useState({ - field: 'descricao', - direction: 'asc', - }); const [mesesDisponiveis, setMesesDisponiveis] = useState([]); // Estados para analítico @@ -207,24 +194,6 @@ export default function Teste() { setExpandedCentros(newExpanded); }; - const handleSort = (field: SortField) => { - setSortConfig((prev) => ({ - field, - direction: - prev.field === field && prev.direction === 'asc' ? 'desc' : 'asc', - })); - }; - - const getSortIcon = (field: SortField) => { - if (sortConfig.field !== field) { - return ; - } - return sortConfig.direction === 'asc' ? ( - - ) : ( - - ); - }; const calcularValoresPorMes = (items: DREItem[]): Record => { const valoresPorMes: Record = {}; @@ -319,25 +288,7 @@ export default function Teste() { }, {} as Record); // Ordenar grupos - const sortedGrupos = Object.entries(grupos).sort(([a], [b]) => { - if (sortConfig.field === 'descricao') { - return sortConfig.direction === 'asc' - ? a.localeCompare(b) - : b.localeCompare(a); - } else { - const totalA = grupos[a].reduce( - (sum, item) => sum + parseFloat(item.valor), - 0 - ); - const totalB = grupos[b].reduce( - (sum, item) => sum + parseFloat(item.valor), - 0 - ); - return sortConfig.direction === 'asc' - ? totalA - totalB - : totalB - totalA; - } - }); + const sortedGrupos = Object.entries(grupos).sort(([a], [b]) => a.localeCompare(b)); sortedGrupos.forEach(([grupo, items]) => { const totalGrupo = items.reduce( @@ -378,25 +329,7 @@ export default function Teste() { }, {} as Record); // Ordenar subgrupos - const sortedSubgrupos = Object.entries(subgrupos).sort(([a], [b]) => { - if (sortConfig.field === 'descricao') { - return sortConfig.direction === 'asc' - ? a.localeCompare(b) - : b.localeCompare(a); - } else { - const totalA = subgrupos[a].reduce( - (sum, item) => sum + parseFloat(item.valor), - 0 - ); - const totalB = subgrupos[b].reduce( - (sum, item) => sum + parseFloat(item.valor), - 0 - ); - return sortConfig.direction === 'asc' - ? totalA - totalB - : totalB - totalA; - } - }); + const sortedSubgrupos = Object.entries(subgrupos).sort(([a], [b]) => a.localeCompare(b)); sortedSubgrupos.forEach(([subgrupo, subgrupoItems]) => { const totalSubgrupo = subgrupoItems.reduce( @@ -431,25 +364,7 @@ export default function Teste() { }, {} as Record); // Ordenar centros de custo - const sortedCentros = Object.entries(centros).sort(([a], [b]) => { - if (sortConfig.field === 'descricao') { - return sortConfig.direction === 'asc' - ? a.localeCompare(b) - : b.localeCompare(a); - } else { - const totalA = centros[a].reduce( - (sum, item) => sum + parseFloat(item.valor), - 0 - ); - const totalB = centros[b].reduce( - (sum, item) => sum + parseFloat(item.valor), - 0 - ); - return sortConfig.direction === 'asc' - ? totalA - totalB - : totalB - totalA; - } - }); + const sortedCentros = Object.entries(centros).sort(([a], [b]) => a.localeCompare(b)); sortedCentros.forEach(([centro, centroItems]) => { const totalCentro = centroItems.reduce( @@ -487,25 +402,7 @@ export default function Teste() { }, {} as Record); // Ordenar contas - const sortedContas = Object.entries(contas).sort(([a], [b]) => { - if (sortConfig.field === 'descricao') { - return sortConfig.direction === 'asc' - ? a.localeCompare(b) - : b.localeCompare(a); - } else { - const totalA = contas[a].reduce( - (sum, item) => sum + parseFloat(item.valor), - 0 - ); - const totalB = contas[b].reduce( - (sum, item) => sum + parseFloat(item.valor), - 0 - ); - return sortConfig.direction === 'asc' - ? totalA - totalB - : totalB - totalA; - } - }); + const sortedContas = Object.entries(contas).sort(([a], [b]) => a.localeCompare(b)); sortedContas.forEach(([conta, contaItems]) => { const totalConta = contaItems.reduce( @@ -542,7 +439,7 @@ export default function Teste() { }; const getRowStyle = (row: HierarchicalRow) => { - const baseStyle = 'transition-colors hover:bg-muted/50'; + const baseStyle = 'transition-all duration-200 hover:bg-gradient-to-r hover:from-blue-50/30 hover:to-indigo-50/30'; // Criar identificador único para a linha const linhaId = `${row.type}-${row.grupo || ''}-${row.subgrupo || ''}-${ @@ -553,18 +450,18 @@ export default function Teste() { let style = baseStyle; if (isSelected) { - style += ' bg-blue-100 border-l-4 border-blue-500 shadow-md'; + style += ' bg-gradient-to-r from-blue-100 to-indigo-100 border-l-4 border-blue-500 shadow-lg'; } switch (row.type) { case 'grupo': - return `${style} bg-primary/5 font-semibold`; + return `${style} bg-gradient-to-r from-blue-50/20 to-indigo-50/20 font-bold text-gray-900 border-b-2 border-blue-200`; case 'subgrupo': - return `${style} bg-primary/10 font-medium`; + return `${style} bg-gradient-to-r from-gray-50/30 to-blue-50/20 font-semibold text-gray-800`; case 'centro_custo': - return `${style} bg-secondary/30 font-medium`; + return `${style} bg-gradient-to-r from-gray-50/20 to-gray-100/10 font-medium text-gray-700`; case 'conta': - return `${style} bg-muted/20`; + return `${style} bg-white font-normal text-gray-600`; default: return style; } @@ -578,66 +475,74 @@ export default function Teste() { switch (row.type) { case 'grupo': return ( -
+
); case 'subgrupo': return ( -
+
); case 'centro_custo': return ( -
+
); case 'conta': return ( -
- +
+
+ +
); @@ -648,11 +553,28 @@ export default function Teste() { if (loading) { return ( -
-
-
- -

Carregando dados...

+
+
+
+
+ + + +
+
+

DRE Gerencial

+

Demonstração do Resultado do Exercício

+
+
+
+ +
+
+
+ +
+

Carregando dados...

+

Aguarde enquanto processamos as informações

@@ -661,12 +583,33 @@ export default function Teste() { if (error) { return ( -
-

- Erro ao carregar DRE Gerencial -

-
-

{error}

+
+
+
+
+ + + +
+
+

DRE Gerencial

+

Demonstração do Resultado do Exercício

+
+
+
+ +
+
+
+ + + +
+

Erro ao carregar DRE Gerencial

+

+ {error} +

+
); @@ -675,79 +618,57 @@ export default function Teste() { const hierarchicalData = buildHierarchicalData(); return ( -
-
-

DRE Gerencial

+
+ {/* Header Section */} +
+
+
+ + + +
+
+

DRE Gerencial

+

Demonstração do Resultado do Exercício

+
+
-
- {/* Header fixo separado */} -
-
-
- -
+ {/* Table Container */} +
+ {/* Table Header */} +
+
+
Descrição
{mesesDisponiveis.map((mes) => ( -
-
- {mes} -
-
- % -
+
+
{mes}
+
%
))} -
- -
+
Total
-
+ {/* Table Body */} +
{hierarchicalData.map((row, index) => ( -
-
+
+
{renderCellContent(row)}
{mesesDisponiveis.map((mes) => ( -
+
handleRowClick(row, mes)} + title={row.valoresPorMes && row.valoresPorMes[mes] ? formatCurrency(row.valoresPorMes[mes]) : '-'} > {row.valoresPorMes && row.valoresPorMes[mes] ? (() => { - const { formatted, isNegative } = - formatCurrencyWithColor(row.valoresPorMes[mes]); + const { formatted, isNegative } = formatCurrencyWithColor(row.valoresPorMes[mes]); return ( - + {formatted} ); @@ -755,28 +676,25 @@ export default function Teste() { : '-'}
handleRowClick(row, mes)} + title={row.percentuaisPorMes && row.percentuaisPorMes[mes] !== undefined ? `${row.percentuaisPorMes[mes].toFixed(1)}%` : '-'} > - {row.percentuaisPorMes && - row.percentuaisPorMes[mes] !== undefined + {row.percentuaisPorMes && row.percentuaisPorMes[mes] !== undefined ? `${row.percentuaisPorMes[mes].toFixed(1)}%` : '-'}
))}
handleRowClick(row)} + title={row.total ? formatCurrency(row.total) : '-'} > {(() => { - const { formatted, isNegative } = formatCurrencyWithColor( - row.total! - ); + const { formatted, isNegative } = formatCurrencyWithColor(row.total!); return ( - + {formatted} );