From 7758ad5abeaf92bef16e65a754b675b105165e04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alessandro=20Gon=C3=A7aalves?= Date: Mon, 20 Oct 2025 12:15:53 -0300 Subject: [PATCH 01/30] =?UTF-8?q?fix:=20adicionados=20filtros=20e=20estili?= =?UTF-8?q?za=C3=A7=C3=A3o=20na=20tabela=20de=20anal=C3=ADtico?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .eslintrc.json | 6 + docs/README.md | 95 +++++ docs/api.md | 377 +++++++++++++++++ docs/architecture.md | 185 +++++++++ docs/components.md | 539 ++++++++++++++++++++++++ docs/database.md | 264 ++++++++++++ docs/deployment.md | 580 ++++++++++++++++++++++++++ docs/development.md | 529 ++++++++++++++++++++++++ docs/troubleshooting.md | 603 +++++++++++++++++++++++++++ package-lock.json | 766 +++++++++++++++++++++++++++++++++- package.json | 4 + src/app/DRE/analitico.tsx | 777 +++++++++++++++++++++-------------- src/components/ui/card.tsx | 27 ++ src/components/ui/dialog.tsx | 119 ++++++ src/components/ui/input.tsx | 24 ++ src/components/ui/select.tsx | 157 +++++++ 16 files changed, 4736 insertions(+), 316 deletions(-) create mode 100644 .eslintrc.json create mode 100644 docs/README.md create mode 100644 docs/api.md create mode 100644 docs/architecture.md create mode 100644 docs/components.md create mode 100644 docs/database.md create mode 100644 docs/deployment.md create mode 100644 docs/development.md create mode 100644 docs/troubleshooting.md create mode 100644 src/components/ui/card.tsx create mode 100644 src/components/ui/dialog.tsx create mode 100644 src/components/ui/input.tsx create mode 100644 src/components/ui/select.tsx diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 0000000..13015d6 --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,6 @@ +{ + "extends": "next/core-web-vitals", + "rules": { + "@typescript-eslint/no-explicit-any": "off" + } +} diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000..f553c41 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,95 @@ +# DRE Gerencial - Documentação do Sistema + +## Visão Geral + +O **DRE Gerencial** é um sistema web desenvolvido em Next.js para análise e visualização de dados financeiros através de uma Demonstração do Resultado do Exercício (DRE) hierárquica e interativa. + +## Objetivo Principal + +O sistema tem como objetivo principal fornecer uma interface intuitiva para análise de dados financeiros empresariais, permitindo: + +- Visualização hierárquica de dados financeiros (Grupo → Subgrupo → Centro de Custo → Conta) +- Análise temporal por períodos mensais +- Drill-down analítico para detalhamento de transações +- Exportação de dados para Excel +- Cálculo de percentuais baseados em grupos de referência + +## Características Principais + +### 1. **Interface Hierárquica** +- Estrutura em árvore expansível (Grupo → Subgrupo → Centro de Custo → Conta) +- Visualização de valores e percentuais por mês +- Ordenação por descrição ou valor total +- Seleção de linhas para análise detalhada + +### 2. **Análise Analítica** +- Drill-down a partir de qualquer nível hierárquico +- Filtros por período, centro de custo, grupo, subgrupo e conta +- Visualização detalhada de transações individuais +- Exportação para Excel com múltiplas abas + +### 3. **Cálculos Automáticos** +- Percentuais baseados no Grupo 03 como referência +- Totais consolidados por nível hierárquico +- Valores por mês com formatação monetária brasileira + +## Estrutura do Projeto + +``` +src/ +├── app/ +│ ├── api/ +│ │ ├── analitico/route.ts # API para dados analíticos +│ │ └── dre/route.ts # API para dados DRE +│ ├── DRE/ +│ │ ├── analitico.tsx # Componente de análise analítica +│ │ ├── page.tsx # Página principal +│ │ └── teste.tsx # Componente principal DRE +│ └── layout.tsx # Layout da aplicação +├── components/ +│ └── ui/ # Componentes UI reutilizáveis +├── db/ +│ ├── index.ts # Configuração do banco +│ └── schema.ts # Schema do banco de dados +└── lib/ + └── utils.ts # Utilitários +``` + +## Tecnologias Utilizadas + +- **Frontend**: Next.js 15, React 19, TypeScript +- **Styling**: Tailwind CSS 4 +- **Database**: PostgreSQL com Drizzle ORM +- **UI Components**: Radix UI, Lucide React +- **Export**: XLSX para Excel + +## Documentação Detalhada + +- [Arquitetura do Sistema](./architecture.md) +- [Banco de Dados](./database.md) +- [APIs](./api.md) +- [Componentes](./components.md) +- [Guia de Desenvolvimento](./development.md) +- [Deploy e Configuração](./deployment.md) +- [Troubleshooting](./troubleshooting.md) + +## Quick Start + +1. Instalar dependências: `npm install` +2. Configurar variáveis de ambiente (ver [Deploy](./deployment.md)) +3. Executar: `npm run dev` +4. Acessar: `http://localhost:3000/DRE` + +## Manutenção + +Para manter o sistema sem perder suas características: + +1. **Preserve a hierarquia**: Grupo → Subgrupo → Centro de Custo → Conta +2. **Mantenha os cálculos**: Percentuais baseados no Grupo 03 +3. **Conserve a funcionalidade**: Drill-down e exportação Excel +4. **Atualize dados**: Mantenha sincronização com fonte de dados +5. **Teste filtros**: Valide todos os filtros analíticos + +--- + +*Última atualização: $(date)* diff --git a/docs/api.md b/docs/api.md new file mode 100644 index 0000000..af48e04 --- /dev/null +++ b/docs/api.md @@ -0,0 +1,377 @@ +# APIs - DRE Gerencial + +## Visão Geral + +O sistema possui duas APIs principais construídas com Next.js App Router, utilizando Drizzle ORM para interação com PostgreSQL. + +## Estrutura das APIs + +### 1. **API DRE Gerencial** (`/api/dre/route.ts`) + +#### Endpoint +``` +GET /api/dre +``` + +#### Descrição +Retorna dados consolidados da view `view_dre_gerencial` para construção da interface hierárquica. + +#### Implementação +```typescript +import db from '@/db'; +import { sql } from 'drizzle-orm'; +import { NextResponse } from 'next/server'; + +export async function GET() { + try { + const data = await db.execute(sql`SELECT * FROM view_dre_gerencial`); + return NextResponse.json(data.rows); + } catch (error) { + console.error('Erro ao buscar dados da view:', error); + return NextResponse.json( + { error: 'Erro ao carregar dados' }, + { status: 500 } + ); + } +} +``` + +#### Response +```typescript +interface DREItem { + codfilial: string; + data_competencia: string; + data_caixa: string; + grupo: string; + subgrupo: string; + centro_custo: string; + codigo_conta: number; + conta: string; + valor: string; +} +``` + +#### Casos de Uso +- Carregamento inicial da interface DRE +- Construção da hierarquia Grupo → Subgrupo → Centro de Custo → Conta +- Cálculo de totais e percentuais + +--- + +### 2. **API Analítica** (`/api/analitico/route.ts`) + +#### Endpoint +``` +GET /api/analitico?dataInicio=YYYY-MM&dataFim=YYYY-MM&[filtros] +``` + +#### Parâmetros + +| Parâmetro | Tipo | Obrigatório | Descrição | +|-----------|------|-------------|-----------| +| `dataInicio` | string | ✅ | Período inicial (YYYY-MM) | +| `dataFim` | string | ✅ | Período final (YYYY-MM) | +| `centroCusto` | string | ❌ | Filtro por centro de custo | +| `codigoGrupo` | string | ❌ | Filtro por código do grupo | +| `codigoSubgrupo` | string | ❌ | Filtro por código do subgrupo | +| `codigoConta` | string | ❌ | Filtro por código da conta | + +#### Implementação +```typescript +export async function GET(request: NextRequest) { + try { + const { searchParams } = new URL(request.url); + const dataInicio = searchParams.get('dataInicio'); + const dataFim = searchParams.get('dataFim'); + const centroCusto = searchParams.get('centroCusto'); + const codigoGrupo = searchParams.get('codigoGrupo'); + const codigoSubgrupo = searchParams.get('codigoSubgrupo'); + const codigoConta = searchParams.get('codigoConta'); + + if (!dataInicio || !dataFim) { + return NextResponse.json( + { message: 'Parâmetros obrigatórios: dataInicio, dataFim' }, + { status: 400 } + ); + } + + // Construção dinâmica da query baseada nos filtros + let query; + + if (centroCusto || codigoGrupo || codigoSubgrupo || codigoConta) { + // Query com filtros específicos + query = buildFilteredQuery(dataInicio, dataFim, filtros); + } else { + // Query simples por período + query = buildSimpleQuery(dataInicio, dataFim); + } + + const data = await db.execute(query); + return NextResponse.json(data.rows); + } catch (error) { + console.error('Erro ao buscar dados analíticos:', error); + return NextResponse.json( + { + message: 'Erro ao buscar dados analíticos', + error: error instanceof Error ? error.message : String(error), + }, + { status: 500 } + ); + } +} +``` + +#### Response +```typescript +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; + valor: number; + historico: string; + historico2: string; + created_at: string; + updated_at: string; +} +``` + +## Estratégias de Query + +### 1. **Query Simples (Sem Filtros Específicos)** +```sql +SELECT + ffa.codigo_fornecedor, + ffa.nome_fornecedor, + ffa.id, + ffa.codfilial, + ffa.recnum, + ffa.data_competencia, + ffa.data_vencimento, + ffa.data_pagamento, + ffa.data_caixa, + ffa.codigo_conta, + ffa.conta, + ffa.codigo_centrocusto, + ffa.valor, + ffa.historico, + ffa.historico2, + ffa.created_at, + ffa.updated_at +FROM fato_financeiro_analitico AS ffa +WHERE to_char(ffa.data_competencia, 'YYYY-MM') BETWEEN $1 AND $2 +``` + +### 2. **Query com Filtros de Centro de Custo e Conta** +```sql +SELECT ffa.* +FROM fato_financeiro_analitico AS ffa +WHERE to_char(ffa.data_competencia, 'YYYY-MM') BETWEEN $1 AND $2 + AND ffa.codigo_centrocusto = $3 + AND ffa.codigo_conta = $4 +``` + +### 3. **Query com Filtros de Grupo/Subgrupo** +```sql +SELECT ffa.* +FROM fato_financeiro_analitico AS ffa +WHERE EXISTS ( + SELECT 1 FROM public.view_dre_gerencial AS dre + WHERE ffa.codigo_conta = dre.codigo_conta::text + AND ffa.codigo_centrocusto = dre.centro_custo + AND to_char(ffa.data_competencia, 'YYYY-MM') = to_char(dre.data_competencia, 'YYYY-MM') + AND SUBSTRING(dre.grupo FROM '^\\s*(\\d+)\\s*\\.') = $1 + AND SUBSTRING(dre.subgrupo FROM '^\\s*(\\d+(?:\\.\\d+)+)\\s*-') = $2 +) +AND to_char(ffa.data_competencia, 'YYYY-MM') BETWEEN $3 AND $4 +``` + +## Tratamento de Erros + +### 1. **Validação de Parâmetros** +```typescript +if (!dataInicio || !dataFim) { + return NextResponse.json( + { message: 'Parâmetros obrigatórios: dataInicio, dataFim' }, + { status: 400 } + ); +} +``` + +### 2. **Tratamento de Erros de Banco** +```typescript +try { + const data = await db.execute(query); + return NextResponse.json(data.rows); +} catch (error) { + console.error('Erro ao buscar dados:', error); + return NextResponse.json( + { + message: 'Erro ao buscar dados', + error: error instanceof Error ? error.message : String(error), + }, + { status: 500 } + ); +} +``` + +### 3. **Códigos de Status HTTP** + +| Status | Cenário | Response | +|--------|---------|----------| +| 200 | Sucesso | Dados solicitados | +| 400 | Parâmetros inválidos | Mensagem de erro | +| 500 | Erro interno | Detalhes do erro | + +## Performance e Otimização + +### 1. **Índices Recomendados** +```sql +-- Para filtros por data +CREATE INDEX idx_fato_financeiro_data_competencia +ON fato_financeiro_analitico (data_competencia); + +-- Para filtros por centro de custo +CREATE INDEX idx_fato_financeiro_centro_custo +ON fato_financeiro_analitico (codigo_centrocusto); + +-- Para filtros por conta +CREATE INDEX idx_fato_financeiro_conta +ON fato_financeiro_analitico (codigo_conta); +``` + +### 2. **Estratégias de Cache** +- **Client-side**: React Query para cache de dados +- **Server-side**: Cache de views materializadas +- **CDN**: Para assets estáticos + +### 3. **Paginação (Futuro)** +```typescript +interface PaginatedResponse { + data: T[]; + pagination: { + page: number; + limit: number; + total: number; + totalPages: number; + }; +} +``` + +## Segurança + +### 1. **Validação de Input** +- Sanitização de parâmetros de query +- Validação de tipos de dados +- Escape de caracteres especiais + +### 2. **SQL Injection Prevention** +- Uso de prepared statements via Drizzle +- Parâmetros tipados +- Validação de entrada + +### 3. **Rate Limiting (Futuro)** +```typescript +// Implementação de rate limiting +const rateLimit = new Map(); + +export async function GET(request: NextRequest) { + const ip = request.ip; + const now = Date.now(); + const windowMs = 15 * 60 * 1000; // 15 minutos + const maxRequests = 100; + + // Lógica de rate limiting +} +``` + +## Monitoramento + +### 1. **Logs Estruturados** +```typescript +console.log({ + timestamp: new Date().toISOString(), + endpoint: '/api/analitico', + method: 'GET', + params: { dataInicio, dataFim, centroCusto }, + duration: Date.now() - startTime, + status: 'success' +}); +``` + +### 2. **Métricas de Performance** +- Tempo de resposta por endpoint +- Número de requisições por minuto +- Taxa de erro por endpoint +- Uso de memória e CPU + +### 3. **Health Check (Futuro)** +```typescript +// GET /api/health +export async function GET() { + try { + await db.execute(sql`SELECT 1`); + return NextResponse.json({ status: 'healthy', timestamp: new Date() }); + } catch (error) { + return NextResponse.json({ status: 'unhealthy', error: error.message }, { status: 500 }); + } +} +``` + +## Testes + +### 1. **Testes Unitários** +```typescript +// Exemplo de teste para API DRE +describe('/api/dre', () => { + it('should return DRE data', async () => { + const response = await fetch('/api/dre'); + const data = await response.json(); + + expect(response.status).toBe(200); + expect(Array.isArray(data)).toBe(true); + }); +}); +``` + +### 2. **Testes de Integração** +```typescript +// Teste com filtros +describe('/api/analitico', () => { + it('should filter by date range', async () => { + const params = new URLSearchParams({ + dataInicio: '2024-01', + dataFim: '2024-12' + }); + + const response = await fetch(`/api/analitico?${params}`); + const data = await response.json(); + + expect(response.status).toBe(200); + expect(data.every(item => + item.data_competencia.startsWith('2024') + )).toBe(true); + }); +}); +``` + +## Próximos Passos + +1. **Implementar Autenticação** JWT +2. **Adicionar Rate Limiting** por IP +3. **Implementar Cache Redis** para queries frequentes +4. **Adicionar Paginação** para grandes volumes +5. **Implementar Webhooks** para notificações +6. **Adicionar Documentação OpenAPI** (Swagger) +7. **Implementar Versionamento** de API +8. **Adicionar Monitoramento** com Prometheus/Grafana diff --git a/docs/architecture.md b/docs/architecture.md new file mode 100644 index 0000000..d6fc2ba --- /dev/null +++ b/docs/architecture.md @@ -0,0 +1,185 @@ +# Arquitetura do Sistema DRE Gerencial + +## Visão Geral da Arquitetura + +O sistema DRE Gerencial segue uma arquitetura moderna baseada em Next.js com App Router, utilizando uma abordagem de componentes React funcionais e TypeScript para type safety. + +## Padrões Arquiteturais + +### 1. **Arquitetura em Camadas** + +``` +┌─────────────────────────────────────┐ +│ Frontend Layer │ +│ (React Components + Tailwind CSS) │ +├─────────────────────────────────────┤ +│ API Layer │ +│ (Next.js API Routes) │ +├─────────────────────────────────────┤ +│ Database Layer │ +│ (PostgreSQL + Drizzle ORM) │ +└─────────────────────────────────────┘ +``` + +### 2. **Estrutura de Componentes** + +#### Componente Principal (`teste.tsx`) +- **Responsabilidade**: Orquestração da interface DRE hierárquica +- **Estado**: Gerencia expansão/colapso, ordenação, filtros analíticos +- **Padrão**: Container Component com lógica de negócio + +#### Componente Analítico (`analitico.tsx`) +- **Responsabilidade**: Visualização detalhada de transações +- **Estado**: Dados analíticos, ordenação, loading +- **Padrão**: Presentational Component com funcionalidades específicas + +### 3. **Gerenciamento de Estado** + +#### Estados Locais por Componente +```typescript +// Estados de expansão hierárquica +const [expandedGroups, setExpandedGroups] = useState>(new Set()); +const [expandedSubgrupos, setExpandedSubgrupos] = useState>(new Set()); +const [expandedCentros, setExpandedCentros] = useState>(new Set()); + +// Estados de ordenação +const [sortConfig, setSortConfig] = useState({ + field: 'descricao', + direction: 'asc', +}); + +// Estados de filtros analíticos +const [analiticoFiltros, setAnaliticoFiltros] = useState({ + dataInicio: '', + dataFim: '', + centroCusto: '', + codigoGrupo: '', + codigoSubgrupo: '', + codigoConta: '', +}); +``` + +### 4. **Padrões de Dados** + +#### Hierarquia de Dados +```typescript +interface HierarchicalRow { + type: 'grupo' | 'subgrupo' | 'centro_custo' | 'conta'; + level: number; + grupo?: string; + subgrupo?: string; + centro_custo?: string; + conta?: string; + codigo_conta?: number; + total?: number; + isExpanded?: boolean; + valoresPorMes?: Record; + percentuaisPorMes?: Record; +} +``` + +#### Transformação de Dados +- **Agregação**: Dados brutos → Hierarquia estruturada +- **Cálculos**: Valores por mês e percentuais automáticos +- **Ordenação**: Por descrição ou valor total + +## Fluxo de Dados + +### 1. **Carregamento Inicial** +``` +API /api/dre → Dados brutos → buildHierarchicalData() → Interface hierárquica +``` + +### 2. **Interação do Usuário** +``` +Clique em linha → handleRowClick() → setAnaliticoFiltros() → AnaliticoComponent +``` + +### 3. **Análise Analítica** +``` +Filtros → API /api/analitico → Dados detalhados → Tabela analítica +``` + +## Padrões de Design + +### 1. **Component Composition** +- Componentes pequenos e focados +- Props tipadas com TypeScript +- Separação de responsabilidades + +### 2. **Custom Hooks (Potencial)** +```typescript +// Exemplo de hook customizado para dados DRE +const useDREData = () => { + const [data, setData] = useState([]); + const [loading, setLoading] = useState(true); + + const fetchData = useCallback(async () => { + // Lógica de fetch + }, []); + + return { data, loading, fetchData }; +}; +``` + +### 3. **Error Boundaries** +- Tratamento de erros em componentes +- Estados de loading e error +- Fallbacks visuais + +## Performance + +### 1. **Otimizações Implementadas** +- `useCallback` para funções de fetch +- `useMemo` para cálculos pesados (potencial) +- Lazy loading de componentes (potencial) + +### 2. **Estratégias de Renderização** +- Renderização condicional baseada em estado +- Virtualização para listas grandes (potencial) +- Debounce para filtros (potencial) + +## Escalabilidade + +### 1. **Estrutura Modular** +- Componentes reutilizáveis em `/components/ui` +- APIs separadas por funcionalidade +- Schema de banco bem definido + +### 2. **Extensibilidade** +- Fácil adição de novos níveis hierárquicos +- Suporte a novos tipos de filtros +- Integração com outras fontes de dados + +## Segurança + +### 1. **Validação de Dados** +- TypeScript para type safety +- Validação de parâmetros nas APIs +- Sanitização de queries SQL + +### 2. **Controle de Acesso** +- Autenticação (a implementar) +- Autorização por níveis (a implementar) +- Logs de auditoria (a implementar) + +## Monitoramento + +### 1. **Logs** +- Console logs para debugging +- Error tracking (a implementar) +- Performance monitoring (a implementar) + +### 2. **Métricas** +- Tempo de carregamento de dados +- Uso de filtros +- Exportações realizadas + +## Próximos Passos Arquiteturais + +1. **Implementar Context API** para estado global +2. **Adicionar React Query** para cache de dados +3. **Implementar Error Boundaries** robustos +4. **Adicionar testes unitários** e de integração +5. **Implementar autenticação** e autorização +6. **Adicionar monitoramento** e analytics diff --git a/docs/components.md b/docs/components.md new file mode 100644 index 0000000..bcdd732 --- /dev/null +++ b/docs/components.md @@ -0,0 +1,539 @@ +# Componentes - DRE Gerencial + +## Visão Geral + +O sistema DRE Gerencial é construído com componentes React funcionais em TypeScript, seguindo padrões modernos de desenvolvimento frontend. + +## Estrutura de Componentes + +### 1. **Componente Principal** (`src/app/DRE/teste.tsx`) + +#### Responsabilidades +- Orquestração da interface DRE hierárquica +- Gerenciamento de estado de expansão/colapso +- Controle de ordenação e filtros +- Integração com componente analítico + +#### Estados Principais +```typescript +const [data, setData] = useState([]); +const [loading, setLoading] = useState(true); +const [error, setError] = useState(null); +const [expandedGroups, setExpandedGroups] = useState>(new Set()); +const [expandedSubgrupos, setExpandedSubgrupos] = useState>(new Set()); +const [expandedCentros, setExpandedCentros] = useState>(new Set()); +const [sortConfig, setSortConfig] = useState({ + field: 'descricao', + direction: 'asc', +}); +const [analiticoFiltros, setAnaliticoFiltros] = useState({ + dataInicio: '', + dataFim: '', + centroCusto: '', + codigoGrupo: '', + codigoSubgrupo: '', + codigoConta: '', +}); +``` + +#### Funções Principais + +##### `fetchData()` +```typescript +const fetchData = async () => { + try { + setLoading(true); + setError(null); + const response = await fetch('/api/dre'); + + if (!response.ok) { + throw new Error(`Erro ao carregar dados: ${response.status}`); + } + + const result = await response.json(); + setData(result); + + // Extrair meses únicos dos dados + const meses = [...new Set( + result.map((item: DREItem) => { + const dataCompetencia = new Date(item.data_competencia); + return `${dataCompetencia.getFullYear()}-${String( + dataCompetencia.getMonth() + 1 + ).padStart(2, '0')}`; + }) + )].sort() as string[]; + + setMesesDisponiveis(meses); + } catch (err) { + setError(err instanceof Error ? err.message : 'Erro desconhecido'); + } finally { + setLoading(false); + } +}; +``` + +##### `buildHierarchicalData()` +```typescript +const buildHierarchicalData = (): HierarchicalRow[] => { + const rows: HierarchicalRow[] = []; + + // Agrupar por grupo, tratando grupo 05 como subgrupo do grupo 04 + const grupos = data.reduce((acc, item) => { + if (item.grupo.includes('05')) { + // Lógica especial para grupo 05 + const grupo04Key = Object.keys(acc).find((key) => key.includes('04')); + if (grupo04Key) { + acc[grupo04Key].push(item); + } else { + const grupo04Nome = '04 - GRUPO 04'; + if (!acc[grupo04Nome]) { + acc[grupo04Nome] = []; + } + acc[grupo04Nome].push(item); + } + } else { + if (!acc[item.grupo]) { + acc[item.grupo] = []; + } + acc[item.grupo].push(item); + } + return acc; + }, {} as Record); + + // Construir hierarquia completa + // ... lógica de construção hierárquica + + return rows; +}; +``` + +##### `handleRowClick()` +```typescript +const handleRowClick = (row: HierarchicalRow, mesSelecionado?: string) => { + if (!data.length) return; + + // Calcular período baseado nos dados + const datas = data.map((item) => item.data_competencia); + const dataInicio = Math.min(...datas.map((d) => new Date(d).getTime())); + const dataFim = Math.max(...datas.map((d) => new Date(d).getTime())); + + const dataInicioStr = new Date(dataInicio).toISOString().substring(0, 7); + const dataFimStr = new Date(dataFim).toISOString().substring(0, 7); + + const { codigoGrupo, codigoSubgrupo } = extractCodes( + row.grupo || '', + row.subgrupo + ); + + // Criar identificador único para a linha + const linhaId = `${row.type}-${row.grupo || ''}-${row.subgrupo || ''}-${ + row.centro_custo || '' + }-${row.codigo_conta || ''}`; + setLinhaSelecionada(linhaId); + + // Configurar filtros para análise analítica + const dataInicioFiltro = mesSelecionado || dataInicioStr; + const dataFimFiltro = mesSelecionado || dataFimStr; + + setAnaliticoFiltros({ + dataInicio: dataInicioFiltro, + dataFim: dataFimFiltro, + centroCusto: row.centro_custo || '', + codigoGrupo, + codigoSubgrupo, + codigoConta: row.codigo_conta?.toString() || '', + }); +}; +``` + +#### Renderização +```typescript +return ( +
+
+

DRE Gerencial

+
+ + {/* Tabela hierárquica */} +
+ {/* Header fixo */} +
+ {/* ... header content */} +
+ + {/* Dados hierárquicos */} +
+ {hierarchicalData.map((row, index) => ( +
+ {/* ... row content */} +
+ ))} +
+
+ + {/* Componente Analítico */} + {!loading && data.length > 0 && ( + + )} +
+); +``` + +--- + +### 2. **Componente Analítico** (`src/app/DRE/analitico.tsx`) + +#### Responsabilidades +- Visualização detalhada de transações +- Ordenação de dados analíticos +- Exportação para Excel +- Aplicação de filtros dinâmicos + +#### Props +```typescript +interface AnaliticoProps { + filtros: { + dataInicio: string; + dataFim: string; + centroCusto?: string; + codigoGrupo?: string; + codigoSubgrupo?: string; + codigoConta?: string; + }; +} +``` + +#### Estados +```typescript +const [data, setData] = useState([]); +const [loading, setLoading] = useState(false); +const [sortConfig, setSortConfig] = useState({ + field: 'data_competencia', + direction: 'desc', +}); +``` + +#### Funções Principais + +##### `fetchData()` +```typescript +const fetchData = useCallback(async () => { + if (!filtros.dataInicio || !filtros.dataFim) { + setData([]); + return; + } + + setLoading(true); + try { + const params = new URLSearchParams({ + dataInicio: filtros.dataInicio, + dataFim: filtros.dataFim, + ...(filtros.centroCusto && { centroCusto: filtros.centroCusto }), + ...(filtros.codigoGrupo && { codigoGrupo: filtros.codigoGrupo }), + ...(filtros.codigoSubgrupo && { codigoSubgrupo: filtros.codigoSubgrupo }), + ...(filtros.codigoConta && { codigoConta: filtros.codigoConta }), + }); + + const response = await fetch(`/api/analitico?${params}`); + if (response.ok) { + const result = await response.json(); + 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); + } +}, [filtros]); +``` + +##### `exportToExcel()` +```typescript +const exportToExcel = () => { + if (data.length === 0) return; + + // Preparar dados para exportação + const exportData = data.map((item) => ({ + 'Data Competência': new Date(item.data_competencia).toLocaleDateString('pt-BR'), + 'Data Vencimento': new Date(item.data_vencimento).toLocaleDateString('pt-BR'), + 'Data Caixa': new Date(item.data_caixa).toLocaleDateString('pt-BR'), + 'Código Fornecedor': item.codigo_fornecedor, + Fornecedor: item.nome_fornecedor, + 'Código Centro Custo': item.codigo_centrocusto, + 'Centro Custo': item.codigo_centrocusto, + 'Código Conta': item.codigo_conta, + Conta: item.conta, + Valor: typeof item.valor === 'string' ? parseFloat(item.valor) : item.valor, + Histórico: item.historico, + 'Histórico 2': item.historico2, + Recnum: item.recnum, + })); + + // Criar workbook + const wb = XLSX.utils.book_new(); + const ws = XLSX.utils.json_to_sheet(exportData); + + // Adicionar resumo na segunda aba + const resumoData = [ + { Métrica: 'Total de Registros', Valor: data.length }, + { Métrica: 'Valor Total', Valor: totalValor }, + ]; + const wsResumo = XLSX.utils.json_to_sheet(resumoData); + + // Adicionar abas ao workbook + XLSX.utils.book_append_sheet(wb, ws, 'Dados Analíticos'); + XLSX.utils.book_append_sheet(wb, wsResumo, 'Resumo'); + + // Gerar nome do arquivo com timestamp + const now = new Date(); + const timestamp = now.toISOString().slice(0, 19).replace(/:/g, '-'); + const fileName = `analitico_${timestamp}.xlsx`; + + // Fazer download + XLSX.writeFile(wb, fileName); +}; +``` + +--- + +### 3. **Componentes UI** (`src/components/ui/`) + +#### Button Component +```typescript +// src/components/ui/button.tsx +import { Slot } from '@radix-ui/react-slot'; +import { cva, type VariantProps } from 'class-variance-authority'; +import { cn } from '@/lib/utils'; + +const buttonVariants = cva( + 'inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50', + { + variants: { + variant: { + default: 'bg-primary text-primary-foreground hover:bg-primary/90', + destructive: 'bg-destructive text-destructive-foreground hover:bg-destructive/90', + outline: 'border border-input bg-background hover:bg-accent hover:text-accent-foreground', + secondary: 'bg-secondary text-secondary-foreground hover:bg-secondary/80', + ghost: 'hover:bg-accent hover:text-accent-foreground', + link: 'text-primary underline-offset-4 hover:underline', + }, + size: { + default: 'h-10 px-4 py-2', + sm: 'h-9 rounded-md px-3', + lg: 'h-11 rounded-md px-8', + icon: 'h-10 w-10', + }, + }, + defaultVariants: { + variant: 'default', + size: 'default', + }, + } +); + +export interface ButtonProps + extends React.ButtonHTMLAttributes, + VariantProps { + asChild?: boolean; +} + +const Button = React.forwardRef( + ({ className, variant, size, asChild = false, ...props }, ref) => { + const Comp = asChild ? Slot : 'button'; + return ( + + ); + } +); +Button.displayName = 'Button'; + +export { Button, buttonVariants }; +``` + +## Padrões de Design + +### 1. **Composition Pattern** +- Componentes pequenos e focados +- Props tipadas com TypeScript +- Reutilização através de composition + +### 2. **State Management** +- Estados locais com `useState` +- Callbacks com `useCallback` para performance +- Effects com `useEffect` para side effects + +### 3. **Styling** +- Tailwind CSS para styling +- Class variance authority para variantes +- Responsive design mobile-first + +### 4. **Type Safety** +- Interfaces TypeScript para props +- Tipos específicos para dados +- Validação de tipos em runtime + +## Utilitários + +### 1. **Formatação** +```typescript +const formatCurrency = (value: number) => { + return new Intl.NumberFormat('pt-BR', { + style: 'currency', + currency: 'BRL', + }).format(value); +}; + +const formatCurrencyWithColor = (value: number) => { + const formatted = formatCurrency(value); + const isNegative = value < 0; + return { formatted, isNegative }; +}; + +const formatDate = (dateString: string) => { + return new Date(dateString).toLocaleDateString('pt-BR'); +}; +``` + +### 2. **Extração de Códigos** +```typescript +const extractCodes = (grupo: string, subgrupo?: string) => { + const grupoMatch = grupo.match(/^(\d+)/); + const codigoGrupo = grupoMatch ? grupoMatch[1] : ''; + + let codigoSubgrupo = ''; + if (subgrupo) { + const subgrupoMatch = subgrupo.match(/^(\d+(?:\.\d+)+)/); + if (subgrupoMatch) { + codigoSubgrupo = subgrupoMatch[1]; + } else { + codigoSubgrupo = subgrupo; + } + } + + return { codigoGrupo, codigoSubgrupo }; +}; +``` + +### 3. **Cálculos** +```typescript +const calcularValoresPorMes = (items: DREItem[]): Record => { + const valoresPorMes: Record = {}; + + items.forEach((item) => { + const dataCompetencia = new Date(item.data_competencia); + const anoMes = `${dataCompetencia.getFullYear()}-${String( + dataCompetencia.getMonth() + 1 + ).padStart(2, '0')}`; + + if (!valoresPorMes[anoMes]) { + valoresPorMes[anoMes] = 0; + } + valoresPorMes[anoMes] += parseFloat(item.valor); + }); + + return valoresPorMes; +}; + +const calcularPercentuaisPorMes = ( + valoresPorMes: Record, + grupo: string +): Record => { + const percentuais: Record = {}; + + // Se for o grupo 03, retorna 100% para todos os meses + if (grupo.includes('03')) { + Object.keys(valoresPorMes).forEach((mes) => { + percentuais[mes] = 100; + }); + return percentuais; + } + + // Para outros grupos, calcular percentual baseado no grupo 03 + Object.keys(valoresPorMes).forEach((mes) => { + const valorAtual = valoresPorMes[mes]; + + // Encontrar o valor do grupo 03 para o mesmo mês + const grupo03Items = data.filter((item) => { + const dataCompetencia = new Date(item.data_competencia); + const anoMes = `${dataCompetencia.getFullYear()}-${String( + dataCompetencia.getMonth() + 1 + ).padStart(2, '0')}`; + return anoMes === mes && item.grupo.includes('03'); + }); + + const valorGrupo03 = grupo03Items.reduce( + (sum, item) => sum + parseFloat(item.valor), + 0 + ); + + if (valorGrupo03 !== 0) { + percentuais[mes] = (valorAtual / valorGrupo03) * 100; + } else { + percentuais[mes] = 0; + } + }); + + return percentuais; +}; +``` + +## Performance + +### 1. **Otimizações Implementadas** +- `useCallback` para funções de fetch +- `useMemo` para cálculos pesados (potencial) +- Renderização condicional + +### 2. **Estratégias de Renderização** +- Lazy loading de componentes +- Virtualização para listas grandes (potencial) +- Debounce para filtros (potencial) + +## Testes + +### 1. **Testes Unitários** +```typescript +// Exemplo de teste para componente +import { render, screen } from '@testing-library/react'; +import Teste from './teste'; + +describe('Teste Component', () => { + it('renders DRE title', () => { + render(); + expect(screen.getByText('DRE Gerencial')).toBeInTheDocument(); + }); +}); +``` + +### 2. **Testes de Integração** +```typescript +// Teste de interação com API +describe('DRE Integration', () => { + it('loads data from API', async () => { + render(); + + await waitFor(() => { + expect(screen.getByText('Carregando dados...')).toBeInTheDocument(); + }); + + // Verificar se dados foram carregados + }); +}); +``` + +## Próximos Passos + +1. **Implementar Context API** para estado global +2. **Adicionar React Query** para cache de dados +3. **Implementar Error Boundaries** robustos +4. **Adicionar testes unitários** e de integração +5. **Implementar lazy loading** de componentes +6. **Adicionar acessibilidade** (ARIA labels) +7. **Implementar temas** dark/light +8. **Adicionar animações** e transições diff --git a/docs/database.md b/docs/database.md new file mode 100644 index 0000000..ccf2a0a --- /dev/null +++ b/docs/database.md @@ -0,0 +1,264 @@ +# Banco de Dados - DRE Gerencial + +## Visão Geral + +O sistema utiliza PostgreSQL como banco de dados principal, com Drizzle ORM para type-safe database operations. A estrutura é baseada em views materializadas para performance otimizada. + +## Configuração do Banco + +### Variáveis de Ambiente +```env +POSTGRES_DB=dre_gerencial +POSTGRES_HOST=localhost +POSTGRES_PORT=5432 +POSTGRES_USER=postgres +POSTGRES_PASSWORD=sua_senha +``` + +### Conexão (src/db/index.ts) +```typescript +import 'dotenv/config'; +import { drizzle } from 'drizzle-orm/node-postgres'; +import { Pool } from 'pg'; +import * as schema from './schema'; + +const pool = new Pool({ + database: process.env.POSTGRES_DB, + host: process.env.POSTGRES_HOST, + port: Number(process.env.POSTGRES_PORT), + user: process.env.POSTGRES_USER, + password: process.env.POSTGRES_PASSWORD, +}); + +const db = drizzle({ + client: pool, + schema, +}); +``` + +## Schema do Banco + +### View Principal (src/db/schema.ts) +```typescript +export const view = pgView('view_dre_gerencial', { + codfilial: text(), + data_competencia: date(), + data_caixa: date(), + grupo: text(), + subgrupo: text(), + centro_custo: text(), + codigo_conta: integer(), + conta: text(), + valor: numeric(), +}); +``` + +### Estrutura da View +A view `view_dre_gerencial` consolida dados de múltiplas tabelas para fornecer uma estrutura hierárquica otimizada: + +| Campo | Tipo | Descrição | +|-------|------|-----------| +| `codfilial` | text | Código da filial | +| `data_competencia` | date | Data de competência do lançamento | +| `data_caixa` | date | Data de caixa | +| `grupo` | text | Descrição do grupo (ex: "01 - RECEITAS") | +| `subgrupo` | text | Descrição do subgrupo | +| `centro_custo` | text | Centro de custo | +| `codigo_conta` | integer | Código numérico da conta | +| `conta` | text | Descrição da conta | +| `valor` | numeric | Valor do lançamento | + +## Tabelas Base (Inferidas) + +### Tabela Principal: `fato_financeiro_analitico` +Baseada na API analítica, esta tabela contém os dados detalhados: + +| Campo | Tipo | Descrição | +|-------|------|-----------| +| `id` | integer | ID único | +| `codfilial` | text | Código da filial | +| `recnum` | integer | Número do registro | +| `data_competencia` | date | Data de competência | +| `data_vencimento` | date | Data de vencimento | +| `data_pagamento` | date | Data de pagamento | +| `data_caixa` | date | Data de caixa | +| `codigo_conta` | text | Código da conta | +| `conta` | text | Descrição da conta | +| `codigo_centrocusto` | text | Código do centro de custo | +| `codigo_fornecedor` | text | Código do fornecedor | +| `nome_fornecedor` | text | Nome do fornecedor | +| `valor` | numeric | Valor do lançamento | +| `historico` | text | Histórico principal | +| `historico2` | text | Histórico secundário | +| `created_at` | timestamp | Data de criação | +| `updated_at` | timestamp | Data de atualização | + +## Queries Principais + +### 1. **Dados DRE Gerencial** +```sql +SELECT * FROM view_dre_gerencial +``` +- **Uso**: Carregamento inicial da interface hierárquica +- **Performance**: Otimizada via view materializada + +### 2. **Dados Analíticos com Filtros** +```sql +SELECT + ffa.codigo_fornecedor, + ffa.nome_fornecedor, + ffa.id, + ffa.codfilial, + ffa.recnum, + ffa.data_competencia, + ffa.data_vencimento, + ffa.data_pagamento, + ffa.data_caixa, + ffa.codigo_conta, + ffa.conta, + ffa.codigo_centrocusto, + ffa.valor, + ffa.historico, + ffa.historico2, + ffa.created_at, + ffa.updated_at +FROM fato_financeiro_analitico AS ffa +WHERE to_char(ffa.data_competencia, 'YYYY-MM') BETWEEN $1 AND $2 + AND ffa.codigo_centrocusto = $3 -- Opcional + AND ffa.codigo_conta = $4 -- Opcional +``` + +### 3. **Query com Filtros de Grupo/Subgrupo** +```sql +SELECT ffa.* +FROM fato_financeiro_analitico AS ffa +WHERE EXISTS ( + SELECT 1 FROM public.view_dre_gerencial AS dre + WHERE ffa.codigo_conta = dre.codigo_conta::text + AND ffa.codigo_centrocusto = dre.centro_custo + AND to_char(ffa.data_competencia, 'YYYY-MM') = to_char(dre.data_competencia, 'YYYY-MM') + AND SUBSTRING(dre.grupo FROM '^\\s*(\\d+)\\s*\\.') = $1 + AND SUBSTRING(dre.subgrupo FROM '^\\s*(\\d+(?:\\.\\d+)+)\\s*-') = $2 +) +AND to_char(ffa.data_competencia, 'YYYY-MM') BETWEEN $3 AND $4 +``` + +## Índices Recomendados + +### Índices para Performance +```sql +-- Índice para filtros por data +CREATE INDEX idx_fato_financeiro_data_competencia +ON fato_financeiro_analitico (data_competencia); + +-- Índice para filtros por centro de custo +CREATE INDEX idx_fato_financeiro_centro_custo +ON fato_financeiro_analitico (codigo_centrocusto); + +-- Índice para filtros por conta +CREATE INDEX idx_fato_financeiro_conta +ON fato_financeiro_analitico (codigo_conta); + +-- Índice composto para queries analíticas +CREATE INDEX idx_fato_financeiro_analitico_composto +ON fato_financeiro_analitico (data_competencia, codigo_centrocusto, codigo_conta); +``` + +## Migrações e Versionamento + +### Drizzle Kit Configuration +```typescript +// drizzle.config.ts +export default defineConfig({ + out: './drizzle', + schema: './src/db/schema.ts', + dialect: 'postgresql', + dbCredentials: { + database: process.env.POSTGRES_DB || 'dre_gerencial', + host: process.env.POSTGRES_HOST || 'localhost', + port: Number(process.env.POSTGRES_PORT) || 5432, + user: process.env.POSTGRES_USER || 'postgres', + password: process.env.POSTGRES_PASSWORD || '', + }, +}); +``` + +### Comandos de Migração +```bash +# Gerar migração +npx drizzle-kit generate + +# Aplicar migração +npx drizzle-kit migrate + +# Visualizar schema +npx drizzle-kit studio +``` + +## Backup e Manutenção + +### Backup Automático +```bash +# Backup diário +pg_dump -h localhost -U postgres -d dre_gerencial > backup_$(date +%Y%m%d).sql + +# Restore +psql -h localhost -U postgres -d dre_gerencial < backup_20240101.sql +``` + +### Manutenção da View +```sql +-- Refresh da view materializada (se aplicável) +REFRESH MATERIALIZED VIEW view_dre_gerencial; + +-- Análise de performance +ANALYZE fato_financeiro_analitico; +ANALYZE view_dre_gerencial; +``` + +## Monitoramento + +### Queries de Monitoramento +```sql +-- Tamanho das tabelas +SELECT + schemaname, + tablename, + pg_size_pretty(pg_total_relation_size(schemaname||'.'||tablename)) as size +FROM pg_tables +WHERE schemaname = 'public' +ORDER BY pg_total_relation_size(schemaname||'.'||tablename) DESC; + +-- Queries lentas +SELECT query, mean_time, calls +FROM pg_stat_statements +ORDER BY mean_time DESC +LIMIT 10; +``` + +## Troubleshooting + +### Problemas Comuns + +1. **Conexão Recusada** + - Verificar se PostgreSQL está rodando + - Validar credenciais de conexão + - Verificar firewall/portas + +2. **Performance Lenta** + - Verificar índices existentes + - Analisar query execution plan + - Considerar particionamento por data + +3. **Dados Inconsistentes** + - Verificar refresh da view + - Validar integridade referencial + - Executar VACUUM ANALYZE + +## Próximos Passos + +1. **Implementar Cache Redis** para queries frequentes +2. **Adicionar Particionamento** por data para tabelas grandes +3. **Implementar Replicação** para alta disponibilidade +4. **Adicionar Monitoramento** de performance em tempo real +5. **Implementar Backup Automático** com retenção configurável diff --git a/docs/deployment.md b/docs/deployment.md new file mode 100644 index 0000000..67c8900 --- /dev/null +++ b/docs/deployment.md @@ -0,0 +1,580 @@ +# Deploy e Configuração - DRE Gerencial + +## Visão Geral + +Este guia cobre o processo completo de deploy e configuração do sistema DRE Gerencial em diferentes ambientes. + +## Pré-requisitos + +### 1. **Ambiente de Desenvolvimento** +- Node.js 18+ +- PostgreSQL 13+ +- npm ou yarn +- Git + +### 2. **Ambiente de Produção** +- Servidor Linux (Ubuntu 20.04+ recomendado) +- PostgreSQL 13+ +- Nginx (opcional, para proxy reverso) +- PM2 ou similar (para gerenciamento de processos) + +## Configuração do Ambiente + +### 1. **Variáveis de Ambiente** + +#### Desenvolvimento (`.env.local`) +```env +# Database +POSTGRES_DB=dre_gerencial +POSTGRES_HOST=localhost +POSTGRES_PORT=5432 +POSTGRES_USER=postgres +POSTGRES_PASSWORD=dev_password + +# Next.js +NEXT_PUBLIC_APP_URL=http://localhost:3000 +NODE_ENV=development +``` + +#### Produção (`.env.production`) +```env +# Database +POSTGRES_DB=dre_gerencial_prod +POSTGRES_HOST=prod-db-host +POSTGRES_PORT=5432 +POSTGRES_USER=prod_user +POSTGRES_PASSWORD=secure_prod_password + +# Next.js +NEXT_PUBLIC_APP_URL=https://dre-gerencial.com +NODE_ENV=production + +# Security +NEXTAUTH_SECRET=your-secret-key +NEXTAUTH_URL=https://dre-gerencial.com +``` + +### 2. **Configuração do Banco de Dados** + +#### Desenvolvimento +```bash +# Criar banco de desenvolvimento +createdb dre_gerencial + +# Conectar e verificar +psql -h localhost -U postgres -d dre_gerencial +``` + +#### Produção +```bash +# Criar usuário e banco de produção +sudo -u postgres psql +CREATE USER prod_user WITH PASSWORD 'secure_prod_password'; +CREATE DATABASE dre_gerencial_prod OWNER prod_user; +GRANT ALL PRIVILEGES ON DATABASE dre_gerencial_prod TO prod_user; +\q +``` + +## Deploy Local + +### 1. **Desenvolvimento** +```bash +# Instalar dependências +npm install + +# Executar migrações +npx drizzle-kit migrate + +# Iniciar servidor de desenvolvimento +npm run dev +``` + +### 2. **Build de Produção Local** +```bash +# Build otimizado +npm run build + +# Iniciar servidor de produção +npm run start +``` + +## Deploy em Servidor + +### 1. **Preparação do Servidor** + +#### Instalar Node.js +```bash +# Ubuntu/Debian +curl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E bash - +sudo apt-get install -y nodejs + +# Verificar instalação +node --version +npm --version +``` + +#### Instalar PostgreSQL +```bash +# Ubuntu/Debian +sudo apt update +sudo apt install postgresql postgresql-contrib + +# Iniciar serviço +sudo systemctl start postgresql +sudo systemctl enable postgresql +``` + +#### Instalar PM2 (Gerenciador de Processos) +```bash +# Instalar PM2 globalmente +sudo npm install -g pm2 + +# Configurar PM2 para iniciar com o sistema +pm2 startup +pm2 save +``` + +### 2. **Deploy da Aplicação** + +#### Clonar Repositório +```bash +# Criar diretório da aplicação +sudo mkdir -p /var/www/dre-gerencial +sudo chown $USER:$USER /var/www/dre-gerencial + +# Clonar repositório +cd /var/www/dre-gerencial +git clone . + +# Instalar dependências +npm install --production +``` + +#### Configurar Variáveis de Ambiente +```bash +# Criar arquivo de ambiente de produção +cp .env.example .env.production + +# Editar variáveis +nano .env.production +``` + +#### Build da Aplicação +```bash +# Build para produção +npm run build + +# Verificar se build foi bem-sucedido +ls -la .next/ +``` + +#### Configurar PM2 +```bash +# Criar arquivo de configuração PM2 +cat > ecosystem.config.js << EOF +module.exports = { + apps: [{ + name: 'dre-gerencial', + script: 'npm', + args: 'start', + cwd: '/var/www/dre-gerencial', + instances: 1, + autorestart: true, + watch: false, + max_memory_restart: '1G', + env: { + NODE_ENV: 'production', + PORT: 3000 + } + }] +}; +EOF + +# Iniciar aplicação +pm2 start ecosystem.config.js + +# Verificar status +pm2 status +pm2 logs dre-gerencial +``` + +### 3. **Configuração do Nginx (Opcional)** + +#### Instalar Nginx +```bash +sudo apt install nginx +sudo systemctl start nginx +sudo systemctl enable nginx +``` + +#### Configurar Proxy Reverso +```bash +# Criar configuração do site +sudo nano /etc/nginx/sites-available/dre-gerencial + +# Conteúdo do arquivo +server { + listen 80; + server_name dre-gerencial.com www.dre-gerencial.com; + + location / { + proxy_pass http://localhost:3000; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection 'upgrade'; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_cache_bypass $http_upgrade; + } +} + +# Habilitar site +sudo ln -s /etc/nginx/sites-available/dre-gerencial /etc/nginx/sites-enabled/ + +# Testar configuração +sudo nginx -t + +# Recarregar Nginx +sudo systemctl reload nginx +``` + +#### Configurar SSL com Let's Encrypt +```bash +# Instalar Certbot +sudo apt install certbot python3-certbot-nginx + +# Obter certificado SSL +sudo certbot --nginx -d dre-gerencial.com -d www.dre-gerencial.com + +# Verificar renovação automática +sudo certbot renew --dry-run +``` + +## Deploy com Docker + +### 1. **Dockerfile** +```dockerfile +# Dockerfile +FROM node:18-alpine AS base + +# Install dependencies only when needed +FROM base AS deps +RUN apk add --no-cache libc6-compat +WORKDIR /app + +# Install dependencies based on the preferred package manager +COPY package.json package-lock.json* ./ +RUN npm ci --only=production + +# Rebuild the source code only when needed +FROM base AS builder +WORKDIR /app +COPY --from=deps /app/node_modules ./node_modules +COPY . . + +# Build the application +RUN npm run build + +# Production image, copy all the files and run next +FROM base AS runner +WORKDIR /app + +ENV NODE_ENV production + +RUN addgroup --system --gid 1001 nodejs +RUN adduser --system --uid 1001 nextjs + +COPY --from=builder /app/public ./public + +# Set the correct permission for prerender cache +RUN mkdir .next +RUN chown nextjs:nodejs .next + +# Automatically leverage output traces to reduce image size +COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./ +COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static + +USER nextjs + +EXPOSE 3000 + +ENV PORT 3000 +ENV HOSTNAME "0.0.0.0" + +CMD ["node", "server.js"] +``` + +### 2. **Docker Compose** +```yaml +# docker-compose.yml +version: '3.8' + +services: + app: + build: . + ports: + - "3000:3000" + environment: + - NODE_ENV=production + - POSTGRES_DB=dre_gerencial + - POSTGRES_HOST=db + - POSTGRES_PORT=5432 + - POSTGRES_USER=postgres + - POSTGRES_PASSWORD=password + depends_on: + - db + restart: unless-stopped + + db: + image: postgres:13 + environment: + - POSTGRES_DB=dre_gerencial + - POSTGRES_USER=postgres + - POSTGRES_PASSWORD=password + volumes: + - postgres_data:/var/lib/postgresql/data + ports: + - "5432:5432" + restart: unless-stopped + +volumes: + postgres_data: +``` + +### 3. **Deploy com Docker** +```bash +# Build e executar +docker-compose up -d + +# Verificar logs +docker-compose logs -f app + +# Parar serviços +docker-compose down +``` + +## Deploy Automatizado + +### 1. **GitHub Actions** + +#### Workflow de Deploy +```yaml +# .github/workflows/deploy.yml +name: Deploy to Production + +on: + push: + branches: [main] + +jobs: + deploy: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + + - name: Setup Node.js + uses: actions/setup-node@v3 + with: + node-version: '18' + cache: 'npm' + + - name: Install dependencies + run: npm ci + + - name: Run tests + run: npm test + + - name: Build application + run: npm run build + + - name: Deploy to server + uses: appleboy/ssh-action@v0.1.5 + with: + host: ${{ secrets.HOST }} + username: ${{ secrets.USERNAME }} + key: ${{ secrets.SSH_KEY }} + script: | + cd /var/www/dre-gerencial + git pull origin main + npm ci --production + npm run build + pm2 restart dre-gerencial +``` + +### 2. **Configuração de Secrets** +No GitHub, adicionar os seguintes secrets: +- `HOST`: IP do servidor +- `USERNAME`: usuário do servidor +- `SSH_KEY`: chave SSH privada + +## Monitoramento + +### 1. **PM2 Monitoring** +```bash +# Monitorar aplicação +pm2 monit + +# Ver logs em tempo real +pm2 logs dre-gerencial --lines 100 + +# Reiniciar aplicação +pm2 restart dre-gerencial + +# Parar aplicação +pm2 stop dre-gerencial +``` + +### 2. **Logs do Sistema** +```bash +# Logs do Nginx +sudo tail -f /var/log/nginx/access.log +sudo tail -f /var/log/nginx/error.log + +# Logs do PostgreSQL +sudo tail -f /var/log/postgresql/postgresql-13-main.log +``` + +### 3. **Monitoramento de Recursos** +```bash +# Uso de CPU e memória +htop + +# Espaço em disco +df -h + +# Status dos serviços +systemctl status nginx +systemctl status postgresql +``` + +## Backup e Restore + +### 1. **Backup do Banco de Dados** +```bash +# Backup completo +pg_dump -h localhost -U postgres -d dre_gerencial_prod > backup_$(date +%Y%m%d).sql + +# Backup apenas dados +pg_dump -h localhost -U postgres -d dre_gerencial_prod --data-only > data_backup_$(date +%Y%m%d).sql + +# Backup apenas schema +pg_dump -h localhost -U postgres -d dre_gerencial_prod --schema-only > schema_backup_$(date +%Y%m%d).sql +``` + +### 2. **Restore do Banco de Dados** +```bash +# Restore completo +psql -h localhost -U postgres -d dre_gerencial_prod < backup_20240101.sql + +# Restore apenas dados +psql -h localhost -U postgres -d dre_gerencial_prod < data_backup_20240101.sql +``` + +### 3. **Backup Automático** +```bash +# Criar script de backup +cat > /home/user/backup_dre.sh << EOF +#!/bin/bash +DATE=$(date +%Y%m%d_%H%M%S) +BACKUP_DIR="/home/user/backups" +DB_NAME="dre_gerencial_prod" + +mkdir -p $BACKUP_DIR + +# Backup do banco +pg_dump -h localhost -U postgres -d $DB_NAME > $BACKUP_DIR/dre_backup_$DATE.sql + +# Manter apenas os últimos 7 backups +cd $BACKUP_DIR +ls -t dre_backup_*.sql | tail -n +8 | xargs -r rm + +echo "Backup completed: dre_backup_$DATE.sql" +EOF + +# Tornar executável +chmod +x /home/user/backup_dre.sh + +# Agendar backup diário +crontab -e +# Adicionar linha: +0 2 * * * /home/user/backup_dre.sh +``` + +## Troubleshooting + +### 1. **Problemas Comuns** + +#### Aplicação não inicia +```bash +# Verificar logs +pm2 logs dre-gerencial + +# Verificar se porta está em uso +netstat -tlnp | grep :3000 + +# Verificar variáveis de ambiente +pm2 env 0 +``` + +#### Erro de conexão com banco +```bash +# Verificar se PostgreSQL está rodando +sudo systemctl status postgresql + +# Testar conexão +psql -h localhost -U postgres -d dre_gerencial_prod + +# Verificar logs do PostgreSQL +sudo tail -f /var/log/postgresql/postgresql-13-main.log +``` + +#### Erro de permissões +```bash +# Verificar permissões do diretório +ls -la /var/www/dre-gerencial + +# Corrigir permissões +sudo chown -R $USER:$USER /var/www/dre-gerencial +chmod -R 755 /var/www/dre-gerencial +``` + +### 2. **Comandos Úteis** + +#### Reiniciar serviços +```bash +# Reiniciar aplicação +pm2 restart dre-gerencial + +# Reiniciar Nginx +sudo systemctl restart nginx + +# Reiniciar PostgreSQL +sudo systemctl restart postgresql +``` + +#### Verificar status +```bash +# Status da aplicação +pm2 status + +# Status dos serviços do sistema +sudo systemctl status nginx postgresql + +# Uso de recursos +free -h +df -h +``` + +## Próximos Passos + +1. **Implementar CI/CD** completo +2. **Adicionar monitoramento** com Prometheus/Grafana +3. **Implementar backup** automatizado +4. **Adicionar alertas** por email/Slack +5. **Implementar load balancing** para alta disponibilidade +6. **Adicionar CDN** para assets estáticos +7. **Implementar cache** com Redis +8. **Adicionar health checks** automatizados diff --git a/docs/development.md b/docs/development.md new file mode 100644 index 0000000..f0f3375 --- /dev/null +++ b/docs/development.md @@ -0,0 +1,529 @@ +# Guia de Desenvolvimento - DRE Gerencial + +## Configuração do Ambiente + +### 1. **Pré-requisitos** +- Node.js 18+ +- PostgreSQL 13+ +- npm ou yarn +- Git + +### 2. **Instalação** +```bash +# Clone o repositório +git clone +cd dre-modelo + +# Instale as dependências +npm install + +# Configure as variáveis de ambiente +cp .env.example .env.local +``` + +### 3. **Variáveis de Ambiente** +```env +# Database +POSTGRES_DB=dre_gerencial +POSTGRES_HOST=localhost +POSTGRES_PORT=5432 +POSTGRES_USER=postgres +POSTGRES_PASSWORD=sua_senha + +# Next.js +NEXT_PUBLIC_APP_URL=http://localhost:3000 +``` + +### 4. **Configuração do Banco** +```bash +# Criar banco de dados +createdb dre_gerencial + +# Executar migrações (se houver) +npx drizzle-kit migrate +``` + +## Scripts Disponíveis + +### 1. **Desenvolvimento** +```bash +# Iniciar servidor de desenvolvimento +npm run dev + +# Build para produção +npm run build + +# Iniciar servidor de produção +npm run start + +# Linting +npm run lint +``` + +### 2. **Banco de Dados** +```bash +# Gerar migração +npx drizzle-kit generate + +# Aplicar migração +npx drizzle-kit migrate + +# Visualizar schema +npx drizzle-kit studio +``` + +## Estrutura do Projeto + +``` +src/ +├── app/ # Next.js App Router +│ ├── api/ # API Routes +│ │ ├── analitico/ # API analítica +│ │ └── dre/ # API DRE +│ ├── DRE/ # Páginas DRE +│ │ ├── analitico.tsx # Componente analítico +│ │ ├── page.tsx # Página principal +│ │ └── teste.tsx # Componente principal +│ ├── globals.css # Estilos globais +│ └── layout.tsx # Layout raiz +├── components/ # Componentes reutilizáveis +│ └── ui/ # Componentes UI base +├── db/ # Configuração do banco +│ ├── index.ts # Conexão Drizzle +│ └── schema.ts # Schema do banco +└── lib/ # Utilitários + └── utils.ts # Funções utilitárias +``` + +## Padrões de Código + +### 1. **TypeScript** +- Sempre usar tipos explícitos +- Interfaces para props de componentes +- Tipos específicos para dados de API + +```typescript +// ✅ Bom +interface AnaliticoItem { + id: number; + valor: number; + data_competencia: string; +} + +// ❌ Evitar +const data: any = await response.json(); +``` + +### 2. **React Hooks** +- Usar `useCallback` para funções passadas como props +- Usar `useMemo` para cálculos pesados +- Evitar dependências desnecessárias em `useEffect` + +```typescript +// ✅ Bom +const fetchData = useCallback(async () => { + // lógica de fetch +}, [filtros]); + +// ❌ Evitar +const fetchData = async () => { + // lógica de fetch +}; +``` + +### 3. **Styling** +- Usar Tailwind CSS para styling +- Classes utilitárias para responsividade +- Variantes com class-variance-authority + +```typescript +// ✅ Bom +const buttonVariants = cva( + 'inline-flex items-center justify-center', + { + variants: { + variant: { + default: 'bg-primary text-primary-foreground', + outline: 'border border-input bg-background', + }, + }, + } +); + +// ❌ Evitar +const styles = { + button: 'bg-blue-500 text-white px-4 py-2', +}; +``` + +## Desenvolvimento de Novas Funcionalidades + +### 1. **Adicionando Nova API** + +#### Criar arquivo de rota +```typescript +// src/app/api/nova-funcionalidade/route.ts +import { NextRequest, NextResponse } from 'next/server'; +import db from '@/db'; + +export async function GET(request: NextRequest) { + try { + // Lógica da API + const data = await db.execute(sql`SELECT * FROM tabela`); + + return NextResponse.json(data.rows); + } catch (error) { + console.error('Erro:', error); + return NextResponse.json( + { error: 'Erro interno' }, + { status: 500 } + ); + } +} +``` + +#### Adicionar tipos +```typescript +// src/types/nova-funcionalidade.ts +export interface NovaFuncionalidadeItem { + id: number; + nome: string; + valor: number; +} +``` + +### 2. **Adicionando Novo Componente** + +#### Estrutura do componente +```typescript +// src/components/NovaFuncionalidade.tsx +'use client'; + +import { useState, useEffect } from 'react'; +import { Button } from '@/components/ui/button'; + +interface NovaFuncionalidadeProps { + filtros: { + dataInicio: string; + dataFim: string; + }; +} + +export default function NovaFuncionalidade({ filtros }: NovaFuncionalidadeProps) { + const [data, setData] = useState([]); + const [loading, setLoading] = useState(false); + + const fetchData = async () => { + setLoading(true); + try { + const response = await fetch(`/api/nova-funcionalidade?${new URLSearchParams(filtros)}`); + const result = await response.json(); + setData(result); + } catch (error) { + console.error('Erro:', error); + } finally { + setLoading(false); + } + }; + + useEffect(() => { + fetchData(); + }, [filtros]); + + return ( +
+

Nova Funcionalidade

+ + {loading ? ( +
Carregando...
+ ) : ( +
+ {/* Renderizar dados */} +
+ )} +
+ ); +} +``` + +### 3. **Adicionando Nova Página** + +#### Criar página +```typescript +// src/app/nova-pagina/page.tsx +import NovaFuncionalidade from '@/components/NovaFuncionalidade'; + +export default function NovaPagina() { + return ( +
+ +
+ ); +} +``` + +## Debugging + +### 1. **Logs de Desenvolvimento** +```typescript +// Usar console.log para debugging +console.log('Dados recebidos:', data); + +// Logs estruturados +console.log({ + timestamp: new Date().toISOString(), + component: 'AnaliticoComponent', + action: 'fetchData', + data: data.length +}); +``` + +### 2. **React Developer Tools** +- Instalar extensão do Chrome/Firefox +- Inspecionar estado dos componentes +- Profiler para performance + +### 3. **Network Tab** +- Verificar requisições de API +- Analisar tempo de resposta +- Verificar payloads + +## Testes + +### 1. **Configuração de Testes** +```bash +# Instalar dependências de teste +npm install --save-dev @testing-library/react @testing-library/jest-dom jest jest-environment-jsdom + +# Configurar Jest +# jest.config.js +const nextJest = require('next/jest'); + +const createJestConfig = nextJest({ + dir: './', +}); + +const customJestConfig = { + setupFilesAfterEnv: ['/jest.setup.js'], + moduleNameMapping: { + '^@/(.*)$': '/src/$1', + }, + testEnvironment: 'jest-environment-jsdom', +}; + +module.exports = createJestConfig(customJestConfig); +``` + +### 2. **Testes Unitários** +```typescript +// __tests__/components/Analitico.test.tsx +import { render, screen } from '@testing-library/react'; +import AnaliticoComponent from '@/app/DRE/analitico'; + +describe('AnaliticoComponent', () => { + it('renders without crashing', () => { + const filtros = { + dataInicio: '2024-01', + dataFim: '2024-12', + }; + + render(); + expect(screen.getByText('Análise Analítica')).toBeInTheDocument(); + }); +}); +``` + +### 3. **Testes de API** +```typescript +// __tests__/api/analitico.test.ts +import { GET } from '@/app/api/analitico/route'; + +describe('/api/analitico', () => { + it('returns data for valid parameters', async () => { + const request = new Request('http://localhost:3000/api/analitico?dataInicio=2024-01&dataFim=2024-12'); + const response = await GET(request); + const data = await response.json(); + + expect(response.status).toBe(200); + expect(Array.isArray(data)).toBe(true); + }); +}); +``` + +## Performance + +### 1. **Otimizações de Bundle** +```typescript +// Lazy loading de componentes +const AnaliticoComponent = lazy(() => import('./analitico')); + +// Dynamic imports +const HeavyComponent = dynamic(() => import('./HeavyComponent'), { + loading: () =>
Carregando...
, +}); +``` + +### 2. **Otimizações de Renderização** +```typescript +// Memoização de componentes +const MemoizedComponent = memo(({ data }) => { + return
{data.map(item => )}
; +}); + +// Memoização de cálculos +const expensiveValue = useMemo(() => { + return data.reduce((sum, item) => sum + item.valor, 0); +}, [data]); +``` + +### 3. **Otimizações de API** +```typescript +// Cache de dados +const { data, isLoading } = useQuery({ + queryKey: ['analitico', filtros], + queryFn: () => fetchAnaliticoData(filtros), + staleTime: 5 * 60 * 1000, // 5 minutos +}); +``` + +## Deploy + +### 1. **Build de Produção** +```bash +# Build otimizado +npm run build + +# Verificar build +npm run start +``` + +### 2. **Variáveis de Ambiente de Produção** +```env +# Produção +POSTGRES_DB=dre_gerencial_prod +POSTGRES_HOST=prod-db-host +POSTGRES_PORT=5432 +POSTGRES_USER=prod_user +POSTGRES_PASSWORD=prod_password + +NEXT_PUBLIC_APP_URL=https://dre-gerencial.com +``` + +### 3. **Docker (Opcional)** +```dockerfile +# Dockerfile +FROM node:18-alpine + +WORKDIR /app +COPY package*.json ./ +RUN npm ci --only=production + +COPY . . +RUN npm run build + +EXPOSE 3000 +CMD ["npm", "start"] +``` + +## Troubleshooting + +### 1. **Problemas Comuns** + +#### Erro de Conexão com Banco +```bash +# Verificar se PostgreSQL está rodando +pg_ctl status + +# Verificar conexão +psql -h localhost -U postgres -d dre_gerencial +``` + +#### Erro de Build +```bash +# Limpar cache +rm -rf .next node_modules +npm install +npm run build +``` + +#### Erro de TypeScript +```bash +# Verificar tipos +npx tsc --noEmit + +# Atualizar tipos +npm update @types/react @types/react-dom +``` + +### 2. **Logs de Erro** +```typescript +// Error boundary +class ErrorBoundary extends Component { + constructor(props) { + super(props); + this.state = { hasError: false }; + } + + static getDerivedStateFromError(error) { + return { hasError: true }; + } + + componentDidCatch(error, errorInfo) { + console.error('Error caught by boundary:', error, errorInfo); + } + + render() { + if (this.state.hasError) { + return
Algo deu errado.
; + } + + return this.props.children; + } +} +``` + +## Contribuição + +### 1. **Fluxo de Trabalho** +```bash +# Criar branch +git checkout -b feature/nova-funcionalidade + +# Fazer commits +git add . +git commit -m "feat: adiciona nova funcionalidade" + +# Push +git push origin feature/nova-funcionalidade + +# Criar Pull Request +``` + +### 2. **Padrões de Commit** +``` +feat: nova funcionalidade +fix: correção de bug +docs: atualização de documentação +style: formatação de código +refactor: refatoração de código +test: adição de testes +chore: tarefas de manutenção +``` + +### 3. **Code Review** +- Verificar tipos TypeScript +- Testar funcionalidades +- Validar performance +- Verificar acessibilidade +- Revisar documentação + +## Próximos Passos + +1. **Implementar CI/CD** com GitHub Actions +2. **Adicionar testes E2E** com Playwright +3. **Implementar monitoramento** com Sentry +4. **Adicionar Storybook** para componentes +5. **Implementar PWA** para mobile +6. **Adicionar internacionalização** (i18n) +7. **Implementar cache** com Redis +8. **Adicionar métricas** com Analytics diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md new file mode 100644 index 0000000..a3b3946 --- /dev/null +++ b/docs/troubleshooting.md @@ -0,0 +1,603 @@ +# Troubleshooting - DRE Gerencial + +## Visão Geral + +Este guia contém soluções para problemas comuns encontrados durante o desenvolvimento, deploy e manutenção do sistema DRE Gerencial. + +## Problemas de Desenvolvimento + +### 1. **Erros de TypeScript** + +#### Erro: "Cannot find module '@/components/ui/button'" +```bash +# Verificar se o arquivo existe +ls -la src/components/ui/button.tsx + +# Verificar tsconfig.json +cat tsconfig.json | grep paths + +# Solução: Verificar se o path alias está correto +{ + "compilerOptions": { + "paths": { + "@/*": ["./src/*"] + } + } +} +``` + +#### Erro: "Property 'valor' does not exist on type 'DREItem'" +```typescript +// Verificar interface +interface DREItem { + valor: string; // ou number + // outros campos... +} + +// Solução: Verificar se o tipo está correto na API +const valor = typeof item.valor === 'string' ? parseFloat(item.valor) : item.valor; +``` + +### 2. **Erros de Build** + +#### Erro: "Module not found: Can't resolve 'xlsx'" +```bash +# Instalar dependência +npm install xlsx +npm install --save-dev @types/xlsx + +# Verificar se está no package.json +cat package.json | grep xlsx +``` + +#### Erro: "Failed to compile" +```bash +# Limpar cache +rm -rf .next node_modules +npm install +npm run build + +# Verificar se há erros de TypeScript +npx tsc --noEmit +``` + +### 3. **Problemas de Performance** + +#### Componente renderizando muito +```typescript +// Solução: Usar useMemo para cálculos pesados +const expensiveValue = useMemo(() => { + return data.reduce((sum, item) => sum + item.valor, 0); +}, [data]); + +// Usar useCallback para funções +const handleClick = useCallback((id: string) => { + // lógica +}, [dependencies]); +``` + +#### Lista muito grande causando lag +```typescript +// Solução: Implementar virtualização +import { FixedSizeList as List } from 'react-window'; + +const VirtualizedList = ({ items }) => ( + + {({ index, style, data }) => ( +
+ {data[index].name} +
+ )} +
+); +``` + +## Problemas de Banco de Dados + +### 1. **Erros de Conexão** + +#### Erro: "Connection refused" +```bash +# Verificar se PostgreSQL está rodando +sudo systemctl status postgresql + +# Iniciar PostgreSQL +sudo systemctl start postgresql + +# Verificar porta +netstat -tlnp | grep 5432 +``` + +#### Erro: "Authentication failed" +```bash +# Verificar usuário e senha +psql -h localhost -U postgres -d dre_gerencial + +# Verificar pg_hba.conf +sudo nano /etc/postgresql/13/main/pg_hba.conf + +# Configuração recomendada +local all postgres peer +host all all 127.0.0.1/32 md5 +``` + +### 2. **Erros de Query** + +#### Erro: "relation 'view_dre_gerencial' does not exist" +```sql +-- Verificar se a view existe +\dv view_dre_gerencial + +-- Criar view se não existir +CREATE VIEW view_dre_gerencial AS +SELECT + codfilial, + data_competencia, + data_caixa, + grupo, + subgrupo, + centro_custo, + codigo_conta, + conta, + valor +FROM fato_financeiro_analitico; +``` + +#### Erro: "column 'valor' does not exist" +```sql +-- Verificar estrutura da tabela +\d fato_financeiro_analitico + +-- Verificar se a coluna existe +SELECT column_name, data_type +FROM information_schema.columns +WHERE table_name = 'fato_financeiro_analitico'; +``` + +### 3. **Problemas de Performance** + +#### Query muito lenta +```sql +-- Verificar plano de execução +EXPLAIN ANALYZE SELECT * FROM fato_financeiro_analitico +WHERE data_competencia BETWEEN '2024-01-01' AND '2024-12-31'; + +-- Criar índices necessários +CREATE INDEX idx_fato_financeiro_data_competencia +ON fato_financeiro_analitico (data_competencia); + +CREATE INDEX idx_fato_financeiro_centro_custo +ON fato_financeiro_analitico (codigo_centrocusto); +``` + +#### Timeout de conexão +```typescript +// Aumentar timeout no pool de conexões +const pool = new Pool({ + database: process.env.POSTGRES_DB, + host: process.env.POSTGRES_HOST, + port: Number(process.env.POSTGRES_PORT), + user: process.env.POSTGRES_USER, + password: process.env.POSTGRES_PASSWORD, + connectionTimeoutMillis: 10000, + idleTimeoutMillis: 30000, + max: 20, +}); +``` + +## Problemas de API + +### 1. **Erros 404** + +#### Rota não encontrada +```typescript +// Verificar se o arquivo de rota existe +ls -la src/app/api/analitico/route.ts + +// Verificar se a função está exportada +export async function GET(request: NextRequest) { + // implementação +} +``` + +#### Parâmetros obrigatórios não fornecidos +```typescript +// Verificar validação de parâmetros +if (!dataInicio || !dataFim) { + return NextResponse.json( + { message: 'Parâmetros obrigatórios: dataInicio, dataFim' }, + { status: 400 } + ); +} +``` + +### 2. **Erros 500** + +#### Erro interno do servidor +```typescript +// Adicionar logs detalhados +try { + const data = await db.execute(query); + return NextResponse.json(data.rows); +} catch (error) { + console.error('Erro detalhado:', { + message: error.message, + stack: error.stack, + query: query.toString(), + }); + + return NextResponse.json( + { error: 'Erro interno do servidor' }, + { status: 500 } + ); +} +``` + +#### Erro de memória +```bash +# Verificar uso de memória +free -h + +# Aumentar limite de memória do Node.js +export NODE_OPTIONS="--max-old-space-size=4096" +npm run dev +``` + +### 3. **Problemas de CORS** + +#### Erro: "Access to fetch at '...' from origin '...' has been blocked by CORS policy" +```typescript +// Adicionar headers CORS +export async function GET(request: NextRequest) { + const response = NextResponse.json(data); + + response.headers.set('Access-Control-Allow-Origin', '*'); + response.headers.set('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE'); + response.headers.set('Access-Control-Allow-Headers', 'Content-Type'); + + return response; +} +``` + +## Problemas de Deploy + +### 1. **Erros de Build em Produção** + +#### Erro: "Module not found" +```bash +# Verificar se todas as dependências estão instaladas +npm ci --production + +# Verificar se não há dependências de desenvolvimento em produção +npm list --production +``` + +#### Erro: "Out of memory" +```bash +# Aumentar memória para build +export NODE_OPTIONS="--max-old-space-size=4096" +npm run build +``` + +### 2. **Problemas de PM2** + +#### Aplicação não inicia +```bash +# Verificar logs +pm2 logs dre-gerencial + +# Verificar configuração +pm2 show dre-gerencial + +# Reiniciar aplicação +pm2 restart dre-gerencial +``` + +#### Aplicação reinicia constantemente +```bash +# Verificar uso de memória +pm2 monit + +# Ajustar limite de memória +pm2 start ecosystem.config.js --max-memory-restart 1G +``` + +### 3. **Problemas de Nginx** + +#### Erro: "502 Bad Gateway" +```bash +# Verificar se a aplicação está rodando +pm2 status + +# Verificar logs do Nginx +sudo tail -f /var/log/nginx/error.log + +# Testar configuração +sudo nginx -t +``` + +#### Erro: "Connection refused" +```bash +# Verificar se a aplicação está escutando na porta correta +netstat -tlnp | grep 3000 + +# Verificar configuração do proxy +sudo nano /etc/nginx/sites-available/dre-gerencial +``` + +## Problemas de Dados + +### 1. **Dados não aparecem** + +#### Verificar se há dados no banco +```sql +-- Verificar se há dados na tabela +SELECT COUNT(*) FROM fato_financeiro_analitico; + +-- Verificar se há dados na view +SELECT COUNT(*) FROM view_dre_gerencial; + +-- Verificar dados por período +SELECT COUNT(*) FROM fato_financeiro_analitico +WHERE data_competencia BETWEEN '2024-01-01' AND '2024-12-31'; +``` + +#### Verificar filtros aplicados +```typescript +// Adicionar logs para debug +console.log('Filtros aplicados:', filtros); +console.log('Query executada:', query.toString()); +console.log('Resultado:', data.length); +``` + +### 2. **Dados incorretos** + +#### Verificar cálculos +```typescript +// Verificar se os cálculos estão corretos +const totalValor = data.reduce((sum, item) => { + const valor = typeof item.valor === 'string' ? parseFloat(item.valor) : item.valor; + return sum + (isNaN(valor) ? 0 : valor); +}, 0); + +console.log('Total calculado:', totalValor); +``` + +#### Verificar formatação de datas +```typescript +// Verificar se as datas estão sendo formatadas corretamente +const formatDate = (dateString: string) => { + try { + return new Date(dateString).toLocaleDateString('pt-BR'); + } catch (error) { + console.error('Erro ao formatar data:', dateString, error); + return 'Data inválida'; + } +}; +``` + +### 3. **Performance de Dados** + +#### Query muito lenta +```sql +-- Verificar plano de execução +EXPLAIN ANALYZE SELECT * FROM fato_financeiro_analitico +WHERE data_competencia BETWEEN '2024-01-01' AND '2024-12-31' +AND codigo_centrocusto = '001'; + +-- Criar índices compostos +CREATE INDEX idx_fato_financeiro_composto +ON fato_financeiro_analitico (data_competencia, codigo_centrocusto); +``` + +#### Muitos dados carregando +```typescript +// Implementar paginação +const ITEMS_PER_PAGE = 100; +const [currentPage, setCurrentPage] = useState(1); + +const paginatedData = data.slice( + (currentPage - 1) * ITEMS_PER_PAGE, + currentPage * ITEMS_PER_PAGE +); +``` + +## Problemas de Interface + +### 1. **Componentes não renderizam** + +#### Verificar se o componente está sendo importado corretamente +```typescript +// Verificar import +import AnaliticoComponent from './analitico'; + +// Verificar se está sendo usado +{!loading && data.length > 0 && ( + +)} +``` + +#### Verificar se há erros no console +```typescript +// Adicionar error boundary +class ErrorBoundary extends Component { + constructor(props) { + super(props); + this.state = { hasError: false }; + } + + static getDerivedStateFromError(error) { + return { hasError: true }; + } + + componentDidCatch(error, errorInfo) { + console.error('Erro no componente:', error, errorInfo); + } + + render() { + if (this.state.hasError) { + return
Erro ao carregar componente
; + } + + return this.props.children; + } +} +``` + +### 2. **Problemas de Styling** + +#### Classes Tailwind não aplicadas +```bash +# Verificar se Tailwind está configurado +cat tailwind.config.js + +# Verificar se as classes estão sendo incluídas +npm run build +``` + +#### Componentes não responsivos +```typescript +// Verificar classes responsivas +
+ {/* conteúdo */} +
+``` + +### 3. **Problemas de Interação** + +#### Cliques não funcionam +```typescript +// Verificar se o evento está sendo capturado +const handleClick = (event: React.MouseEvent) => { + event.preventDefault(); + event.stopPropagation(); + + console.log('Clique capturado'); + // lógica +}; + +// Verificar se o elemento está clicável + +``` + +#### Estados não atualizam +```typescript +// Verificar se o estado está sendo atualizado corretamente +const [data, setData] = useState([]); + +const updateData = (newData) => { + console.log('Atualizando dados:', newData); + setData(newData); +}; + +// Verificar se o useEffect está sendo executado +useEffect(() => { + console.log('useEffect executado'); + fetchData(); +}, [dependencies]); +``` + +## Comandos Úteis para Debug + +### 1. **Verificar Status do Sistema** +```bash +# Status dos serviços +sudo systemctl status nginx postgresql + +# Uso de recursos +htop +free -h +df -h + +# Logs do sistema +sudo journalctl -f +``` + +### 2. **Verificar Aplicação** +```bash +# Status da aplicação +pm2 status +pm2 logs dre-gerencial + +# Verificar processos +ps aux | grep node + +# Verificar portas +netstat -tlnp | grep :3000 +``` + +### 3. **Verificar Banco de Dados** +```bash +# Conectar ao banco +psql -h localhost -U postgres -d dre_gerencial + +# Verificar conexões ativas +SELECT * FROM pg_stat_activity; + +# Verificar tamanho do banco +SELECT pg_size_pretty(pg_database_size('dre_gerencial')); +``` + +## Logs e Monitoramento + +### 1. **Configurar Logs Detalhados** +```typescript +// Adicionar logs estruturados +const logger = { + info: (message: string, data?: any) => { + console.log({ + timestamp: new Date().toISOString(), + level: 'INFO', + message, + data, + }); + }, + error: (message: string, error?: any) => { + console.error({ + timestamp: new Date().toISOString(), + level: 'ERROR', + message, + error: error?.message || error, + stack: error?.stack, + }); + }, +}; +``` + +### 2. **Monitoramento de Performance** +```typescript +// Adicionar métricas de performance +const performanceMonitor = { + start: (label: string) => { + performance.mark(`${label}-start`); + }, + end: (label: string) => { + performance.mark(`${label}-end`); + performance.measure(label, `${label}-start`, `${label}-end`); + + const measure = performance.getEntriesByName(label)[0]; + console.log(`${label}: ${measure.duration}ms`); + }, +}; +``` + +## Próximos Passos + +1. **Implementar sistema de logs** centralizado +2. **Adicionar monitoramento** em tempo real +3. **Implementar alertas** automáticos +4. **Criar dashboard** de saúde do sistema +5. **Implementar backup** automatizado +6. **Adicionar testes** de carga +7. **Implementar rollback** automático +8. **Criar documentação** de runbooks diff --git a/package-lock.json b/package-lock.json index 786348b..5d3a6f3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,7 +8,11 @@ "name": "dre-gerencial", "version": "0.1.0", "dependencies": { + "@radix-ui/react-dialog": "^1.1.15", + "@radix-ui/react-select": "^2.2.6", "@radix-ui/react-slot": "^1.2.3", + "@tanstack/react-table": "^8.21.3", + "@tanstack/react-virtual": "^3.13.12", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "dotenv": "^17.2.3", @@ -1113,6 +1117,44 @@ "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, + "node_modules/@floating-ui/core": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.3.tgz", + "integrity": "sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w==", + "license": "MIT", + "dependencies": { + "@floating-ui/utils": "^0.2.10" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.4.tgz", + "integrity": "sha512-OOchDgh4F2CchOX94cRVqhvy7b3AFb+/rQXyswmzmGakRfkMgoWVjfnLWkRirfLEfuD4ysVW16eXzwt3jHIzKA==", + "license": "MIT", + "dependencies": { + "@floating-ui/core": "^1.7.3", + "@floating-ui/utils": "^0.2.10" + } + }, + "node_modules/@floating-ui/react-dom": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.6.tgz", + "integrity": "sha512-4JX6rEatQEvlmgU80wZyq9RT96HZJa88q8hp0pBd+LrczeDI4o6uA2M+uvxngVHo4Ihr8uibXxH6+70zhAFrVw==", + "license": "MIT", + "dependencies": { + "@floating-ui/dom": "^1.7.4" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.10", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.10.tgz", + "integrity": "sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==", + "license": "MIT" + }, "node_modules/@humanfs/core": { "version": "0.19.1", "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", @@ -1861,6 +1903,67 @@ "node": ">=12.4.0" } }, + "node_modules/@radix-ui/number": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/number/-/number-1.1.1.tgz", + "integrity": "sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g==", + "license": "MIT" + }, + "node_modules/@radix-ui/primitive": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.3.tgz", + "integrity": "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==", + "license": "MIT" + }, + "node_modules/@radix-ui/react-arrow": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.7.tgz", + "integrity": "sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-collection": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.7.tgz", + "integrity": "sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-compose-refs": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz", @@ -1876,6 +1979,303 @@ } } }, + "node_modules/@radix-ui/react-context": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.2.tgz", + "integrity": "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dialog": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.1.15.tgz", + "integrity": "sha512-TCglVRtzlffRNxRMEyR36DGBLJpeusFcgMVD9PZEzAKnUs1lKCgX5u9BmC2Yg+LL9MgZDugFFs1Vl+Jp4t/PGw==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-dismissable-layer": "1.1.11", + "@radix-ui/react-focus-guards": "1.1.3", + "@radix-ui/react-focus-scope": "1.1.7", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-portal": "1.1.9", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-slot": "1.2.3", + "@radix-ui/react-use-controllable-state": "1.2.2", + "aria-hidden": "^1.2.4", + "react-remove-scroll": "^2.6.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-direction": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.1.1.tgz", + "integrity": "sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dismissable-layer": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.11.tgz", + "integrity": "sha512-Nqcp+t5cTB8BinFkZgXiMJniQH0PsUt2k51FUhbdfeKvc4ACcG2uQniY/8+h1Yv6Kza4Q7lD7PQV0z0oicE0Mg==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-escape-keydown": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-focus-guards": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.3.tgz", + "integrity": "sha512-0rFg/Rj2Q62NCm62jZw0QX7a3sz6QCQU0LpZdNrJX8byRGaGVTqbrW9jAoIAHyMQqsNpeZ81YgSizOt5WXq0Pw==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-focus-scope": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.7.tgz", + "integrity": "sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-id": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.1.tgz", + "integrity": "sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-popper": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.8.tgz", + "integrity": "sha512-0NJQ4LFFUuWkE7Oxf0htBKS6zLkkjBH+hM1uk7Ng705ReR8m/uelduy1DBo0PyBXPKVnBA6YBlU94MBGXrSBCw==", + "license": "MIT", + "dependencies": { + "@floating-ui/react-dom": "^2.0.0", + "@radix-ui/react-arrow": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-layout-effect": "1.1.1", + "@radix-ui/react-use-rect": "1.1.1", + "@radix-ui/react-use-size": "1.1.1", + "@radix-ui/rect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-portal": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.9.tgz", + "integrity": "sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-presence": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.5.tgz", + "integrity": "sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", + "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-select": { + "version": "2.2.6", + "resolved": "https://registry.npmjs.org/@radix-ui/react-select/-/react-select-2.2.6.tgz", + "integrity": "sha512-I30RydO+bnn2PQztvo25tswPH+wFBjehVGtmagkU78yMdwTwVf12wnAOF+AeP8S2N8xD+5UPbGhkUfPyvT+mwQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/number": "1.1.1", + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-dismissable-layer": "1.1.11", + "@radix-ui/react-focus-guards": "1.1.3", + "@radix-ui/react-focus-scope": "1.1.7", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-popper": "1.2.8", + "@radix-ui/react-portal": "1.1.9", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-slot": "1.2.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-layout-effect": "1.1.1", + "@radix-ui/react-use-previous": "1.1.1", + "@radix-ui/react-visually-hidden": "1.2.3", + "aria-hidden": "^1.2.4", + "react-remove-scroll": "^2.6.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-slot": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", @@ -1894,6 +2294,171 @@ } } }, + "node_modules/@radix-ui/react-use-callback-ref": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.1.tgz", + "integrity": "sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-controllable-state": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.2.2.tgz", + "integrity": "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-effect-event": "0.0.2", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-effect-event": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-effect-event/-/react-use-effect-event-0.0.2.tgz", + "integrity": "sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-escape-keydown": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.1.1.tgz", + "integrity": "sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-callback-ref": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-layout-effect": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.1.tgz", + "integrity": "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-previous": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-previous/-/react-use-previous-1.1.1.tgz", + "integrity": "sha512-2dHfToCj/pzca2Ck724OZ5L0EVrr3eHRNsG/b3xQJLA2hZpVCS99bLAX+hm1IHXDEnzU6by5z/5MIY794/a8NQ==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-rect": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-rect/-/react-use-rect-1.1.1.tgz", + "integrity": "sha512-QTYuDesS0VtuHNNvMh+CjlKJ4LJickCMUAqjlE3+j8w+RlRpwyX3apEQKGFzbZGdo7XNG1tXa+bQqIE7HIXT2w==", + "license": "MIT", + "dependencies": { + "@radix-ui/rect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-size": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-size/-/react-use-size-1.1.1.tgz", + "integrity": "sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-visually-hidden": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.2.3.tgz", + "integrity": "sha512-pzJq12tEaaIhqjbzpCuv/OypJY/BPavOofm+dbab+MHLajy277+1lLm6JFcGgF5eskJ6mquGirhXY2GD/8u8Ug==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/rect": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/rect/-/rect-1.1.1.tgz", + "integrity": "sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==", + "license": "MIT" + }, "node_modules/@rtsao/scc": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz", @@ -2193,6 +2758,66 @@ "tailwindcss": "4.1.14" } }, + "node_modules/@tanstack/react-table": { + "version": "8.21.3", + "resolved": "https://registry.npmjs.org/@tanstack/react-table/-/react-table-8.21.3.tgz", + "integrity": "sha512-5nNMTSETP4ykGegmVkhjcS8tTLW6Vl4axfEGQN3v0zdHYbK4UfoqfPChclTrJ4EoK9QynqAu9oUf8VEmrpZ5Ww==", + "license": "MIT", + "dependencies": { + "@tanstack/table-core": "8.21.3" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": ">=16.8", + "react-dom": ">=16.8" + } + }, + "node_modules/@tanstack/react-virtual": { + "version": "3.13.12", + "resolved": "https://registry.npmjs.org/@tanstack/react-virtual/-/react-virtual-3.13.12.tgz", + "integrity": "sha512-Gd13QdxPSukP8ZrkbgS2RwoZseTTbQPLnQEn7HY/rqtM+8Zt95f7xKC7N0EsKs7aoz0WzZ+fditZux+F8EzYxA==", + "license": "MIT", + "dependencies": { + "@tanstack/virtual-core": "3.13.12" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/@tanstack/table-core": { + "version": "8.21.3", + "resolved": "https://registry.npmjs.org/@tanstack/table-core/-/table-core-8.21.3.tgz", + "integrity": "sha512-ldZXEhOBb8Is7xLs01fR3YEc3DERiz5silj8tnGkFZytt1abEvl/GhUmCE0PMLaMPTa3Jk4HbKmRlHmu+gCftg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tanstack/virtual-core": { + "version": "3.13.12", + "resolved": "https://registry.npmjs.org/@tanstack/virtual-core/-/virtual-core-3.13.12.tgz", + "integrity": "sha512-1YBOJfRHV4sXUmWsFSf5rQor4Ss82G8dQWLRbnk3GA4jeP8hQt1hxXh0tmflpC0dz3VgEv/1+qwPyLeWkQuPFA==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, "node_modules/@tybys/wasm-util": { "version": "0.10.1", "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz", @@ -2261,7 +2886,7 @@ "version": "19.2.1", "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.1.tgz", "integrity": "sha512-/EEvYBdT3BflCWvTMO7YkYBHVE9Ci6XdqZciZANQgKpaiDRGOLIlRo91jbTNRQjgPFWVaRxcYc0luVNFitz57A==", - "dev": true, + "devOptional": true, "license": "MIT", "peerDependencies": { "@types/react": "^19.2.0" @@ -2903,6 +3528,18 @@ "dev": true, "license": "Python-2.0" }, + "node_modules/aria-hidden": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.6.tgz", + "integrity": "sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/aria-query": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.2.tgz", @@ -3513,6 +4150,12 @@ "node": ">=8" } }, + "node_modules/detect-node-es": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz", + "integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==", + "license": "MIT" + }, "node_modules/doctrine": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", @@ -4627,6 +5270,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/get-nonce": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz", + "integrity": "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/get-proto": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", @@ -6446,6 +7098,75 @@ "dev": true, "license": "MIT" }, + "node_modules/react-remove-scroll": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.7.1.tgz", + "integrity": "sha512-HpMh8+oahmIdOuS5aFKKY6Pyog+FNaZV/XyJOq7b4YFwsFHe5yYfdbIalI4k3vU2nSDql7YskmUseHsRrJqIPA==", + "license": "MIT", + "dependencies": { + "react-remove-scroll-bar": "^2.3.7", + "react-style-singleton": "^2.2.3", + "tslib": "^2.1.0", + "use-callback-ref": "^1.3.3", + "use-sidecar": "^1.1.3" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-remove-scroll-bar": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.8.tgz", + "integrity": "sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==", + "license": "MIT", + "dependencies": { + "react-style-singleton": "^2.2.2", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-style-singleton": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.3.tgz", + "integrity": "sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==", + "license": "MIT", + "dependencies": { + "get-nonce": "^1.0.0", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/reflect.getprototypeof": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz", @@ -7435,6 +8156,49 @@ "punycode": "^2.1.0" } }, + "node_modules/use-callback-ref": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.3.3.tgz", + "integrity": "sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/use-sidecar": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.3.tgz", + "integrity": "sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==", + "license": "MIT", + "dependencies": { + "detect-node-es": "^1.1.0", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", diff --git a/package.json b/package.json index db51c58..aec9ed6 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,11 @@ "lint": "eslint" }, "dependencies": { + "@radix-ui/react-dialog": "^1.1.15", + "@radix-ui/react-select": "^2.2.6", "@radix-ui/react-slot": "^1.2.3", + "@tanstack/react-table": "^8.21.3", + "@tanstack/react-virtual": "^3.13.12", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "dotenv": "^17.2.3", diff --git a/src/app/DRE/analitico.tsx b/src/app/DRE/analitico.tsx index 2b0a841..157458c 100644 --- a/src/app/DRE/analitico.tsx +++ b/src/app/DRE/analitico.tsx @@ -1,8 +1,32 @@ 'use client'; -import { Button } from '@/components/ui/button'; -import { ArrowDown, ArrowUp, ArrowUpDown, Download } from 'lucide-react'; -import { useCallback, useEffect, useState } from 'react'; +import * as React from "react"; +import { + useReactTable, + 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 { + Dialog, + DialogContent, + DialogHeader, + DialogTitle, + DialogFooter, +} from "@/components/ui/dialog"; +import { + Select, + SelectTrigger, + SelectValue, + SelectContent, + SelectItem, +} from "@/components/ui/select"; +import { ChevronUp, ChevronDown, Download } from "lucide-react"; import * as XLSX from 'xlsx'; interface AnaliticoItem { @@ -27,26 +51,6 @@ interface AnaliticoItem { updated_at: string; } -type SortField = - | 'data_competencia' - | 'data_vencimento' - | 'data_caixa' - | 'codigo_fornecedor' - | 'nome_fornecedor' - | 'codigo_centrocusto' - | 'codigo_conta' - | 'conta' - | 'valor' - | 'historico' - | 'historico2' - | 'recnum'; -type SortDirection = 'asc' | 'desc'; - -interface SortConfig { - field: SortField; - direction: SortDirection; -} - interface AnaliticoProps { filtros: { dataInicio: string; @@ -59,14 +63,15 @@ interface AnaliticoProps { } export default function AnaliticoComponent({ filtros }: AnaliticoProps) { - const [data, setData] = useState([]); - const [loading, setLoading] = useState(false); - const [sortConfig, setSortConfig] = useState({ - field: 'data_competencia', - direction: 'desc', - }); + const [data, setData] = React.useState([]); + const [loading, setLoading] = React.useState(false); + const [globalFilter, setGlobalFilter] = React.useState(""); + 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 = useCallback(async () => { + const fetchData = React.useCallback(async () => { // Só faz a requisição se tiver dataInicio e dataFim if (!filtros.dataInicio || !filtros.dataFim) { setData([]); @@ -100,61 +105,139 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { } }, [filtros]); - useEffect(() => { + React.useEffect(() => { fetchData(); }, [fetchData]); - const handleSort = (field: SortField) => { - setSortConfig((prev) => ({ - field, - direction: - prev.field === field && prev.direction === 'asc' ? 'desc' : 'asc', - })); - }; + const columns = React.useMemo( + () => [ + { + accessorKey: "data_competencia", + header: "Data Comp.", + cell: ({ getValue }: any) => { + const value = getValue(); + return new Date(value).toLocaleDateString('pt-BR'); + } + }, + { + accessorKey: "data_vencimento", + header: "Data Venc.", + cell: ({ getValue }: any) => { + const value = getValue(); + return new Date(value).toLocaleDateString('pt-BR'); + } + }, + { + accessorKey: "data_caixa", + header: "Data Caixa", + cell: ({ getValue }: any) => { + const value = getValue(); + return new Date(value).toLocaleDateString('pt-BR'); + } + }, + { accessorKey: "codigo_fornecedor", header: "Cód. Fornec." }, + { accessorKey: "nome_fornecedor", header: "Fornecedor" }, + { accessorKey: "codigo_centrocusto", header: "Cód. Centro" }, + { accessorKey: "codigo_conta", header: "Cód. Conta" }, + { accessorKey: "conta", header: "Conta" }, + { + accessorKey: "valor", + header: "Valor", + cell: ({ getValue }: any) => { + const value = getValue(); + const formatted = new Intl.NumberFormat('pt-BR', { + style: 'currency', + currency: 'BRL', + }).format(value); + const isNegative = value < 0; + return ( + + {formatted} + + ); + } + }, + { accessorKey: "historico", header: "Histórico" }, + { accessorKey: "historico2", header: "Histórico 2" }, + { accessorKey: "recnum", header: "Recnum" }, + ], + [] + ); - const getSortIcon = (field: SortField) => { - if (sortConfig.field !== field) { - return ; - } - return sortConfig.direction === 'asc' ? ( - - ) : ( - - ); - }; + const filterFns = React.useMemo( + () => ({ + advancedText: (row: any, columnId: string, filter: any) => { + if (!filter) return true; + const raw = row.getValue(columnId); + const v = raw == null ? "" : String(raw); + const op = filter.operator; + const q = (filter.value ?? "").toString(); + const a = v.toLowerCase(); + const b = q.toLowerCase(); + switch (op) { + case "contains": + return a.includes(b); + case "equals": + return a === b; + case "startsWith": + return a.startsWith(b); + case "endsWith": + return a.endsWith(b); + case "empty": + return a.length === 0; + case "notEmpty": + return a.length > 0; + default: + return true; + } + }, + }), + [] + ); - const sortedData = [...data].sort((a, b) => { - const aValue = a[sortConfig.field]; - const bValue = b[sortConfig.field]; - - if (typeof aValue === 'string' && typeof bValue === 'string') { - return sortConfig.direction === 'asc' - ? aValue.localeCompare(bValue) - : bValue.localeCompare(aValue); - } - - if (typeof aValue === 'number' && typeof bValue === 'number') { - return sortConfig.direction === 'asc' ? aValue - bValue : bValue - aValue; - } - - return 0; + const table = useReactTable({ + data, + columns, + state: { globalFilter, columnFilters }, + onGlobalFilterChange: setGlobalFilter, + onColumnFiltersChange: setColumnFilters, + filterFns, + getCoreRowModel: getCoreRowModel(), + getFilteredRowModel: getFilteredRowModel(), + getSortedRowModel: getSortedRowModel(), }); - const formatCurrency = (value: number) => { - return new Intl.NumberFormat('pt-BR', { - style: 'currency', - currency: 'BRL', - }).format(value); + const parentRef = React.useRef(null); + const rowVirtualizer = useVirtualizer({ + count: table.getRowModel().rows.length, + getScrollElement: () => parentRef.current, + estimateSize: () => 36, + overscan: 20, + }); + + 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 = () => { + const filters = conditions + .filter((c) => c.column && (c.operator === "empty" || c.operator === "notEmpty" || (c.value ?? "") !== "")) + .map((c) => ({ id: c.column, value: { operator: c.operator, value: c.value } })); + setColumnFilters(filters); + setOpen(false); }; - const formatCurrencyWithColor = (value: number) => { - const formatted = formatCurrency(value); - const isNegative = value < 0; - return { formatted, isNegative }; - }; - - const formatDate = (dateString: string) => { - return new Date(dateString).toLocaleDateString('pt-BR'); + const clearFilters = () => { + setConditions([{ column: "", operator: "contains", value: "" }]); + setColumnFilters([]); }; const totalValor = data.reduce((sum, item) => { @@ -213,255 +296,319 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { }; return ( -
-
-

Análise Analítica

- {data.length > 0 && ( - - )} -
- - {/* Filtros aplicados */} - {/*
-
- Filtros aplicados: -
- {filtros.centroCusto && ( - - Centro: {filtros.centroCusto} - - )} - {filtros.codigoGrupo && ( - - Grupo: {filtros.codigoGrupo} - - )} - {filtros.codigoSubgrupo && ( - - Subgrupo: {filtros.codigoSubgrupo} - - )} - {filtros.codigoConta && ( - - Conta: {filtros.codigoConta} - + + +
+
+
+ + + +
+
+

Análise Analítica

+

Relatório detalhado de transações

+
+
+
+ ) => setGlobalFilter(e.target.value)} + className="w-64 bg-white border-gray-300 focus:border-blue-500 focus:ring-blue-500" + /> + + {data.length > 0 && ( + )}
-
*/} - {/* Resumo */} - - {/* Tabela */} -
- {/* Header fixo */} -
-
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
Histórico
-
Histórico 2
-
Recnum
-
-
- -
- {loading ? ( -
- Carregando dados analíticos... -
- ) : sortedData.length === 0 ? ( -
- Nenhum dado analítico encontrado para os filtros aplicados. -
- ) : ( - sortedData.map((row, index) => ( -
-
- {formatDate(row.data_competencia)} -
-
- {formatDate(row.data_vencimento)} -
-
- {formatDate(row.data_caixa)} -
-
- {row.codigo_fornecedor || '-'} -
-
- {row.nome_fornecedor || '-'} -
-
- {row.codigo_centrocusto || '-'} -
-
- {row.codigo_conta || '-'} -
-
- {row.conta || '-'} -
-
- {(() => { - const valor = - typeof row.valor === 'string' - ? parseFloat(row.valor) - : row.valor; - const { formatted, isNegative } = - formatCurrencyWithColor(valor); +
+ + + {table.getHeaderGroups().map((hg: any) => ( + + {hg.headers.map((header: any) => { + const sorted = header.column.getIsSorted(); return ( - - {formatted} - +
+ + {flexRender(header.column.columnDef.header, header.getContext())} + +
+ {sorted === "asc" ? ( + + ) : sorted === "desc" ? ( + + ) : ( +
+ + +
+ )} +
+
+ ); - })()} + })} + + ))} + +
+ +
+ + + {loading ? ( + + + + ) : virtualRows.length === 0 ? ( + + + + ) : ( + virtualRows.map((virtualRow: any) => { + const row = table.getRowModel().rows[virtualRow.index]; + return ( + + {row.getVisibleCells().map((cell: any, cellIndex: number) => ( + + ))} + + ); + }) + )} + +
+
+
+ Carregando dados analíticos... +
+
+
+
+ + + +
+ Nenhum dado analítico encontrado para os filtros aplicados. +
+
+
+ {flexRender(cell.column.columnDef.cell, cell.getContext())} +
+
+
+
+ + {data.length > 0 && ( +
+
+
+
+ + +
-
- {row.historico || '-'} -
-
- {row.historico2 || '-'} -
-
- {row.recnum || '-'} +
+

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

+

Transações encontradas

- )) - )} -
-
- {data.length > 0 && ( -
-
-
-

- Total de Registros: {data.length} -

-
-
-

- {(() => { - const { formatted, isNegative } = - formatCurrencyWithColor(totalValor); - return ( - - Valor Total: {formatted} - - ); - })()} -

+
+

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

+

Soma de todos os valores

+
-
- )} -
+ )} + + + + + 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 && ( +
+ +
+ )} +
+ ))} + +
+ +
+
+ + + + + +
+
+ + ); -} +} \ No newline at end of file diff --git a/src/components/ui/card.tsx b/src/components/ui/card.tsx new file mode 100644 index 0000000..794c886 --- /dev/null +++ b/src/components/ui/card.tsx @@ -0,0 +1,27 @@ +import * as React from "react" +import { cn } from "@/lib/utils" + +const Card = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+)) +Card.displayName = "Card" + +const CardContent = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+)) +CardContent.displayName = "CardContent" + +export { Card, CardContent } diff --git a/src/components/ui/dialog.tsx b/src/components/ui/dialog.tsx new file mode 100644 index 0000000..230cd30 --- /dev/null +++ b/src/components/ui/dialog.tsx @@ -0,0 +1,119 @@ +import * as React from "react" +import * as DialogPrimitive from "@radix-ui/react-dialog" +import { X } from "lucide-react" +import { cn } from "@/lib/utils" + +const Dialog = DialogPrimitive.Root + +const DialogTrigger = DialogPrimitive.Trigger + +const DialogPortal = DialogPrimitive.Portal + +const DialogClose = DialogPrimitive.Close + +const DialogOverlay = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +DialogOverlay.displayName = DialogPrimitive.Overlay.displayName + +const DialogContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, ...props }, ref) => ( + + + + {children} + + + Close + + + +)) +DialogContent.displayName = DialogPrimitive.Content.displayName + +const DialogHeader = ({ + className, + ...props +}: React.HTMLAttributes) => ( +
+) +DialogHeader.displayName = "DialogHeader" + +const DialogFooter = ({ + className, + ...props +}: React.HTMLAttributes) => ( +
+) +DialogFooter.displayName = "DialogFooter" + +const DialogTitle = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +DialogTitle.displayName = DialogPrimitive.Title.displayName + +const DialogDescription = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +DialogDescription.displayName = DialogPrimitive.Description.displayName + +export { + Dialog, + DialogPortal, + DialogOverlay, + DialogClose, + DialogTrigger, + DialogContent, + DialogHeader, + DialogFooter, + DialogTitle, + DialogDescription, +} diff --git a/src/components/ui/input.tsx b/src/components/ui/input.tsx new file mode 100644 index 0000000..d63bae1 --- /dev/null +++ b/src/components/ui/input.tsx @@ -0,0 +1,24 @@ +import * as React from "react" +import { cn } from "@/lib/utils" + +export interface InputProps + extends React.InputHTMLAttributes {} + +const Input = React.forwardRef( + ({ className, type, ...props }, ref) => { + return ( + + ) + } +) +Input.displayName = "Input" + +export { Input } diff --git a/src/components/ui/select.tsx b/src/components/ui/select.tsx new file mode 100644 index 0000000..2e2b024 --- /dev/null +++ b/src/components/ui/select.tsx @@ -0,0 +1,157 @@ +import * as React from "react" +import * as SelectPrimitive from "@radix-ui/react-select" +import { Check, ChevronDown, ChevronUp } from "lucide-react" +import { cn } from "@/lib/utils" + +const Select = SelectPrimitive.Root + +const SelectGroup = SelectPrimitive.Group + +const SelectValue = SelectPrimitive.Value + +const SelectTrigger = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, ...props }, ref) => ( + span]:line-clamp-1", + className + )} + {...props} + > + {children} + + + + +)) +SelectTrigger.displayName = SelectPrimitive.Trigger.displayName + +const SelectScrollUpButton = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + + + +)) +SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName + +const SelectScrollDownButton = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + + + +)) +SelectScrollDownButton.displayName = + SelectPrimitive.ScrollDownButton.displayName + +const SelectContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, position = "popper", ...props }, ref) => ( + + + + + {children} + + + + +)) +SelectContent.displayName = SelectPrimitive.Content.displayName + +const SelectLabel = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +SelectLabel.displayName = SelectPrimitive.Label.displayName + +const SelectItem = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, ...props }, ref) => ( + + + + + + + + {children} + +)) +SelectItem.displayName = SelectPrimitive.Item.displayName + +const SelectSeparator = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +SelectSeparator.displayName = SelectPrimitive.Separator.displayName + +export { + Select, + SelectGroup, + SelectValue, + SelectTrigger, + SelectContent, + SelectLabel, + SelectItem, + SelectSeparator, + SelectScrollUpButton, + SelectScrollDownButton, +} From 1de1031fbcc751749a9fc0a3a26c439f42b04222 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alessandro=20Gon=C3=A7aalves?= Date: Mon, 20 Oct 2025 13:03:14 -0300 Subject: [PATCH 02/30] fix: filtro --- .eslintrc.json | 4 +- src/app/DRE/analitico.tsx | 96 +++++++++++++++++++++------------------ 2 files changed, 56 insertions(+), 44 deletions(-) diff --git a/.eslintrc.json b/.eslintrc.json index 13015d6..0149fec 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -1,6 +1,8 @@ { "extends": "next/core-web-vitals", "rules": { - "@typescript-eslint/no-explicit-any": "off" + "@typescript-eslint/no-explicit-any": "off", + "@typescript-eslint/no-unused-vars": "off", + "@typescript-eslint/no-empty-object-type": "off" } } diff --git a/src/app/DRE/analitico.tsx b/src/app/DRE/analitico.tsx index 157458c..28bdd1b 100644 --- a/src/app/DRE/analitico.tsx +++ b/src/app/DRE/analitico.tsx @@ -114,7 +114,8 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { { accessorKey: "data_competencia", header: "Data Comp.", - cell: ({ getValue }: any) => { + filterFn: "advancedText", + cell: ({ getValue }: { getValue: () => string }) => { const value = getValue(); return new Date(value).toLocaleDateString('pt-BR'); } @@ -122,7 +123,8 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { { accessorKey: "data_vencimento", header: "Data Venc.", - cell: ({ getValue }: any) => { + filterFn: "advancedText", + cell: ({ getValue }: { getValue: () => string }) => { const value = getValue(); return new Date(value).toLocaleDateString('pt-BR'); } @@ -130,20 +132,22 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { { accessorKey: "data_caixa", header: "Data Caixa", - cell: ({ getValue }: any) => { + filterFn: "advancedText", + cell: ({ getValue }: { getValue: () => string }) => { const value = getValue(); return new Date(value).toLocaleDateString('pt-BR'); } }, - { accessorKey: "codigo_fornecedor", header: "Cód. Fornec." }, - { accessorKey: "nome_fornecedor", header: "Fornecedor" }, - { accessorKey: "codigo_centrocusto", header: "Cód. Centro" }, - { accessorKey: "codigo_conta", header: "Cód. Conta" }, - { accessorKey: "conta", header: "Conta" }, + { accessorKey: "codigo_fornecedor", header: "Cód. Fornec.", filterFn: "advancedText" }, + { accessorKey: "nome_fornecedor", header: "Fornecedor", filterFn: "advancedText" }, + { accessorKey: "codigo_centrocusto", header: "Cód. Centro", filterFn: "advancedText" }, + { accessorKey: "codigo_conta", header: "Cód. Conta", filterFn: "advancedText" }, + { accessorKey: "conta", header: "Conta", filterFn: "advancedText" }, { accessorKey: "valor", header: "Valor", - cell: ({ getValue }: any) => { + filterFn: "advancedText", + cell: ({ getValue }: { getValue: () => number }) => { const value = getValue(); const formatted = new Intl.NumberFormat('pt-BR', { style: 'currency', @@ -157,9 +161,9 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { ); } }, - { accessorKey: "historico", header: "Histórico" }, - { accessorKey: "historico2", header: "Histórico 2" }, - { accessorKey: "recnum", header: "Recnum" }, + { accessorKey: "historico", header: "Histórico", filterFn: "advancedText" }, + { accessorKey: "historico2", header: "Histórico 2", filterFn: "advancedText" }, + { accessorKey: "recnum", header: "Recnum", filterFn: "advancedText" }, ], [] ); @@ -228,9 +232,15 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { }, []); const applyFilters = () => { - const filters = conditions - .filter((c) => c.column && (c.operator === "empty" || c.operator === "notEmpty" || (c.value ?? "") !== "")) - .map((c) => ({ id: c.column, value: { operator: c.operator, value: c.value } })); + const validConditions = conditions.filter((c) => + c.column && (c.operator === "empty" || c.operator === "notEmpty" || (c.value ?? "") !== "") + ); + + const filters = validConditions.map((c) => ({ + id: c.column, + value: { operator: c.operator, value: c.value } + })); + setColumnFilters(filters); setOpen(false); }; @@ -336,16 +346,16 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { )}
-
+
- {table.getHeaderGroups().map((hg: any) => ( + {table.getHeaderGroups().map((hg) => ( - {hg.headers.map((header: any) => { + {hg.headers.map((header) => { const sorted = header.column.getIsSorted(); return ( ); })} @@ -389,7 +399,7 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) {
Carregando dados analíticos... -
+ ) : virtualRows.length === 0 ? ( @@ -400,13 +410,13 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { - + Nenhum dado analítico encontrado para os filtros aplicados. - + ) : ( - virtualRows.map((virtualRow: any) => { + virtualRows.map((virtualRow) => { const row = table.getRowModel().rows[virtualRow.index]; return ( - {row.getVisibleCells().map((cell: any, cellIndex: number) => ( + {row.getVisibleCells().map((cell, cellIndex) => ( ))} @@ -446,16 +456,16 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { - {data.length > 0 && ( + {data.length > 0 && (
-
+
-
-
+
+

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

@@ -469,13 +479,13 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { style: 'currency', currency: 'BRL', }).format(totalValor)} - - + +

Soma de todos os valores

-
- )} +
+ )} @@ -502,11 +512,11 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { - {columns.map((col: any) => ( - - {col.header} - - ))} + {columns.map((col) => ( + + {col.header} + + ))}
@@ -589,7 +599,7 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { Adicionar condição - +
{flexRender(header.column.columnDef.header, header.getContext())} - +
{sorted === "asc" ? ( @@ -367,9 +377,9 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) {
- )} - - + )} + +
{flexRender(cell.column.columnDef.cell, cell.getContext())} -
+
- - {table.getHeaderGroups().map((hg) => ( - - {hg.headers.map((header) => { - const sorted = header.column.getIsSorted(); - return ( - - ); - })} - - ))} - -
-
- - {flexRender(header.column.columnDef.header, header.getContext())} - -
- {sorted === "asc" ? ( - - ) : sorted === "desc" ? ( - - ) : ( -
- - -
- )} -
-
-
- -
- - +
+
+
+ + {table.getHeaderGroups().map((hg) => ( + + {hg.headers.map((header) => { + const sorted = header.column.getIsSorted(); + return ( + + ); + })} + + ))} + + {loading ? ( - {row.getVisibleCells().map((cell, cellIndex) => ( - - ))} + {row.getVisibleCells().map((cell, cellIndex) => ( + + ))} ); }) )} - -
+
+ + {flexRender(header.column.columnDef.header, header.getContext())} + +
+ {sorted === "asc" ? ( + + ) : sorted === "desc" ? ( + + ) : ( +
+ + +
+ )} +
+
+
@@ -441,70 +445,69 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) {
-
- {flexRender(cell.column.columnDef.cell, cell.getContext())} -
-
+
+ {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

-
-
-
- )} + + +
+ + {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

+
+
+
+ )} +
From 88c334959dea85d4493c55512a3c1287992f976b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alessandro=20Gon=C3=A7aalves?= Date: Mon, 20 Oct 2025 17:03:15 -0300 Subject: [PATCH 05/30] =?UTF-8?q?fix:=20Corre=C3=A7=C3=A3o=20da=20estiliza?= =?UTF-8?q?=C3=A7=C3=A3o=20da=20DRE=20Gerencial?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/DRE/analitico.tsx | 592 +++++++++++++++++--------------------- src/app/DRE/teste.tsx | 336 ++++++++-------------- 2 files changed, 398 insertions(+), 530 deletions(-) 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} ); From 6e9a3ad4b926390a81f242d59e0b143364dd3a81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alessandro=20Gon=C3=A7aalves?= Date: Mon, 20 Oct 2025 17:07:31 -0300 Subject: [PATCH 06/30] fix: rolagem horizontal da da da tabela analitica --- src/app/DRE/analitico.tsx | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/app/DRE/analitico.tsx b/src/app/DRE/analitico.tsx index 46e2a1c..f43c1e5 100644 --- a/src/app/DRE/analitico.tsx +++ b/src/app/DRE/analitico.tsx @@ -358,7 +358,8 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) {
{/* Table Container */} -
+
+
{/* Table Header */}
@@ -378,7 +379,11 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { {/* Table Body */}
{loading ? (
@@ -426,6 +431,7 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) {
)}
+
{/* Summary Footer */} {data.length > 0 && ( @@ -437,10 +443,10 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) {
-
+

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

+

Transações encontradas

@@ -451,7 +457,7 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { style: 'currency', currency: 'BRL', }).format(totalValor)} - +

Soma de todos os valores

From dd5f92825c44260c92b8615edefc5bc14118786b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alessandro=20Gon=C3=A7aalves?= Date: Mon, 20 Oct 2025 17:26:14 -0300 Subject: [PATCH 07/30] =?UTF-8?q?fix:=20bot=C3=B5es=20de=20filtro?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/DRE/analitico.tsx | 125 +++++++++++++++++++++----------------- 1 file changed, 69 insertions(+), 56 deletions(-) diff --git a/src/app/DRE/analitico.tsx b/src/app/DRE/analitico.tsx index f43c1e5..ddfd3fe 100644 --- a/src/app/DRE/analitico.tsx +++ b/src/app/DRE/analitico.tsx @@ -24,7 +24,7 @@ import { SelectContent, SelectItem, } from "@/components/ui/select"; -import { Download } from "lucide-react"; +import { Download, Filter, X } from "lucide-react"; import * as XLSX from 'xlsx'; interface AnaliticoItem { @@ -255,6 +255,7 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { const clearFilters = () => { setConditions([{ column: "", operator: "contains", value: "" }]); setColumnFilters([]); + setGlobalFilter(""); }; const totalValor = data.reduce((sum, item) => { @@ -328,33 +329,44 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) {
- {/* Controls */} -
- ) => setGlobalFilter(e.target.value)} - className="w-64 bg-white border-gray-300 focus:border-blue-500 focus:ring-blue-500" - /> - - {data.length > 0 && ( - - )} -
+ {/* Controls */} +
+ ) => setGlobalFilter(e.target.value)} + className="w-64 bg-white border-gray-300 focus:border-blue-500 focus:ring-blue-500" + /> + + {(columnFilters.length > 0 || globalFilter) && ( + + )} + {data.length > 0 && ( + + )} +
{/* Table Container */} @@ -431,39 +443,40 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) {
)}
-
-
- {/* Summary Footer */} - {data.length > 0 && ( -
-
-
-
- - - + + {/* Summary Footer - Integrado */} + {data.length > 0 && ( +
+
+
+
+ + + +
+
+

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

+

Transações encontradas

+
-
-

- 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

-
-

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

-

Soma de todos os valores

-
+ )}
- )} +
{/* Advanced Filters Dialog */} From 35aca238eaacc4cab657ce7badfa027d660190a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alessandro=20Gon=C3=A7aalves?= Date: Mon, 20 Oct 2025 17:35:24 -0300 Subject: [PATCH 08/30] =?UTF-8?q?fix:=20remo=C3=A7=C3=A3o=20dos=20icones?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/DRE/analitico.tsx | 550 +++++++++++++++++++++++--------------- src/app/DRE/teste.tsx | 303 ++++++++++++++------- 2 files changed, 543 insertions(+), 310 deletions(-) diff --git a/src/app/DRE/analitico.tsx b/src/app/DRE/analitico.tsx index ddfd3fe..bc8bb10 100644 --- a/src/app/DRE/analitico.tsx +++ b/src/app/DRE/analitico.tsx @@ -1,4 +1,4 @@ -'use client'; +"use client"; import * as React from "react"; import { @@ -25,7 +25,7 @@ import { SelectItem, } from "@/components/ui/select"; import { Download, Filter, X } from "lucide-react"; -import * as XLSX from 'xlsx'; +import * as XLSX from "xlsx"; interface AnaliticoItem { codigo_grupo: string; @@ -66,7 +66,9 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { const [globalFilter, setGlobalFilter] = React.useState(""); const [columnFilters, setColumnFilters] = React.useState([]); const [open, setOpen] = React.useState(false); - const [conditions, setConditions] = React.useState([{ column: "", operator: "contains", value: "" }]); + const [conditions, setConditions] = React.useState([ + { column: "", operator: "contains", value: "" }, + ]); const fetchData = React.useCallback(async () => { // Só faz a requisição se tiver dataInicio e dataFim @@ -93,10 +95,10 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { const result = await response.json(); setData(result as AnaliticoItem[]); } else { - console.error('Erro ao buscar dados:', await response.text()); + console.error("Erro ao buscar dados:", await response.text()); } } catch (error) { - console.error('Erro ao buscar dados:', error); + console.error("Erro ao buscar dados:", error); } finally { setLoading(false); } @@ -108,58 +110,82 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { const columns = React.useMemo( () => [ - { - accessorKey: "data_competencia", - header: "Data Comp.", + { + accessorKey: "data_competencia", + header: "Data Comp.", filterFn: "advancedText", cell: ({ getValue }: { getValue: () => string }) => { const value = getValue(); - return new Date(value).toLocaleDateString('pt-BR'); - } + return new Date(value).toLocaleDateString("pt-BR"); + }, }, - { - accessorKey: "data_vencimento", - header: "Data Venc.", + { + accessorKey: "data_vencimento", + header: "Data Venc.", filterFn: "advancedText", cell: ({ getValue }: { getValue: () => string }) => { const value = getValue(); - return new Date(value).toLocaleDateString('pt-BR'); - } + return new Date(value).toLocaleDateString("pt-BR"); + }, }, - { - accessorKey: "data_caixa", - header: "Data Caixa", + { + accessorKey: "data_caixa", + header: "Data Caixa", filterFn: "advancedText", cell: ({ getValue }: { getValue: () => string }) => { const value = getValue(); - return new Date(value).toLocaleDateString('pt-BR'); - } + return new Date(value).toLocaleDateString("pt-BR"); + }, + }, + { + accessorKey: "codigo_fornecedor", + header: "Cód. Fornec.", + filterFn: "advancedText", + }, + { + accessorKey: "nome_fornecedor", + header: "Fornecedor", + filterFn: "advancedText", + }, + { + accessorKey: "codigo_centrocusto", + header: "Cód. Centro", + filterFn: "advancedText", + }, + { + accessorKey: "codigo_conta", + header: "Cód. Conta", + filterFn: "advancedText", }, - { accessorKey: "codigo_fornecedor", header: "Cód. Fornec.", filterFn: "advancedText" }, - { accessorKey: "nome_fornecedor", header: "Fornecedor", filterFn: "advancedText" }, - { accessorKey: "codigo_centrocusto", header: "Cód. Centro", filterFn: "advancedText" }, - { accessorKey: "codigo_conta", header: "Cód. Conta", filterFn: "advancedText" }, { accessorKey: "conta", header: "Conta", filterFn: "advancedText" }, - { - accessorKey: "valor", - header: "Valor", + { + accessorKey: "valor", + header: "Valor", filterFn: "advancedText", cell: ({ getValue }: { getValue: () => number }) => { const value = getValue(); - const formatted = new Intl.NumberFormat('pt-BR', { - style: 'currency', - currency: 'BRL', + const formatted = new Intl.NumberFormat("pt-BR", { + style: "currency", + currency: "BRL", }).format(value); const isNegative = value < 0; return ( - + {formatted} ); - } + }, + }, + { + accessorKey: "historico", + header: "Histórico", + filterFn: "advancedText", + }, + { + accessorKey: "historico2", + header: "Histórico 2", + filterFn: "advancedText", }, - { accessorKey: "historico", header: "Histórico", filterFn: "advancedText" }, - { accessorKey: "historico2", header: "Histórico 2", filterFn: "advancedText" }, { accessorKey: "recnum", header: "Recnum", filterFn: "advancedText" }, ], [] @@ -169,10 +195,10 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { () => ({ advancedText: (row: any, columnId: string, filters: any[]) => { if (!filters || filters.length === 0) return true; - + // Se veio um único filtro (objeto), transforma em array const conds = Array.isArray(filters) ? filters : [filters]; - + // A coluna deve atender a todas as condições aplicáveis a ela return conds.every((filter) => { const raw = row.getValue(columnId); @@ -181,7 +207,7 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { const q = (filter.value ?? "").toString(); const a = v.toLowerCase(); const b = q.toLowerCase(); - + switch (op) { case "contains": return a.includes(b); @@ -203,7 +229,6 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { }), [] ); - const table = useReactTable({ data, @@ -227,27 +252,28 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { const virtualRows = rowVirtualizer.getVirtualItems(); - const applyFilters = () => { // Agrupar múltiplas condições por coluna const grouped: Record = {}; - + conditions.forEach((c) => { if ( c.column && - (c.operator === "empty" || c.operator === "notEmpty" || (c.value ?? "") !== "") + (c.operator === "empty" || + c.operator === "notEmpty" || + (c.value ?? "") !== "") ) { if (!grouped[c.column]) grouped[c.column] = []; grouped[c.column].push({ operator: c.operator, value: c.value }); } }); - + // Converte em formato aceito pelo TanStack const filters = Object.keys(grouped).map((col) => ({ id: col, value: grouped[col], })); - + setColumnFilters(filters); setOpen(false); }; @@ -260,7 +286,7 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { const totalValor = data.reduce((sum, item) => { const valor = - typeof item.valor === 'string' ? parseFloat(item.valor) : item.valor; + typeof item.valor === "string" ? parseFloat(item.valor) : item.valor; return sum + (isNaN(valor) ? 0 : valor); }, 0); @@ -269,23 +295,23 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { // Preparar dados para exportação const exportData = data.map((item) => ({ - 'Data Competência': new Date(item.data_competencia).toLocaleDateString( - 'pt-BR' + "Data Competência": new Date(item.data_competencia).toLocaleDateString( + "pt-BR" ), - 'Data Vencimento': new Date(item.data_vencimento).toLocaleDateString( - 'pt-BR' + "Data Vencimento": new Date(item.data_vencimento).toLocaleDateString( + "pt-BR" ), - 'Data Caixa': new Date(item.data_caixa).toLocaleDateString('pt-BR'), - 'Código Fornecedor': item.codigo_fornecedor, + "Data Caixa": new Date(item.data_caixa).toLocaleDateString("pt-BR"), + "Código Fornecedor": item.codigo_fornecedor, Fornecedor: item.nome_fornecedor, - 'Código Centro Custo': item.codigo_centrocusto, - 'Centro Custo': item.codigo_centrocusto, // Assumindo que é o mesmo valor - 'Código Conta': item.codigo_conta, + "Código Centro Custo": item.codigo_centrocusto, + "Centro Custo": item.codigo_centrocusto, // Assumindo que é o mesmo valor + "Código Conta": item.codigo_conta, Conta: item.conta, Valor: - typeof item.valor === 'string' ? parseFloat(item.valor) : item.valor, + typeof item.valor === "string" ? parseFloat(item.valor) : item.valor, Histórico: item.historico, - 'Histórico 2': item.historico2, + "Histórico 2": item.historico2, Recnum: item.recnum, })); @@ -295,18 +321,18 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { // Adicionar resumo na segunda aba const resumoData = [ - { Métrica: 'Total de Registros', Valor: data.length }, - { Métrica: 'Valor Total', Valor: totalValor }, + { Métrica: "Total de Registros", Valor: data.length }, + { Métrica: "Valor Total", Valor: totalValor }, ]; const wsResumo = XLSX.utils.json_to_sheet(resumoData); // Adicionar abas ao workbook - XLSX.utils.book_append_sheet(wb, ws, 'Dados Analíticos'); - XLSX.utils.book_append_sheet(wb, wsResumo, 'Resumo'); + XLSX.utils.book_append_sheet(wb, ws, "Dados Analíticos"); + XLSX.utils.book_append_sheet(wb, wsResumo, "Resumo"); // Gerar nome do arquivo com data e hora const now = new Date(); - const timestamp = now.toISOString().slice(0, 19).replace(/:/g, '-'); + const timestamp = now.toISOString().slice(0, 19).replace(/:/g, "-"); const fileName = `analitico_${timestamp}.xlsx`; // Fazer download @@ -318,163 +344,258 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { {/* Header Section */}
-
- - + {/*
+ + -
+
*/}
-

Análise Analítica

-

Relatório detalhado de transações

+

+ 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" - /> - - {(columnFilters.length > 0 || globalFilter) && ( - - )} - {data.length > 0 && ( - - )} -
+ + {/* Controls */} +
+ ) => + setGlobalFilter(e.target.value) + } + className="w-64 bg-white border-gray-300 focus:border-blue-500 focus:ring-blue-500" + /> + + {(columnFilters.length > 0 || globalFilter) && ( + + )} + {data.length > 0 && ( + + )} +
{/* Table Container */}
- {/* Table Header */} -
-
-
Data Comp.
-
Data Venc.
-
Data Caixa
-
Cód. Fornec.
-
Fornecedor
-
Cód. Centro
-
Cód. Conta
-
Conta
-
Valor
-
Recnum
+ {/* Table Header */} +
+
+
Data Comp.
+
Data Venc.
+
Data Caixa
+
Cód. Fornec.
+
Fornecedor
+
Cód. Centro
+
Cód. Conta
+
Conta
+
Valor
+
Recnum
+
-
- {/* Table Body */} -
- {loading ? ( -
-
-
-

Carregando dados...

-
-
- ) : virtualRows.length === 0 ? ( -
-
-
- - - + {/* Table Body */} +
+ {loading ? ( +
+
+
+

Carregando dados...

-

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)} + ) : virtualRows.length === 0 ? ( +
+
+
+ + + +
+

Nenhum dado encontrado

-
{row.original.recnum}
-
- ); - })}
- )} -
+ ) : ( +
+ {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 - Integrado */} - {data.length > 0 && ( -
-
-
-
- - - + {/* Summary Footer - Integrado */} + {data.length > 0 && ( +
+
+
+ {/*
+ + + +
*/} +
+

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

+

+ Transações encontradas +

+
-
-

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

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

-

Transações encontradas

+

+ Soma de todos os valores +

-
-

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

-

Soma de todos os valores

-
-
- )} + )}
@@ -482,12 +603,17 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { - Filtros Avançados + + Filtros Avançados +
{conditions.map((cond, idx) => ( -
+
@@ -522,7 +651,8 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { onValueChange={(v: string) => { const next = [...conditions]; next[idx].operator = v; - if (v === "empty" || v === "notEmpty") next[idx].value = ""; + if (v === "empty" || v === "notEmpty") + next[idx].value = ""; setConditions(next); }} > @@ -540,7 +670,9 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) {
- {!(cond.operator === "empty" || cond.operator === "notEmpty") && ( + {!( + cond.operator === "empty" || cond.operator === "notEmpty" + ) && (
- -
); -} \ No newline at end of file +} diff --git a/src/app/DRE/teste.tsx b/src/app/DRE/teste.tsx index 272032c..77fb086 100644 --- a/src/app/DRE/teste.tsx +++ b/src/app/DRE/teste.tsx @@ -1,8 +1,8 @@ -'use client'; +"use client"; -import { LoaderPinwheel } from 'lucide-react'; -import { useEffect, useState } from 'react'; -import AnaliticoComponent from './analitico'; +import { LoaderPinwheel } from "lucide-react"; +import { useEffect, useState } from "react"; +import AnaliticoComponent from "./analitico"; interface DREItem { codfilial: string; @@ -17,7 +17,7 @@ interface DREItem { } interface HierarchicalRow { - type: 'grupo' | 'subgrupo' | 'centro_custo' | 'conta'; + type: "grupo" | "subgrupo" | "centro_custo" | "conta"; level: number; grupo?: string; subgrupo?: string; @@ -30,7 +30,6 @@ interface HierarchicalRow { percentuaisPorMes?: Record; } - export default function Teste() { const [data, setData] = useState([]); const [loading, setLoading] = useState(true); @@ -46,12 +45,12 @@ export default function Teste() { // Estados para analítico const [analiticoFiltros, setAnaliticoFiltros] = useState({ - dataInicio: '', - dataFim: '', - centroCusto: '', - codigoGrupo: '', - codigoSubgrupo: '', - codigoConta: '', + dataInicio: "", + dataFim: "", + centroCusto: "", + codigoGrupo: "", + codigoSubgrupo: "", + codigoConta: "", }); const [linhaSelecionada, setLinhaSelecionada] = useState(null); @@ -63,7 +62,7 @@ export default function Teste() { try { setLoading(true); setError(null); - const response = await fetch('/api/dre'); + const response = await fetch("/api/dre"); if (!response.ok) { throw new Error(`Erro ao carregar dados: ${response.status}`); @@ -79,29 +78,29 @@ export default function Teste() { const dataCompetencia = new Date(item.data_competencia); return `${dataCompetencia.getFullYear()}-${String( dataCompetencia.getMonth() + 1 - ).padStart(2, '0')}`; + ).padStart(2, "0")}`; }) ), ].sort() as string[]; setMesesDisponiveis(meses); } catch (err) { - setError(err instanceof Error ? err.message : 'Erro desconhecido'); + setError(err instanceof Error ? err.message : "Erro desconhecido"); } finally { setLoading(false); } }; const formatCurrency = (value: string | number) => { - const numValue = typeof value === 'string' ? parseFloat(value) : value; - return numValue.toLocaleString('pt-BR', { - style: 'currency', - currency: 'BRL', + const numValue = typeof value === "string" ? parseFloat(value) : value; + return numValue.toLocaleString("pt-BR", { + style: "currency", + currency: "BRL", }); }; const formatCurrencyWithColor = (value: string | number) => { - const numValue = typeof value === 'string' ? parseFloat(value) : value; + const numValue = typeof value === "string" ? parseFloat(value) : value; const formatted = formatCurrency(value); const isNegative = numValue < 0; return { formatted, isNegative }; @@ -110,9 +109,9 @@ export default function Teste() { // Função para extrair códigos dos grupos e subgrupos const extractCodes = (grupo: string, subgrupo?: string) => { const grupoMatch = grupo.match(/^(\d+)/); - const codigoGrupo = grupoMatch ? grupoMatch[1] : ''; + const codigoGrupo = grupoMatch ? grupoMatch[1] : ""; - let codigoSubgrupo = ''; + let codigoSubgrupo = ""; if (subgrupo) { // Primeiro tenta extrair código numérico (ex: "001.008 - LOJA 8" -> "001.008") const subgrupoMatch = subgrupo.match(/^(\d+(?:\.\d+)+)/); @@ -140,14 +139,14 @@ export default function Teste() { const dataFimStr = new Date(dataFim).toISOString().substring(0, 7); // YYYY-MM const { codigoGrupo, codigoSubgrupo } = extractCodes( - row.grupo || '', + row.grupo || "", row.subgrupo ); // Criar um identificador único para a linha - const linhaId = `${row.type}-${row.grupo || ''}-${row.subgrupo || ''}-${ - row.centro_custo || '' - }-${row.codigo_conta || ''}`; + const linhaId = `${row.type}-${row.grupo || ""}-${row.subgrupo || ""}-${ + row.centro_custo || "" + }-${row.codigo_conta || ""}`; setLinhaSelecionada(linhaId); // Se um mês específico foi selecionado, usar apenas esse mês @@ -157,10 +156,10 @@ export default function Teste() { setAnaliticoFiltros({ dataInicio: dataInicioFiltro, dataFim: dataFimFiltro, - centroCusto: row.centro_custo || '', + centroCusto: row.centro_custo || "", codigoGrupo, codigoSubgrupo, - codigoConta: row.codigo_conta?.toString() || '', + codigoConta: row.codigo_conta?.toString() || "", }); }; @@ -194,7 +193,6 @@ export default function Teste() { setExpandedCentros(newExpanded); }; - const calcularValoresPorMes = (items: DREItem[]): Record => { const valoresPorMes: Record = {}; @@ -202,7 +200,7 @@ export default function Teste() { const dataCompetencia = new Date(item.data_competencia); const anoMes = `${dataCompetencia.getFullYear()}-${String( dataCompetencia.getMonth() + 1 - ).padStart(2, '0')}`; + ).padStart(2, "0")}`; if (!valoresPorMes[anoMes]) { valoresPorMes[anoMes] = 0; @@ -221,7 +219,7 @@ export default function Teste() { const percentuais: Record = {}; // Se for o grupo 03, retorna 100% para todos os meses - if (grupo.includes('03')) { + if (grupo.includes("03")) { Object.keys(valoresPorMes).forEach((mes) => { percentuais[mes] = 100; }); @@ -237,8 +235,8 @@ export default function Teste() { const dataCompetencia = new Date(item.data_competencia); const anoMes = `${dataCompetencia.getFullYear()}-${String( dataCompetencia.getMonth() + 1 - ).padStart(2, '0')}`; - return anoMes === mes && item.grupo.includes('03'); + ).padStart(2, "0")}`; + return anoMes === mes && item.grupo.includes("03"); }); const valorGrupo03 = grupo03Items.reduce( @@ -262,16 +260,16 @@ export default function Teste() { // Agrupar por grupo, mas tratar grupo 05 como subgrupo do grupo 04 const grupos = data.reduce((acc, item) => { // Se for grupo 05, adicionar ao grupo 04 como subgrupo - if (item.grupo.includes('05')) { + if (item.grupo.includes("05")) { // Encontrar grupo 04 existente ou criar um - const grupo04Key = Object.keys(acc).find((key) => key.includes('04')); + const grupo04Key = Object.keys(acc).find((key) => key.includes("04")); if (grupo04Key) { acc[grupo04Key].push(item); } else { // Se não existe grupo 04, criar um grupo especial const grupo04Nome = - Object.keys(acc).find((key) => key.includes('04')) || - '04 - GRUPO 04'; + Object.keys(acc).find((key) => key.includes("04")) || + "04 - GRUPO 04"; if (!acc[grupo04Nome]) { acc[grupo04Nome] = []; } @@ -288,7 +286,9 @@ export default function Teste() { }, {} as Record); // Ordenar grupos - const sortedGrupos = Object.entries(grupos).sort(([a], [b]) => a.localeCompare(b)); + const sortedGrupos = Object.entries(grupos).sort(([a], [b]) => + a.localeCompare(b) + ); sortedGrupos.forEach(([grupo, items]) => { const totalGrupo = items.reduce( @@ -299,7 +299,7 @@ export default function Teste() { // Linha do grupo const valoresPorMes = calcularValoresPorMes(items); rows.push({ - type: 'grupo', + type: "grupo", level: 0, grupo, total: totalGrupo, @@ -312,7 +312,7 @@ export default function Teste() { // Agrupar por subgrupo dentro do grupo const subgrupos = items.reduce((acc, item) => { // Se o item originalmente era do grupo 05, agrupar tudo sob o nome do grupo 05 - if (item.grupo.includes('05')) { + if (item.grupo.includes("05")) { const subgrupoKey = item.grupo; // Usar o nome completo do grupo 05 if (!acc[subgrupoKey]) { acc[subgrupoKey] = []; @@ -329,7 +329,9 @@ export default function Teste() { }, {} as Record); // Ordenar subgrupos - const sortedSubgrupos = Object.entries(subgrupos).sort(([a], [b]) => a.localeCompare(b)); + const sortedSubgrupos = Object.entries(subgrupos).sort(([a], [b]) => + a.localeCompare(b) + ); sortedSubgrupos.forEach(([subgrupo, subgrupoItems]) => { const totalSubgrupo = subgrupoItems.reduce( @@ -340,7 +342,7 @@ export default function Teste() { // Linha do subgrupo const valoresSubgrupoPorMes = calcularValoresPorMes(subgrupoItems); rows.push({ - type: 'subgrupo', + type: "subgrupo", level: 1, grupo, subgrupo, @@ -364,7 +366,9 @@ export default function Teste() { }, {} as Record); // Ordenar centros de custo - const sortedCentros = Object.entries(centros).sort(([a], [b]) => a.localeCompare(b)); + const sortedCentros = Object.entries(centros).sort(([a], [b]) => + a.localeCompare(b) + ); sortedCentros.forEach(([centro, centroItems]) => { const totalCentro = centroItems.reduce( @@ -375,7 +379,7 @@ export default function Teste() { // Linha do centro de custo const valoresCentroPorMes = calcularValoresPorMes(centroItems); rows.push({ - type: 'centro_custo', + type: "centro_custo", level: 2, grupo, subgrupo, @@ -402,7 +406,9 @@ export default function Teste() { }, {} as Record); // Ordenar contas - const sortedContas = Object.entries(contas).sort(([a], [b]) => a.localeCompare(b)); + const sortedContas = Object.entries(contas).sort(([a], [b]) => + a.localeCompare(b) + ); sortedContas.forEach(([conta, contaItems]) => { const totalConta = contaItems.reduce( @@ -413,7 +419,7 @@ export default function Teste() { // Linha da conta (sem ano/mês no nome) const valoresContaPorMes = calcularValoresPorMes(contaItems); rows.push({ - type: 'conta', + type: "conta", level: 3, grupo, subgrupo, @@ -439,28 +445,30 @@ export default function Teste() { }; const getRowStyle = (row: HierarchicalRow) => { - const baseStyle = 'transition-all duration-200 hover:bg-gradient-to-r hover:from-blue-50/30 hover:to-indigo-50/30'; + 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 || ''}-${ - row.centro_custo || '' - }-${row.codigo_conta || ''}`; + const linhaId = `${row.type}-${row.grupo || ""}-${row.subgrupo || ""}-${ + row.centro_custo || "" + }-${row.codigo_conta || ""}`; const isSelected = linhaSelecionada === linhaId; let style = baseStyle; if (isSelected) { - style += ' bg-gradient-to-r from-blue-100 to-indigo-100 border-l-4 border-blue-500 shadow-lg'; + style += + " bg-gradient-to-r from-blue-100 to-indigo-100 border-l-4 border-blue-500 shadow-lg"; } switch (row.type) { - case 'grupo': + case "grupo": 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': + case "subgrupo": return `${style} bg-gradient-to-r from-gray-50/30 to-blue-50/20 font-semibold text-gray-800`; - case 'centro_custo': + case "centro_custo": return `${style} bg-gradient-to-r from-gray-50/20 to-gray-100/10 font-medium text-gray-700`; - case 'conta': + case "conta": return `${style} bg-white font-normal text-gray-600`; default: return style; @@ -473,7 +481,7 @@ export default function Teste() { const renderCellContent = (row: HierarchicalRow) => { switch (row.type) { - case 'grupo': + case "grupo": return (
); - case 'subgrupo': + case "subgrupo": return (
); - case 'centro_custo': + case "centro_custo": return (
); - case 'conta': + case "conta": return (
@@ -556,25 +568,43 @@ export default function Teste() {
-
- - + {/*
+ + -
+
*/}
-

DRE Gerencial

-

Demonstração do Resultado do Exercício

+

+ DRE Gerencial +

+

+ Demonstração do Resultado do Exercício +

- +
-

Carregando dados...

-

Aguarde enquanto processamos as informações

+

+ Carregando dados... +

+

+ Aguarde enquanto processamos as informações +

@@ -586,26 +616,52 @@ export default function Teste() {
-
- - + {/*
+ + -
+
*/}
-

DRE Gerencial

-

Demonstração do Resultado do Exercício

+

+ DRE Gerencial +

+

+ Demonstração do Resultado do Exercício +

- +
- - + +
-

Erro ao carregar DRE Gerencial

+

+ Erro ao carregar DRE Gerencial +

{error}

@@ -622,14 +678,26 @@ export default function Teste() { {/* Header Section */}
-
- - + {/*
+ + -
+
*/}

DRE Gerencial

-

Demonstração do Resultado do Exercício

+

+ Demonstração do Resultado do Exercício +

@@ -643,7 +711,9 @@ export default function Teste() { {mesesDisponiveis.map((mes) => (
{mes}
-
%
+
+ % +
))}
Total
@@ -653,8 +723,16 @@ export default function Teste() { {/* Table Body */}
{hierarchicalData.map((row, index) => ( -
-
+
+
{renderCellContent(row)}
{mesesDisponiveis.map((mes) => ( @@ -662,39 +740,62 @@ export default function Teste() {
handleRowClick(row, mes)} - title={row.valoresPorMes && row.valoresPorMes[mes] ? formatCurrency(row.valoresPorMes[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} ); })() - : '-'} + : "-"}
handleRowClick(row, mes)} - title={row.percentuaisPorMes && row.percentuaisPorMes[mes] !== undefined ? `${row.percentuaisPorMes[mes].toFixed(1)}%` : '-'} + 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) : '-'} + title={row.total ? formatCurrency(row.total) : "-"} > {(() => { - const { formatted, isNegative } = formatCurrencyWithColor(row.total!); + const { formatted, isNegative } = formatCurrencyWithColor( + row.total! + ); return ( - + {formatted} ); From f34292953954e15355afe6f01421249ff2e6b83f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alessandro=20Gon=C3=A7aalves?= Date: Mon, 20 Oct 2025 17:43:04 -0300 Subject: [PATCH 09/30] fix: calculo do dao card totalizador --- src/app/DRE/analitico.tsx | 98 +++++++++++++++++++++++---------------- 1 file changed, 57 insertions(+), 41 deletions(-) diff --git a/src/app/DRE/analitico.tsx b/src/app/DRE/analitico.tsx index bc8bb10..920d417 100644 --- a/src/app/DRE/analitico.tsx +++ b/src/app/DRE/analitico.tsx @@ -284,11 +284,27 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { setGlobalFilter(""); }; - const totalValor = data.reduce((sum, item) => { + const [totalValor, setTotalValor] = React.useState(0); + + React.useEffect(() => { + // Usar dados filtrados da tabela em vez dos dados originais + const filteredData = table.getRowModel().rows.map(row => row.original); + const newTotal = filteredData.reduce((sum, item) => { const valor = - typeof item.valor === "string" ? parseFloat(item.valor) : item.valor; + typeof item.valor === "string" ? parseFloat(item.valor) : item.valor; return sum + (isNaN(valor) ? 0 : valor); }, 0); + + console.log('🔄 Calculando total:', { + totalRows: table.getRowModel().rows.length, + originalDataLength: data.length, + newTotal, + columnFilters: columnFilters.length, + globalFilter + }); + + setTotalValor(newTotal); + }, [table, data, columnFilters, globalFilter]); const exportToExcel = () => { if (data.length === 0) return; @@ -402,17 +418,17 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { Limpar Filtros )} - {data.length > 0 && ( - - )} + > + + Exportar XLSX + + )}
@@ -432,8 +448,8 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) {
Conta
Valor
Recnum
-
+
{/* Table Body */}

Carregando dados...

-
-
+
+
) : virtualRows.length === 0 ? (
@@ -468,10 +484,10 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" /> -
+

Nenhum dado encontrado

-
-
+
+
) : (
+
{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} -
+
+
{row.original.recnum} -
-
+
+
); })} -
+
)} -
+
{/* Summary Footer - Integrado */} {data.length > 0 && ( @@ -573,12 +589,12 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) {

Transações encontradas

-
+

- @@ -587,14 +603,14 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { style: "currency", currency: "BRL", }).format(totalValor)} - +

Soma de todos os valores

+
-
)}
@@ -640,7 +656,7 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { ))} -
+
+
{!( cond.operator === "empty" || cond.operator === "notEmpty" @@ -687,7 +703,7 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { placeholder="Digite o valor" className="w-full bg-white border-gray-300" /> -
+
)} {conditions.length > 1 && ( @@ -703,8 +719,8 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { > ✕ -
- )} + + )} ))} From a4c751851b2e80c0ceb29e7711ec5653ba3eae56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alessandro=20Gon=C3=A7aalves?= Date: Mon, 20 Oct 2025 17:49:35 -0300 Subject: [PATCH 10/30] fix: ajuste na largura da coluna VALOR --- src/app/DRE/analitico.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/app/DRE/analitico.tsx b/src/app/DRE/analitico.tsx index 920d417..0ce2dd7 100644 --- a/src/app/DRE/analitico.tsx +++ b/src/app/DRE/analitico.tsx @@ -445,8 +445,8 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) {
Fornecedor
Cód. Centro
Cód. Conta
-
Conta
-
Valor
+
Conta
+
Valor
Recnum
@@ -532,13 +532,13 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { {row.original.codigo_conta}
{row.original.conta}
Date: Mon, 20 Oct 2025 17:53:57 -0300 Subject: [PATCH 11/30] =?UTF-8?q?fix:=20corre=C3=A7=C3=A3o=20na=20exporta?= =?UTF-8?q?=C3=A7=C3=A3o=20com=20filtro?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/DRE/analitico.tsx | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/app/DRE/analitico.tsx b/src/app/DRE/analitico.tsx index 0ce2dd7..6984ba8 100644 --- a/src/app/DRE/analitico.tsx +++ b/src/app/DRE/analitico.tsx @@ -309,8 +309,16 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { const exportToExcel = () => { if (data.length === 0) return; + // Usar dados filtrados da tabela em vez dos dados originais + const filteredData = table.getRowModel().rows.map(row => row.original); + + if (filteredData.length === 0) { + alert('Nenhum dado filtrado para exportar'); + return; + } + // Preparar dados para exportação - const exportData = data.map((item) => ({ + const exportData = filteredData.map((item) => ({ "Data Competência": new Date(item.data_competencia).toLocaleDateString( "pt-BR" ), @@ -337,8 +345,9 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { // Adicionar resumo na segunda aba const resumoData = [ - { Métrica: "Total de Registros", Valor: data.length }, + { Métrica: "Total de Registros", Valor: filteredData.length }, { Métrica: "Valor Total", Valor: totalValor }, + { Métrica: "Filtros Aplicados", Valor: columnFilters.length > 0 || globalFilter ? "Sim" : "Não" }, ]; const wsResumo = XLSX.utils.json_to_sheet(resumoData); @@ -349,7 +358,8 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { // Gerar nome do arquivo com data e hora const now = new Date(); const timestamp = now.toISOString().slice(0, 19).replace(/:/g, "-"); - const fileName = `analitico_${timestamp}.xlsx`; + const hasFilters = columnFilters.length > 0 || globalFilter; + const fileName = `analitico${hasFilters ? '_filtrado' : ''}_${timestamp}.xlsx`; // Fazer download XLSX.writeFile(wb, fileName); From 379523824f4f5047b27989b81345efe200bac8a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alessandro=20Gon=C3=A7aalves?= Date: Mon, 20 Oct 2025 17:56:42 -0300 Subject: [PATCH 12/30] fix: ajuste na coluna de % --- src/app/DRE/teste.tsx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/app/DRE/teste.tsx b/src/app/DRE/teste.tsx index 77fb086..e2eed63 100644 --- a/src/app/DRE/teste.tsx +++ b/src/app/DRE/teste.tsx @@ -709,9 +709,9 @@ export default function Teste() {
Descrição
{mesesDisponiveis.map((mes) => ( -
-
{mes}
-
+
+
{mes}
+
%
@@ -736,9 +736,9 @@ export default function Teste() { {renderCellContent(row)}
{mesesDisponiveis.map((mes) => ( -
+
handleRowClick(row, mes)} title={ row.valoresPorMes && row.valoresPorMes[mes] @@ -765,7 +765,7 @@ export default function Teste() { : "-"}
handleRowClick(row, mes)} title={ row.percentuaisPorMes && From 6d0a3f0830ea0eb30039cb252c7645704bba9c50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alessandro=20Gon=C3=A7aalves?= Date: Mon, 20 Oct 2025 18:05:59 -0300 Subject: [PATCH 13/30] fix: ajuste na largura da tabela --- src/app/DRE/analitico.tsx | 2 +- src/app/DRE/teste.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app/DRE/analitico.tsx b/src/app/DRE/analitico.tsx index 6984ba8..66150e3 100644 --- a/src/app/DRE/analitico.tsx +++ b/src/app/DRE/analitico.tsx @@ -366,7 +366,7 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { }; return ( -
+
{/* Header Section */}
diff --git a/src/app/DRE/teste.tsx b/src/app/DRE/teste.tsx index e2eed63..b851a4b 100644 --- a/src/app/DRE/teste.tsx +++ b/src/app/DRE/teste.tsx @@ -674,7 +674,7 @@ export default function Teste() { const hierarchicalData = buildHierarchicalData(); return ( -
+
{/* Header Section */}
From 4d566696e294c0ad4ada6d43e5ea49977e21c2e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alessandro=20Gon=C3=A7aalves?= Date: Mon, 20 Oct 2025 18:09:03 -0300 Subject: [PATCH 14/30] fix: troca dos emojs por icons --- src/app/DRE/teste.tsx | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/src/app/DRE/teste.tsx b/src/app/DRE/teste.tsx index b851a4b..4df3065 100644 --- a/src/app/DRE/teste.tsx +++ b/src/app/DRE/teste.tsx @@ -1,6 +1,6 @@ "use client"; -import { LoaderPinwheel } from "lucide-react"; +import { LoaderPinwheel, ChevronDown, ChevronRight } from "lucide-react"; import { useEffect, useState } from "react"; import AnaliticoComponent from "./analitico"; @@ -488,9 +488,11 @@ export default function Teste() { onClick={() => toggleGroup(row.grupo!)} className="p-2 hover:bg-blue-100 rounded-lg transition-all duration-200 flex items-center justify-center w-8 h-8 flex-shrink-0" > - - {row.isExpanded ? "▼" : "▶"} - + {row.isExpanded ? ( + + ) : ( + + )} )} - {data.length > 0 && ( - - )} + > + + Exportar XLSX + + )}
@@ -472,23 +495,39 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { {/* Table Header */}
-
Data de Vencimento
+
+ Data de Vencimento +
Data de Caixa
Entidade
-
Código do Fornecedor
-
Nome do Fornecedor
+
+ Código do Fornecedor +
+
+ Nome do Fornecedor +
Centro de Custo
Código da Conta
Nome da Conta
-
Valor Realizado
-
Valor Previsto
-
Valor Confirmado
-
Valor Pago
+
+ Valor Realizado +
+
+ Valor Previsto +
+
+ Valor Confirmado +
+
+ Valor Pago +
Histórico
Histórico 2
-
Número do Lançamento
+
+ Número do Lançamento +
+
-
{/* Table Body */}

Carregando dados...

-
-
+
+
) : virtualRows.length === 0 ? (
@@ -523,10 +562,10 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" /> -
+

Nenhum dado encontrado

-
-
+
+
) : (
+
{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} -
+
-
-
-
-
-
-
-
+
+
+ - +
+
+ - +
+
+ - +
+
{row.original.historico} -
-
+
+
{row.original.historico2} -
-
-
-
+ +
+ - +
+ ); })} - + )} + + + {/* Footer com Totalizador das Colunas */} + {data.length > 0 && ( +
+
+
+ TOTAL: {table.getRowModel().rows.length} registros
+
+
+
+
+
+
+
+
+ {new Intl.NumberFormat("pt-BR", { + style: "currency", + currency: "BRL", + }).format(columnTotals.valorRealizado)} +
+
+ - +
+
+ - +
+
+ - +
+
+
+
+
+
+ )} {/* Summary Footer - Integrado */} - {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 -

-
-
-
- )} + { + // 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 + //

+ //
+ //
+ //
+ // ) + } @@ -698,7 +782,7 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { ))} - +
+ {!( cond.operator === "empty" || cond.operator === "notEmpty" @@ -745,7 +829,7 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { placeholder="Digite o valor" className="w-full bg-white border-gray-300" /> - + )} {conditions.length > 1 && ( @@ -761,8 +845,8 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { > ✕ - - )} + + )} ))} From bda93d2705923ac202419a408e638bf48c4ecf44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alessandro=20Gon=C3=A7aalves?= Date: Mon, 20 Oct 2025 23:04:42 -0300 Subject: [PATCH 17/30] =?UTF-8?q?fix:=20corre=C3=A7=C3=A3o=20postgress?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package-lock.json | 2083 ++++++++++++++++++++++--------------- package.json | 5 +- postcss.config.js | 6 + postcss.config.mjs | 5 - src/app/DRE/analitico.tsx | 76 +- src/app/globals.css | 117 +-- tailwind.config.js | 54 + 7 files changed, 1401 insertions(+), 945 deletions(-) create mode 100644 postcss.config.js delete mode 100644 postcss.config.mjs create mode 100644 tailwind.config.js diff --git a/package-lock.json b/package-lock.json index 5d3a6f3..7870943 100644 --- a/package-lock.json +++ b/package-lock.json @@ -27,16 +27,17 @@ }, "devDependencies": { "@eslint/eslintrc": "^3", - "@tailwindcss/postcss": "^4", "@types/node": "^20", "@types/pg": "^8.15.5", "@types/react": "^19", "@types/react-dom": "^19", "@types/xlsx": "^0.0.35", + "autoprefixer": "^10.4.21", "drizzle-kit": "^0.31.5", "eslint": "^9", "eslint-config-next": "15.5.4", - "tailwindcss": "^4", + "postcss": "^8.5.6", + "tailwindcss": "^3.4.18", "tsx": "^4.20.6", "tw-animate-css": "^1.4.0", "typescript": "^5" @@ -532,9 +533,9 @@ } }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.10.tgz", - "integrity": "sha512-0NFWnA+7l41irNuaSVlLfgNT12caWJVLzp5eAVhZ0z1qpxbockccEt3s+149rE64VUI3Ml2zt8Nv5JVc4QXTsw==", + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.11.tgz", + "integrity": "sha512-Xt1dOL13m8u0WE8iplx9Ibbm+hFAO0GsU2P34UNoDGvZYkY8ifSiy6Zuc1lYxfG7svWE2fzqCUmFp5HCn51gJg==", "cpu": [ "ppc64" ], @@ -549,9 +550,9 @@ } }, "node_modules/@esbuild/android-arm": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.10.tgz", - "integrity": "sha512-dQAxF1dW1C3zpeCDc5KqIYuZ1tgAdRXNoZP7vkBIRtKZPYe2xVr/d3SkirklCHudW1B45tGiUlz2pUWDfbDD4w==", + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.11.tgz", + "integrity": "sha512-uoa7dU+Dt3HYsethkJ1k6Z9YdcHjTrSb5NUy66ZfZaSV8hEYGD5ZHbEMXnqLFlbBflLsl89Zke7CAdDJ4JI+Gg==", "cpu": [ "arm" ], @@ -566,9 +567,9 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.10.tgz", - "integrity": "sha512-LSQa7eDahypv/VO6WKohZGPSJDq5OVOo3UoFR1E4t4Gj1W7zEQMUhI+lo81H+DtB+kP+tDgBp+M4oNCwp6kffg==", + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.11.tgz", + "integrity": "sha512-9slpyFBc4FPPz48+f6jyiXOx/Y4v34TUeDDXJpZqAWQn/08lKGeD8aDp9TMn9jDz2CiEuHwfhRmGBvpnd/PWIQ==", "cpu": [ "arm64" ], @@ -583,9 +584,9 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.10.tgz", - "integrity": "sha512-MiC9CWdPrfhibcXwr39p9ha1x0lZJ9KaVfvzA0Wxwz9ETX4v5CHfF09bx935nHlhi+MxhA63dKRRQLiVgSUtEg==", + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.11.tgz", + "integrity": "sha512-Sgiab4xBjPU1QoPEIqS3Xx+R2lezu0LKIEcYe6pftr56PqPygbB7+szVnzoShbx64MUupqoE0KyRlN7gezbl8g==", "cpu": [ "x64" ], @@ -600,9 +601,9 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.10.tgz", - "integrity": "sha512-JC74bdXcQEpW9KkV326WpZZjLguSZ3DfS8wrrvPMHgQOIEIG/sPXEN/V8IssoJhbefLRcRqw6RQH2NnpdprtMA==", + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.11.tgz", + "integrity": "sha512-VekY0PBCukppoQrycFxUqkCojnTQhdec0vevUL/EDOCnXd9LKWqD/bHwMPzigIJXPhC59Vd1WFIL57SKs2mg4w==", "cpu": [ "arm64" ], @@ -617,9 +618,9 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.10.tgz", - "integrity": "sha512-tguWg1olF6DGqzws97pKZ8G2L7Ig1vjDmGTwcTuYHbuU6TTjJe5FXbgs5C1BBzHbJ2bo1m3WkQDbWO2PvamRcg==", + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.11.tgz", + "integrity": "sha512-+hfp3yfBalNEpTGp9loYgbknjR695HkqtY3d3/JjSRUyPg/xd6q+mQqIb5qdywnDxRZykIHs3axEqU6l1+oWEQ==", "cpu": [ "x64" ], @@ -634,9 +635,9 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.10.tgz", - "integrity": "sha512-3ZioSQSg1HT2N05YxeJWYR+Libe3bREVSdWhEEgExWaDtyFbbXWb49QgPvFH8u03vUPX10JhJPcz7s9t9+boWg==", + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.11.tgz", + "integrity": "sha512-CmKjrnayyTJF2eVuO//uSjl/K3KsMIeYeyN7FyDBjsR3lnSJHaXlVoAK8DZa7lXWChbuOk7NjAc7ygAwrnPBhA==", "cpu": [ "arm64" ], @@ -651,9 +652,9 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.10.tgz", - "integrity": "sha512-LLgJfHJk014Aa4anGDbh8bmI5Lk+QidDmGzuC2D+vP7mv/GeSN+H39zOf7pN5N8p059FcOfs2bVlrRr4SK9WxA==", + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.11.tgz", + "integrity": "sha512-Dyq+5oscTJvMaYPvW3x3FLpi2+gSZTCE/1ffdwuM6G1ARang/mb3jvjxs0mw6n3Lsw84ocfo9CrNMqc5lTfGOw==", "cpu": [ "x64" ], @@ -668,9 +669,9 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.10.tgz", - "integrity": "sha512-oR31GtBTFYCqEBALI9r6WxoU/ZofZl962pouZRTEYECvNF/dtXKku8YXcJkhgK/beU+zedXfIzHijSRapJY3vg==", + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.11.tgz", + "integrity": "sha512-TBMv6B4kCfrGJ8cUPo7vd6NECZH/8hPpBHHlYI3qzoYFvWu2AdTvZNuU/7hsbKWqu/COU7NIK12dHAAqBLLXgw==", "cpu": [ "arm" ], @@ -685,9 +686,9 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.10.tgz", - "integrity": "sha512-5luJWN6YKBsawd5f9i4+c+geYiVEw20FVW5x0v1kEMWNq8UctFjDiMATBxLvmmHA4bf7F6hTRaJgtghFr9iziQ==", + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.11.tgz", + "integrity": "sha512-Qr8AzcplUhGvdyUF08A1kHU3Vr2O88xxP0Tm8GcdVOUm25XYcMPp2YqSVHbLuXzYQMf9Bh/iKx7YPqECs6ffLA==", "cpu": [ "arm64" ], @@ -702,9 +703,9 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.10.tgz", - "integrity": "sha512-NrSCx2Kim3EnnWgS4Txn0QGt0Xipoumb6z6sUtl5bOEZIVKhzfyp/Lyw4C1DIYvzeW/5mWYPBFJU3a/8Yr75DQ==", + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.11.tgz", + "integrity": "sha512-TmnJg8BMGPehs5JKrCLqyWTVAvielc615jbkOirATQvWWB1NMXY77oLMzsUjRLa0+ngecEmDGqt5jiDC6bfvOw==", "cpu": [ "ia32" ], @@ -719,9 +720,9 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.10.tgz", - "integrity": "sha512-xoSphrd4AZda8+rUDDfD9J6FUMjrkTz8itpTITM4/xgerAZZcFW7Dv+sun7333IfKxGG8gAq+3NbfEMJfiY+Eg==", + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.11.tgz", + "integrity": "sha512-DIGXL2+gvDaXlaq8xruNXUJdT5tF+SBbJQKbWy/0J7OhU8gOHOzKmGIlfTTl6nHaCOoipxQbuJi7O++ldrxgMw==", "cpu": [ "loong64" ], @@ -736,9 +737,9 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.10.tgz", - "integrity": "sha512-ab6eiuCwoMmYDyTnyptoKkVS3k8fy/1Uvq7Dj5czXI6DF2GqD2ToInBI0SHOp5/X1BdZ26RKc5+qjQNGRBelRA==", + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.11.tgz", + "integrity": "sha512-Osx1nALUJu4pU43o9OyjSCXokFkFbyzjXb6VhGIJZQ5JZi8ylCQ9/LFagolPsHtgw6himDSyb5ETSfmp4rpiKQ==", "cpu": [ "mips64el" ], @@ -753,9 +754,9 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.10.tgz", - "integrity": "sha512-NLinzzOgZQsGpsTkEbdJTCanwA5/wozN9dSgEl12haXJBzMTpssebuXR42bthOF3z7zXFWH1AmvWunUCkBE4EA==", + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.11.tgz", + "integrity": "sha512-nbLFgsQQEsBa8XSgSTSlrnBSrpoWh7ioFDUmwo158gIm5NNP+17IYmNWzaIzWmgCxq56vfr34xGkOcZ7jX6CPw==", "cpu": [ "ppc64" ], @@ -770,9 +771,9 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.10.tgz", - "integrity": "sha512-FE557XdZDrtX8NMIeA8LBJX3dC2M8VGXwfrQWU7LB5SLOajfJIxmSdyL/gU1m64Zs9CBKvm4UAuBp5aJ8OgnrA==", + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.11.tgz", + "integrity": "sha512-HfyAmqZi9uBAbgKYP1yGuI7tSREXwIb438q0nqvlpxAOs3XnZ8RsisRfmVsgV486NdjD7Mw2UrFSw51lzUk1ww==", "cpu": [ "riscv64" ], @@ -787,9 +788,9 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.10.tgz", - "integrity": "sha512-3BBSbgzuB9ajLoVZk0mGu+EHlBwkusRmeNYdqmznmMc9zGASFjSsxgkNsqmXugpPk00gJ0JNKh/97nxmjctdew==", + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.11.tgz", + "integrity": "sha512-HjLqVgSSYnVXRisyfmzsH6mXqyvj0SA7pG5g+9W7ESgwA70AXYNpfKBqh1KbTxmQVaYxpzA/SvlB9oclGPbApw==", "cpu": [ "s390x" ], @@ -804,9 +805,9 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.10.tgz", - "integrity": "sha512-QSX81KhFoZGwenVyPoberggdW1nrQZSvfVDAIUXr3WqLRZGZqWk/P4T8p2SP+de2Sr5HPcvjhcJzEiulKgnxtA==", + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.11.tgz", + "integrity": "sha512-HSFAT4+WYjIhrHxKBwGmOOSpphjYkcswF449j6EjsjbinTZbp8PJtjsVK1XFJStdzXdy/jaddAep2FGY+wyFAQ==", "cpu": [ "x64" ], @@ -821,9 +822,9 @@ } }, "node_modules/@esbuild/netbsd-arm64": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.10.tgz", - "integrity": "sha512-AKQM3gfYfSW8XRk8DdMCzaLUFB15dTrZfnX8WXQoOUpUBQ+NaAFCP1kPS/ykbbGYz7rxn0WS48/81l9hFl3u4A==", + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.11.tgz", + "integrity": "sha512-hr9Oxj1Fa4r04dNpWr3P8QKVVsjQhqrMSUzZzf+LZcYjZNqhA3IAfPQdEh1FLVUJSiu6sgAwp3OmwBfbFgG2Xg==", "cpu": [ "arm64" ], @@ -838,9 +839,9 @@ } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.10.tgz", - "integrity": "sha512-7RTytDPGU6fek/hWuN9qQpeGPBZFfB4zZgcz2VK2Z5VpdUxEI8JKYsg3JfO0n/Z1E/6l05n0unDCNc4HnhQGig==", + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.11.tgz", + "integrity": "sha512-u7tKA+qbzBydyj0vgpu+5h5AeudxOAGncb8N6C9Kh1N4n7wU1Xw1JDApsRjpShRpXRQlJLb9wY28ELpwdPcZ7A==", "cpu": [ "x64" ], @@ -855,9 +856,9 @@ } }, "node_modules/@esbuild/openbsd-arm64": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.10.tgz", - "integrity": "sha512-5Se0VM9Wtq797YFn+dLimf2Zx6McttsH2olUBsDml+lm0GOCRVebRWUvDtkY4BWYv/3NgzS8b/UM3jQNh5hYyw==", + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.11.tgz", + "integrity": "sha512-Qq6YHhayieor3DxFOoYM1q0q1uMFYb7cSpLD2qzDSvK1NAvqFi8Xgivv0cFC6J+hWVw2teCYltyy9/m/14ryHg==", "cpu": [ "arm64" ], @@ -872,9 +873,9 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.10.tgz", - "integrity": "sha512-XkA4frq1TLj4bEMB+2HnI0+4RnjbuGZfet2gs/LNs5Hc7D89ZQBHQ0gL2ND6Lzu1+QVkjp3x1gIcPKzRNP8bXw==", + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.11.tgz", + "integrity": "sha512-CN+7c++kkbrckTOz5hrehxWN7uIhFFlmS/hqziSFVWpAzpWrQoAG4chH+nN3Be+Kzv/uuo7zhX716x3Sn2Jduw==", "cpu": [ "x64" ], @@ -889,9 +890,9 @@ } }, "node_modules/@esbuild/openharmony-arm64": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.10.tgz", - "integrity": "sha512-AVTSBhTX8Y/Fz6OmIVBip9tJzZEUcY8WLh7I59+upa5/GPhh2/aM6bvOMQySspnCCHvFi79kMtdJS1w0DXAeag==", + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.11.tgz", + "integrity": "sha512-rOREuNIQgaiR+9QuNkbkxubbp8MSO9rONmwP5nKncnWJ9v5jQ4JxFnLu4zDSRPf3x4u+2VN4pM4RdyIzDty/wQ==", "cpu": [ "arm64" ], @@ -906,9 +907,9 @@ } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.10.tgz", - "integrity": "sha512-fswk3XT0Uf2pGJmOpDB7yknqhVkJQkAQOcW/ccVOtfx05LkbWOaRAtn5SaqXypeKQra1QaEa841PgrSL9ubSPQ==", + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.11.tgz", + "integrity": "sha512-nq2xdYaWxyg9DcIyXkZhcYulC6pQ2FuCgem3LI92IwMgIZ69KHeY8T4Y88pcwoLIjbed8n36CyKoYRDygNSGhA==", "cpu": [ "x64" ], @@ -923,9 +924,9 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.10.tgz", - "integrity": "sha512-ah+9b59KDTSfpaCg6VdJoOQvKjI33nTaQr4UluQwW7aEwZQsbMCfTmfEO4VyewOxx4RaDT/xCy9ra2GPWmO7Kw==", + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.11.tgz", + "integrity": "sha512-3XxECOWJq1qMZ3MN8srCJ/QfoLpL+VaxD/WfNRm1O3B4+AZ/BnLVgFbUV3eiRYDMXetciH16dwPbbHqwe1uU0Q==", "cpu": [ "arm64" ], @@ -940,9 +941,9 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.10.tgz", - "integrity": "sha512-QHPDbKkrGO8/cz9LKVnJU22HOi4pxZnZhhA2HYHez5Pz4JeffhDjf85E57Oyco163GnzNCVkZK0b/n4Y0UHcSw==", + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.11.tgz", + "integrity": "sha512-3ukss6gb9XZ8TlRyJlgLn17ecsK4NSQTmdIXRASVsiS2sQ6zPPZklNJT5GR5tE/MUarymmy8kCEf5xPCNCqVOA==", "cpu": [ "ia32" ], @@ -957,9 +958,9 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.10.tgz", - "integrity": "sha512-9KpxSVFCu0iK1owoez6aC/s/EdUQLDN3adTxGCqxMVhrPDj6bt5dbrHDXUuq+Bs2vATFBBrQS5vdQ/Ed2P+nbw==", + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.11.tgz", + "integrity": "sha512-D7Hpz6A2L4hzsRpPaCYkQnGOotdUpDzSGRIv9I+1ITdHROSFUWW95ZPZWQmGka1Fg7W3zFJowyn9WGwMJ0+KPA==", "cpu": [ "x64" ], @@ -1016,13 +1017,13 @@ } }, "node_modules/@eslint/config-array": { - "version": "0.21.0", - "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.0.tgz", - "integrity": "sha512-ENIdc4iLu0d93HeYirvKmrzshzofPw6VkZRKQGe9Nv46ZnWUzcF1xV01dcvEg/1wXUR61OmmlSfyeyO7EvjLxQ==", + "version": "0.21.1", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.1.tgz", + "integrity": "sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@eslint/object-schema": "^2.1.6", + "@eslint/object-schema": "^2.1.7", "debug": "^4.3.1", "minimatch": "^3.1.2" }, @@ -1031,9 +1032,9 @@ } }, "node_modules/@eslint/config-helpers": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.0.tgz", - "integrity": "sha512-WUFvV4WoIwW8Bv0KeKCIIEgdSiFOsulyN0xrMu+7z43q/hkOLXjvb5u7UC9jDxvRzcrbEmuZBX5yJZz1741jog==", + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.1.tgz", + "integrity": "sha512-csZAzkNhsgwb0I/UAV6/RGFTbiakPCf0ZrGmrIxQpYvGZ00PhTkSnyKNolphgIvmnJeGw6rcGVEXfTzUnFuEvw==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -1081,9 +1082,9 @@ } }, "node_modules/@eslint/js": { - "version": "9.37.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.37.0.tgz", - "integrity": "sha512-jaS+NJ+hximswBG6pjNX0uEJZkrT0zwpVi3BA3vX22aFGjJjmgSTSmPpZCRKmoBL5VY/M6p0xsSJx7rk7sy5gg==", + "version": "9.38.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.38.0.tgz", + "integrity": "sha512-UZ1VpFvXf9J06YG9xQBdnzU+kthors6KjhMAl6f4gH4usHyh31rUf2DLGInT8RFYIReYXNSydgPY0V2LuWgl7A==", "dev": true, "license": "MIT", "engines": { @@ -1094,9 +1095,9 @@ } }, "node_modules/@eslint/object-schema": { - "version": "2.1.6", - "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.6.tgz", - "integrity": "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==", + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.7.tgz", + "integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==", "dev": true, "license": "Apache-2.0", "engines": { @@ -1635,17 +1636,22 @@ "url": "https://opencollective.com/libvips" } }, - "node_modules/@isaacs/fs-minipass": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz", - "integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==", + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", "dev": true, "license": "ISC", "dependencies": { - "minipass": "^7.0.4" + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" }, "engines": { - "node": ">=18.0.0" + "node": ">=12" } }, "node_modules/@jridgewell/gen-mapping": { @@ -1659,17 +1665,6 @@ "@jridgewell/trace-mapping": "^0.3.24" } }, - "node_modules/@jridgewell/remapping": { - "version": "2.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", - "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.24" - } - }, "node_modules/@jridgewell/resolve-uri": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", @@ -1839,22 +1834,6 @@ "node": ">= 10" } }, - "node_modules/@next/swc-win32-x64-msvc": { - "version": "15.5.4", - "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-15.5.4.tgz", - "integrity": "sha512-1ur2tSHZj8Px/KMAthmuI9FMp/YFusMMGoRNJaRZMOlSkgvLjzosSdQI0cJAKogdHl3qXUQKL9MGaYvKwA7DXg==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -1903,6 +1882,17 @@ "node": ">=12.4.0" } }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14" + } + }, "node_modules/@radix-ui/number": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@radix-ui/number/-/number-1.1.1.tgz", @@ -2467,9 +2457,9 @@ "license": "MIT" }, "node_modules/@rushstack/eslint-patch": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.13.0.tgz", - "integrity": "sha512-2ih5qGw5SZJ+2fLZxP6Lr6Na2NTIgPRL/7Kmyuw0uIyBQnuhQ8fi8fzUTd38eIQmqp+GYLC00cI6WgtqHxBwmw==", + "version": "1.14.0", + "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.14.0.tgz", + "integrity": "sha512-WJFej426qe4RWOm9MMtP4V3CV4AucXolQty+GRgAWLgQXmpCuwzs7hEpxxhSc/znXUSxum9d/P/32MW0FlAAlA==", "dev": true, "license": "MIT" }, @@ -2482,282 +2472,6 @@ "tslib": "^2.8.0" } }, - "node_modules/@tailwindcss/node": { - "version": "4.1.14", - "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.1.14.tgz", - "integrity": "sha512-hpz+8vFk3Ic2xssIA3e01R6jkmsAhvkQdXlEbRTk6S10xDAtiQiM3FyvZVGsucefq764euO/b8WUW9ysLdThHw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/remapping": "^2.3.4", - "enhanced-resolve": "^5.18.3", - "jiti": "^2.6.0", - "lightningcss": "1.30.1", - "magic-string": "^0.30.19", - "source-map-js": "^1.2.1", - "tailwindcss": "4.1.14" - } - }, - "node_modules/@tailwindcss/oxide": { - "version": "4.1.14", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.1.14.tgz", - "integrity": "sha512-23yx+VUbBwCg2x5XWdB8+1lkPajzLmALEfMb51zZUBYaYVPDQvBSD/WYDqiVyBIo2BZFa3yw1Rpy3G2Jp+K0dw==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "dependencies": { - "detect-libc": "^2.0.4", - "tar": "^7.5.1" - }, - "engines": { - "node": ">= 10" - }, - "optionalDependencies": { - "@tailwindcss/oxide-android-arm64": "4.1.14", - "@tailwindcss/oxide-darwin-arm64": "4.1.14", - "@tailwindcss/oxide-darwin-x64": "4.1.14", - "@tailwindcss/oxide-freebsd-x64": "4.1.14", - "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.14", - "@tailwindcss/oxide-linux-arm64-gnu": "4.1.14", - "@tailwindcss/oxide-linux-arm64-musl": "4.1.14", - "@tailwindcss/oxide-linux-x64-gnu": "4.1.14", - "@tailwindcss/oxide-linux-x64-musl": "4.1.14", - "@tailwindcss/oxide-wasm32-wasi": "4.1.14", - "@tailwindcss/oxide-win32-arm64-msvc": "4.1.14", - "@tailwindcss/oxide-win32-x64-msvc": "4.1.14" - } - }, - "node_modules/@tailwindcss/oxide-android-arm64": { - "version": "4.1.14", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.1.14.tgz", - "integrity": "sha512-a94ifZrGwMvbdeAxWoSuGcIl6/DOP5cdxagid7xJv6bwFp3oebp7y2ImYsnZBMTwjn5Ev5xESvS3FFYUGgPODQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tailwindcss/oxide-darwin-arm64": { - "version": "4.1.14", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.1.14.tgz", - "integrity": "sha512-HkFP/CqfSh09xCnrPJA7jud7hij5ahKyWomrC3oiO2U9i0UjP17o9pJbxUN0IJ471GTQQmzwhp0DEcpbp4MZTA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tailwindcss/oxide-darwin-x64": { - "version": "4.1.14", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.1.14.tgz", - "integrity": "sha512-eVNaWmCgdLf5iv6Qd3s7JI5SEFBFRtfm6W0mphJYXgvnDEAZ5sZzqmI06bK6xo0IErDHdTA5/t7d4eTfWbWOFw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tailwindcss/oxide-freebsd-x64": { - "version": "4.1.14", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.1.14.tgz", - "integrity": "sha512-QWLoRXNikEuqtNb0dhQN6wsSVVjX6dmUFzuuiL09ZeXju25dsei2uIPl71y2Ic6QbNBsB4scwBoFnlBfabHkEw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": { - "version": "4.1.14", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.1.14.tgz", - "integrity": "sha512-VB4gjQni9+F0VCASU+L8zSIyjrLLsy03sjcR3bM0V2g4SNamo0FakZFKyUQ96ZVwGK4CaJsc9zd/obQy74o0Fw==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tailwindcss/oxide-linux-arm64-gnu": { - "version": "4.1.14", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.1.14.tgz", - "integrity": "sha512-qaEy0dIZ6d9vyLnmeg24yzA8XuEAD9WjpM5nIM1sUgQ/Zv7cVkharPDQcmm/t/TvXoKo/0knI3me3AGfdx6w1w==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tailwindcss/oxide-linux-arm64-musl": { - "version": "4.1.14", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.1.14.tgz", - "integrity": "sha512-ISZjT44s59O8xKsPEIesiIydMG/sCXoMBCqsphDm/WcbnuWLxxb+GcvSIIA5NjUw6F8Tex7s5/LM2yDy8RqYBQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tailwindcss/oxide-linux-x64-gnu": { - "version": "4.1.14", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.1.14.tgz", - "integrity": "sha512-02c6JhLPJj10L2caH4U0zF8Hji4dOeahmuMl23stk0MU1wfd1OraE7rOloidSF8W5JTHkFdVo/O7uRUJJnUAJg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tailwindcss/oxide-linux-x64-musl": { - "version": "4.1.14", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.1.14.tgz", - "integrity": "sha512-TNGeLiN1XS66kQhxHG/7wMeQDOoL0S33x9BgmydbrWAb9Qw0KYdd8o1ifx4HOGDWhVmJ+Ul+JQ7lyknQFilO3Q==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tailwindcss/oxide-wasm32-wasi": { - "version": "4.1.14", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.1.14.tgz", - "integrity": "sha512-uZYAsaW/jS/IYkd6EWPJKW/NlPNSkWkBlaeVBi/WsFQNP05/bzkebUL8FH1pdsqx4f2fH/bWFcUABOM9nfiJkQ==", - "bundleDependencies": [ - "@napi-rs/wasm-runtime", - "@emnapi/core", - "@emnapi/runtime", - "@tybys/wasm-util", - "@emnapi/wasi-threads", - "tslib" - ], - "cpu": [ - "wasm32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "@emnapi/core": "^1.5.0", - "@emnapi/runtime": "^1.5.0", - "@emnapi/wasi-threads": "^1.1.0", - "@napi-rs/wasm-runtime": "^1.0.5", - "@tybys/wasm-util": "^0.10.1", - "tslib": "^2.4.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { - "version": "4.1.14", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.1.14.tgz", - "integrity": "sha512-Az0RnnkcvRqsuoLH2Z4n3JfAef0wElgzHD5Aky/e+0tBUxUhIeIqFBTMNQvmMRSP15fWwmvjBxZ3Q8RhsDnxAA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tailwindcss/oxide-win32-x64-msvc": { - "version": "4.1.14", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.1.14.tgz", - "integrity": "sha512-ttblVGHgf68kEE4om1n/n44I0yGPkCPbLsqzjvybhpwa6mKKtgFfAzy6btc3HRmuW7nHe0OOrSeNP9sQmmH9XA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tailwindcss/postcss": { - "version": "4.1.14", - "resolved": "https://registry.npmjs.org/@tailwindcss/postcss/-/postcss-4.1.14.tgz", - "integrity": "sha512-BdMjIxy7HUNThK87C7BC8I1rE8BVUsfNQSI5siQ4JK3iIa3w0XyVvVL9SXLWO//CtYTcp1v7zci0fYwJOjB+Zg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@alloc/quick-lru": "^5.2.0", - "@tailwindcss/node": "4.1.14", - "@tailwindcss/oxide": "4.1.14", - "postcss": "^8.4.41", - "tailwindcss": "4.1.14" - } - }, "node_modules/@tanstack/react-table": { "version": "8.21.3", "resolved": "https://registry.npmjs.org/@tanstack/react-table/-/react-table-8.21.3.tgz", @@ -2851,9 +2565,9 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "20.19.19", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.19.tgz", - "integrity": "sha512-pb1Uqj5WJP7wrcbLU7Ru4QtA0+3kAXrkutGiD26wUKzSMgNNaPARTUDQmElUXp64kh3cWdou3Q0C7qwwxqSFmg==", + "version": "20.19.23", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.23.tgz", + "integrity": "sha512-yIdlVVVHXpmqRhtyovZAcSy0MiPcYWGkoO4CGe/+jpP0hmNuihm4XhHbADpK++MsiLHP5MVlv+bcgdF99kSiFQ==", "devOptional": true, "license": "MIT", "dependencies": { @@ -2883,9 +2597,9 @@ } }, "node_modules/@types/react-dom": { - "version": "19.2.1", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.1.tgz", - "integrity": "sha512-/EEvYBdT3BflCWvTMO7YkYBHVE9Ci6XdqZciZANQgKpaiDRGOLIlRo91jbTNRQjgPFWVaRxcYc0luVNFitz57A==", + "version": "19.2.2", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.2.tgz", + "integrity": "sha512-9KQPoO6mZCi7jcIStSnlOWn2nEF3mNmyr3rIAsGnAbQKYbRLyqmeSc39EVgtxXVia+LMT8j3knZLAZAh+xLmrw==", "devOptional": true, "license": "MIT", "peerDependencies": { @@ -2900,17 +2614,17 @@ "license": "MIT" }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.46.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.46.0.tgz", - "integrity": "sha512-hA8gxBq4ukonVXPy0OKhiaUh/68D0E88GSmtC1iAEnGaieuDi38LhS7jdCHRLi6ErJBNDGCzvh5EnzdPwUc0DA==", + "version": "8.46.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.46.2.tgz", + "integrity": "sha512-ZGBMToy857/NIPaaCucIUQgqueOiq7HeAKkhlvqVV4lm089zUFW6ikRySx2v+cAhKeUCPuWVHeimyk6Dw1iY3w==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.46.0", - "@typescript-eslint/type-utils": "8.46.0", - "@typescript-eslint/utils": "8.46.0", - "@typescript-eslint/visitor-keys": "8.46.0", + "@typescript-eslint/scope-manager": "8.46.2", + "@typescript-eslint/type-utils": "8.46.2", + "@typescript-eslint/utils": "8.46.2", + "@typescript-eslint/visitor-keys": "8.46.2", "graphemer": "^1.4.0", "ignore": "^7.0.0", "natural-compare": "^1.4.0", @@ -2924,7 +2638,7 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^8.46.0", + "@typescript-eslint/parser": "^8.46.2", "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } @@ -2940,16 +2654,16 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "8.46.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.46.0.tgz", - "integrity": "sha512-n1H6IcDhmmUEG7TNVSspGmiHHutt7iVKtZwRppD7e04wha5MrkV1h3pti9xQLcCMt6YWsncpoT0HMjkH1FNwWQ==", + "version": "8.46.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.46.2.tgz", + "integrity": "sha512-BnOroVl1SgrPLywqxyqdJ4l3S2MsKVLDVxZvjI1Eoe8ev2r3kGDo+PcMihNmDE+6/KjkTubSJnmqGZZjQSBq/g==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/scope-manager": "8.46.0", - "@typescript-eslint/types": "8.46.0", - "@typescript-eslint/typescript-estree": "8.46.0", - "@typescript-eslint/visitor-keys": "8.46.0", + "@typescript-eslint/scope-manager": "8.46.2", + "@typescript-eslint/types": "8.46.2", + "@typescript-eslint/typescript-estree": "8.46.2", + "@typescript-eslint/visitor-keys": "8.46.2", "debug": "^4.3.4" }, "engines": { @@ -2965,14 +2679,14 @@ } }, "node_modules/@typescript-eslint/project-service": { - "version": "8.46.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.46.0.tgz", - "integrity": "sha512-OEhec0mH+U5Je2NZOeK1AbVCdm0ChyapAyTeXVIYTPXDJ3F07+cu87PPXcGoYqZ7M9YJVvFnfpGg1UmCIqM+QQ==", + "version": "8.46.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.46.2.tgz", + "integrity": "sha512-PULOLZ9iqwI7hXcmL4fVfIsBi6AN9YxRc0frbvmg8f+4hQAjQ5GYNKK0DIArNo+rOKmR/iBYwkpBmnIwin4wBg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.46.0", - "@typescript-eslint/types": "^8.46.0", + "@typescript-eslint/tsconfig-utils": "^8.46.2", + "@typescript-eslint/types": "^8.46.2", "debug": "^4.3.4" }, "engines": { @@ -2987,14 +2701,14 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.46.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.46.0.tgz", - "integrity": "sha512-lWETPa9XGcBes4jqAMYD9fW0j4n6hrPtTJwWDmtqgFO/4HF4jmdH/Q6wggTw5qIT5TXjKzbt7GsZUBnWoO3dqw==", + "version": "8.46.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.46.2.tgz", + "integrity": "sha512-LF4b/NmGvdWEHD2H4MsHD8ny6JpiVNDzrSZr3CsckEgCbAGZbYM4Cqxvi9L+WqDMT+51Ozy7lt2M+d0JLEuBqA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.46.0", - "@typescript-eslint/visitor-keys": "8.46.0" + "@typescript-eslint/types": "8.46.2", + "@typescript-eslint/visitor-keys": "8.46.2" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -3005,9 +2719,9 @@ } }, "node_modules/@typescript-eslint/tsconfig-utils": { - "version": "8.46.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.46.0.tgz", - "integrity": "sha512-WrYXKGAHY836/N7zoK/kzi6p8tXFhasHh8ocFL9VZSAkvH956gfeRfcnhs3xzRy8qQ/dq3q44v1jvQieMFg2cw==", + "version": "8.46.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.46.2.tgz", + "integrity": "sha512-a7QH6fw4S57+F5y2FIxxSDyi5M4UfGF+Jl1bCGd7+L4KsaUY80GsiF/t0UoRFDHAguKlBaACWJRmdrc6Xfkkag==", "dev": true, "license": "MIT", "engines": { @@ -3022,15 +2736,15 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.46.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.46.0.tgz", - "integrity": "sha512-hy+lvYV1lZpVs2jRaEYvgCblZxUoJiPyCemwbQZ+NGulWkQRy0HRPYAoef/CNSzaLt+MLvMptZsHXHlkEilaeg==", + "version": "8.46.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.46.2.tgz", + "integrity": "sha512-HbPM4LbaAAt/DjxXaG9yiS9brOOz6fabal4uvUmaUYe6l3K1phQDMQKBRUrr06BQkxkvIZVVHttqiybM9nJsLA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.46.0", - "@typescript-eslint/typescript-estree": "8.46.0", - "@typescript-eslint/utils": "8.46.0", + "@typescript-eslint/types": "8.46.2", + "@typescript-eslint/typescript-estree": "8.46.2", + "@typescript-eslint/utils": "8.46.2", "debug": "^4.3.4", "ts-api-utils": "^2.1.0" }, @@ -3047,9 +2761,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "8.46.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.46.0.tgz", - "integrity": "sha512-bHGGJyVjSE4dJJIO5yyEWt/cHyNwga/zXGJbJJ8TiO01aVREK6gCTu3L+5wrkb1FbDkQ+TKjMNe9R/QQQP9+rA==", + "version": "8.46.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.46.2.tgz", + "integrity": "sha512-lNCWCbq7rpg7qDsQrd3D6NyWYu+gkTENkG5IKYhUIcxSb59SQC/hEQ+MrG4sTgBVghTonNWq42bA/d4yYumldQ==", "dev": true, "license": "MIT", "engines": { @@ -3061,16 +2775,16 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.46.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.46.0.tgz", - "integrity": "sha512-ekDCUfVpAKWJbRfm8T1YRrCot1KFxZn21oV76v5Fj4tr7ELyk84OS+ouvYdcDAwZL89WpEkEj2DKQ+qg//+ucg==", + "version": "8.46.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.46.2.tgz", + "integrity": "sha512-f7rW7LJ2b7Uh2EiQ+7sza6RDZnajbNbemn54Ob6fRwQbgcIn+GWfyuHDHRYgRoZu1P4AayVScrRW+YfbTvPQoQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/project-service": "8.46.0", - "@typescript-eslint/tsconfig-utils": "8.46.0", - "@typescript-eslint/types": "8.46.0", - "@typescript-eslint/visitor-keys": "8.46.0", + "@typescript-eslint/project-service": "8.46.2", + "@typescript-eslint/tsconfig-utils": "8.46.2", + "@typescript-eslint/types": "8.46.2", + "@typescript-eslint/visitor-keys": "8.46.2", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", @@ -3146,16 +2860,16 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "8.46.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.46.0.tgz", - "integrity": "sha512-nD6yGWPj1xiOm4Gk0k6hLSZz2XkNXhuYmyIrOWcHoPuAhjT9i5bAG+xbWPgFeNR8HPHHtpNKdYUXJl/D3x7f5g==", + "version": "8.46.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.46.2.tgz", + "integrity": "sha512-sExxzucx0Tud5tE0XqR0lT0psBQvEpnpiul9XbGUB1QwpWJJAps1O/Z7hJxLGiZLBKMCutjTzDgmd1muEhBnVg==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.7.0", - "@typescript-eslint/scope-manager": "8.46.0", - "@typescript-eslint/types": "8.46.0", - "@typescript-eslint/typescript-estree": "8.46.0" + "@typescript-eslint/scope-manager": "8.46.2", + "@typescript-eslint/types": "8.46.2", + "@typescript-eslint/typescript-estree": "8.46.2" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -3170,13 +2884,13 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.46.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.46.0.tgz", - "integrity": "sha512-FrvMpAK+hTbFy7vH5j1+tMYHMSKLE6RzluFJlkFNKD0p9YsUT75JlBSmr5so3QRzvMwU5/bIEdeNrxm8du8l3Q==", + "version": "8.46.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.46.2.tgz", + "integrity": "sha512-tUFMXI4gxzzMXt4xpGJEsBsTox0XbNQ1y94EwlD/CuZwFcQP79xfQqMhau9HsRc/J0cAPA/HZt1dZPtGn9V/7w==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.46.0", + "@typescript-eslint/types": "8.46.2", "eslint-visitor-keys": "^4.2.1" }, "engines": { @@ -3505,6 +3219,19 @@ "url": "https://github.com/sponsors/epoberezkin" } }, + "node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, "node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -3521,6 +3248,34 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", + "dev": true, + "license": "MIT" + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/arg": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", + "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", + "dev": true, + "license": "MIT" + }, "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", @@ -3727,6 +3482,44 @@ "node": ">= 0.4" } }, + "node_modules/autoprefixer": { + "version": "10.4.21", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.21.tgz", + "integrity": "sha512-O+A6LWV5LDHSJD3LjHYoNi4VLsj/Whi7k6zG12xTYaU4cQ8oxQGckXNX8cRHK5yOZ/ppVHe0ZBXGzSV9jXdVbQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/autoprefixer" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "browserslist": "^4.24.4", + "caniuse-lite": "^1.0.30001702", + "fraction.js": "^4.3.7", + "normalize-range": "^0.1.2", + "picocolors": "^1.1.1", + "postcss-value-parser": "^4.2.0" + }, + "bin": { + "autoprefixer": "bin/autoprefixer" + }, + "engines": { + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, "node_modules/available-typed-arrays": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", @@ -3744,9 +3537,9 @@ } }, "node_modules/axe-core": { - "version": "4.10.3", - "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.10.3.tgz", - "integrity": "sha512-Xm7bpRXnDSX2YE2YFfBk2FnF0ep6tmG7xPh8iHee8MIcrgq762Nkce856dYtJYLkuIoYZvGfTs/PbZhideTcEg==", + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.11.0.tgz", + "integrity": "sha512-ilYanEU8vxxBexpJd8cWM4ElSQq4QctCLKih0TSfjIfCQTeyH/6zVrmIJfLPrKTKJRbiG+cfnZbQIjAlJmF1jQ==", "dev": true, "license": "MPL-2.0", "engines": { @@ -3770,6 +3563,29 @@ "dev": true, "license": "MIT" }, + "node_modules/baseline-browser-mapping": { + "version": "2.8.18", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.18.tgz", + "integrity": "sha512-UYmTpOBwgPScZpS4A+YbapwWuBwasxvO/2IOHArSsAhL/+ZdmATBXTex3t+l2hXwLVYK382ibr/nKoY9GKe86w==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.js" + } + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/brace-expansion": { "version": "1.1.12", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", @@ -3794,6 +3610,40 @@ "node": ">=8" } }, + "node_modules/browserslist": { + "version": "4.26.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.26.3.tgz", + "integrity": "sha512-lAUU+02RFBuCKQPj/P6NgjlbCnLBMp4UtgTx7vNHd3XSIJF87s9a5rA3aH2yw3GS9DqZAUbOtZdCCiZeVRqt0w==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "baseline-browser-mapping": "^2.8.9", + "caniuse-lite": "^1.0.30001746", + "electron-to-chromium": "^1.5.227", + "node-releases": "^2.0.21", + "update-browserslist-db": "^1.1.3" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, "node_modules/buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", @@ -3861,10 +3711,20 @@ "node": ">=6" } }, + "node_modules/camelcase-css": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", + "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, "node_modules/caniuse-lite": { - "version": "1.0.30001748", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001748.tgz", - "integrity": "sha512-5P5UgAr0+aBmNiplks08JLw+AW/XG/SurlgZLgB1dDLfAw7EfRGxIwzPHxdSCGY/BTKDqIVyJL87cCN6s0ZR0w==", + "version": "1.0.30001751", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001751.tgz", + "integrity": "sha512-A0QJhug0Ly64Ii3eIqHu5X51ebln3k4yTUkY1j8drqpWHVreg/VLijN48cZ1bYPiqOQuqpkIKnzr/Ul8V+p6Cw==", "funding": [ { "type": "opencollective", @@ -3911,14 +3771,42 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/chownr": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz", - "integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==", + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", "dev": true, - "license": "BlueOak-1.0.0", + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, "engines": { - "node": ">=18" + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" } }, "node_modules/class-variance-authority": { @@ -3977,6 +3865,16 @@ "dev": true, "license": "MIT" }, + "node_modules/commander": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -4011,6 +3909,19 @@ "node": ">= 8" } }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true, + "license": "MIT", + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/csstype": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", @@ -4144,8 +4055,8 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", - "devOptional": true, "license": "Apache-2.0", + "optional": true, "engines": { "node": ">=8" } @@ -4156,6 +4067,20 @@ "integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==", "license": "MIT" }, + "node_modules/didyoumean": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", + "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/dlv": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", + "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", + "dev": true, + "license": "MIT" + }, "node_modules/doctrine": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", @@ -4337,6 +4262,20 @@ "node": ">= 0.4" } }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true, + "license": "MIT" + }, + "node_modules/electron-to-chromium": { + "version": "1.5.237", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.237.tgz", + "integrity": "sha512-icUt1NvfhGLar5lSWH3tHNzablaA5js3HVHacQimfP8ViEBOQv+L7DKEuHdbTZ0SKCO1ogTJTIL1Gwk9S6Qvcg==", + "dev": true, + "license": "ISC" + }, "node_modules/emoji-regex": { "version": "9.2.2", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", @@ -4344,20 +4283,6 @@ "dev": true, "license": "MIT" }, - "node_modules/enhanced-resolve": { - "version": "5.18.3", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.3.tgz", - "integrity": "sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==", - "dev": true, - "license": "MIT", - "dependencies": { - "graceful-fs": "^4.2.4", - "tapable": "^2.2.0" - }, - "engines": { - "node": ">=10.13.0" - } - }, "node_modules/es-abstract": { "version": "1.24.0", "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.0.tgz", @@ -4536,9 +4461,9 @@ } }, "node_modules/esbuild": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.10.tgz", - "integrity": "sha512-9RiGKvCwaqxO2owP61uQ4BgNborAQskMR6QusfWzQqv7AZOg5oGehdY2pRJMTKuwxd1IDBP4rSbI5lHzU7SMsQ==", + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.11.tgz", + "integrity": "sha512-KohQwyzrKTQmhXDW1PjCv3Tyspn9n5GcY2RTDqeORIdIJY8yKIF7sTSopFmn/wpMPW4rdPXI0UE5LJLuq3bx0Q==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -4549,32 +4474,32 @@ "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.25.10", - "@esbuild/android-arm": "0.25.10", - "@esbuild/android-arm64": "0.25.10", - "@esbuild/android-x64": "0.25.10", - "@esbuild/darwin-arm64": "0.25.10", - "@esbuild/darwin-x64": "0.25.10", - "@esbuild/freebsd-arm64": "0.25.10", - "@esbuild/freebsd-x64": "0.25.10", - "@esbuild/linux-arm": "0.25.10", - "@esbuild/linux-arm64": "0.25.10", - "@esbuild/linux-ia32": "0.25.10", - "@esbuild/linux-loong64": "0.25.10", - "@esbuild/linux-mips64el": "0.25.10", - "@esbuild/linux-ppc64": "0.25.10", - "@esbuild/linux-riscv64": "0.25.10", - "@esbuild/linux-s390x": "0.25.10", - "@esbuild/linux-x64": "0.25.10", - "@esbuild/netbsd-arm64": "0.25.10", - "@esbuild/netbsd-x64": "0.25.10", - "@esbuild/openbsd-arm64": "0.25.10", - "@esbuild/openbsd-x64": "0.25.10", - "@esbuild/openharmony-arm64": "0.25.10", - "@esbuild/sunos-x64": "0.25.10", - "@esbuild/win32-arm64": "0.25.10", - "@esbuild/win32-ia32": "0.25.10", - "@esbuild/win32-x64": "0.25.10" + "@esbuild/aix-ppc64": "0.25.11", + "@esbuild/android-arm": "0.25.11", + "@esbuild/android-arm64": "0.25.11", + "@esbuild/android-x64": "0.25.11", + "@esbuild/darwin-arm64": "0.25.11", + "@esbuild/darwin-x64": "0.25.11", + "@esbuild/freebsd-arm64": "0.25.11", + "@esbuild/freebsd-x64": "0.25.11", + "@esbuild/linux-arm": "0.25.11", + "@esbuild/linux-arm64": "0.25.11", + "@esbuild/linux-ia32": "0.25.11", + "@esbuild/linux-loong64": "0.25.11", + "@esbuild/linux-mips64el": "0.25.11", + "@esbuild/linux-ppc64": "0.25.11", + "@esbuild/linux-riscv64": "0.25.11", + "@esbuild/linux-s390x": "0.25.11", + "@esbuild/linux-x64": "0.25.11", + "@esbuild/netbsd-arm64": "0.25.11", + "@esbuild/netbsd-x64": "0.25.11", + "@esbuild/openbsd-arm64": "0.25.11", + "@esbuild/openbsd-x64": "0.25.11", + "@esbuild/openharmony-arm64": "0.25.11", + "@esbuild/sunos-x64": "0.25.11", + "@esbuild/win32-arm64": "0.25.11", + "@esbuild/win32-ia32": "0.25.11", + "@esbuild/win32-x64": "0.25.11" } }, "node_modules/esbuild-register": { @@ -4590,6 +4515,16 @@ "esbuild": ">=0.12 <1" } }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/escape-string-regexp": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", @@ -4604,25 +4539,24 @@ } }, "node_modules/eslint": { - "version": "9.37.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.37.0.tgz", - "integrity": "sha512-XyLmROnACWqSxiGYArdef1fItQd47weqB7iwtfr9JHwRrqIXZdcFMvvEcL9xHCmL0SNsOvF0c42lWyM1U5dgig==", + "version": "9.38.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.38.0.tgz", + "integrity": "sha512-t5aPOpmtJcZcz5UJyY2GbvpDlsK5E8JqRqoKtfiKE3cNh437KIqfJr3A3AKf5k64NPx6d0G3dno6XDY05PqPtw==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", - "@eslint/config-array": "^0.21.0", - "@eslint/config-helpers": "^0.4.0", + "@eslint/config-array": "^0.21.1", + "@eslint/config-helpers": "^0.4.1", "@eslint/core": "^0.16.0", "@eslint/eslintrc": "^3.3.1", - "@eslint/js": "9.37.0", + "@eslint/js": "9.38.0", "@eslint/plugin-kit": "^0.4.0", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.2", "@types/estree": "^1.0.6", - "@types/json-schema": "^7.0.15", "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.6", @@ -5170,6 +5104,23 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/foreground-child": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", + "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", + "dev": true, + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.6", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/frac": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/frac/-/frac-1.1.2.tgz", @@ -5179,6 +5130,20 @@ "node": ">=0.8" } }, + "node_modules/fraction.js": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", + "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + }, + "funding": { + "type": "patreon", + "url": "https://github.com/sponsors/rawify" + } + }, "node_modules/fsevents": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", @@ -5312,9 +5277,9 @@ } }, "node_modules/get-tsconfig": { - "version": "4.11.0", - "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.11.0.tgz", - "integrity": "sha512-sNsqf7XKQ38IawiVGPOoAlqZo1DMrO7TU+ZcZwi7yLl7/7S0JwmoBMKz/IkUPhSoXM0Ng3vT0yB1iCe5XavDeQ==", + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.12.0.tgz", + "integrity": "sha512-LScr2aNr2FbjAjZh2C6X6BxRx1/x+aTDExct/xyq2XKbYOiG5c0aK7pMsSuyc0brz3ibr/lbQiHD9jzt4lccJw==", "dev": true, "license": "MIT", "dependencies": { @@ -5324,6 +5289,27 @@ "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" } }, + "node_modules/glob": { + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "dev": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/glob-parent": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", @@ -5337,6 +5323,32 @@ "node": ">=10.13.0" } }, + "node_modules/glob/node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/globals": { "version": "14.0.0", "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", @@ -5380,13 +5392,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "dev": true, - "license": "ISC" - }, "node_modules/graphemer": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", @@ -5594,6 +5599,19 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/is-boolean-object": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.2.tgz", @@ -5711,6 +5729,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/is-generator-function": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.2.tgz", @@ -5974,14 +6002,30 @@ "node": ">= 0.4" } }, + "node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, "node_modules/jiti": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz", - "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==", + "version": "1.21.7", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz", + "integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==", "dev": true, "license": "MIT", "bin": { - "jiti": "lib/jiti-cli.mjs" + "jiti": "bin/jiti.js" } }, "node_modules/js-tokens": { @@ -6098,244 +6142,25 @@ "node": ">= 0.8.0" } }, - "node_modules/lightningcss": { - "version": "1.30.1", - "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.30.1.tgz", - "integrity": "sha512-xi6IyHML+c9+Q3W0S4fCQJOym42pyurFiJUHEcEyHS0CeKzia4yZDEsLlqOFykxOdHpNy0NmvVO31vcSqAxJCg==", + "node_modules/lilconfig": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", + "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", "dev": true, - "license": "MPL-2.0", - "dependencies": { - "detect-libc": "^2.0.3" - }, + "license": "MIT", "engines": { - "node": ">= 12.0.0" + "node": ">=14" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - }, - "optionalDependencies": { - "lightningcss-darwin-arm64": "1.30.1", - "lightningcss-darwin-x64": "1.30.1", - "lightningcss-freebsd-x64": "1.30.1", - "lightningcss-linux-arm-gnueabihf": "1.30.1", - "lightningcss-linux-arm64-gnu": "1.30.1", - "lightningcss-linux-arm64-musl": "1.30.1", - "lightningcss-linux-x64-gnu": "1.30.1", - "lightningcss-linux-x64-musl": "1.30.1", - "lightningcss-win32-arm64-msvc": "1.30.1", - "lightningcss-win32-x64-msvc": "1.30.1" + "url": "https://github.com/sponsors/antonk52" } }, - "node_modules/lightningcss-darwin-arm64": { - "version": "1.30.1", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.30.1.tgz", - "integrity": "sha512-c8JK7hyE65X1MHMN+Viq9n11RRC7hgin3HhYKhrMyaXflk5GVplZ60IxyoVtzILeKr+xAJwg6zK6sjTBJ0FKYQ==", - "cpu": [ - "arm64" - ], + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-darwin-x64": { - "version": "1.30.1", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.30.1.tgz", - "integrity": "sha512-k1EvjakfumAQoTfcXUcHQZhSpLlkAuEkdMBsI/ivWw9hL+7FtilQc0Cy3hrx0AAQrVtQAbMI7YjCgYgvn37PzA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-freebsd-x64": { - "version": "1.30.1", - "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.30.1.tgz", - "integrity": "sha512-kmW6UGCGg2PcyUE59K5r0kWfKPAVy4SltVeut+umLCFoJ53RdCUWxcRDzO1eTaxf/7Q2H7LTquFHPL5R+Gjyig==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-arm-gnueabihf": { - "version": "1.30.1", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.30.1.tgz", - "integrity": "sha512-MjxUShl1v8pit+6D/zSPq9S9dQ2NPFSQwGvxBCYaBYLPlCWuPh9/t1MRS8iUaR8i+a6w7aps+B4N0S1TYP/R+Q==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-arm64-gnu": { - "version": "1.30.1", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.30.1.tgz", - "integrity": "sha512-gB72maP8rmrKsnKYy8XUuXi/4OctJiuQjcuqWNlJQ6jZiWqtPvqFziskH3hnajfvKB27ynbVCucKSm2rkQp4Bw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-arm64-musl": { - "version": "1.30.1", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.30.1.tgz", - "integrity": "sha512-jmUQVx4331m6LIX+0wUhBbmMX7TCfjF5FoOH6SD1CttzuYlGNVpA7QnrmLxrsub43ClTINfGSYyHe2HWeLl5CQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-x64-gnu": { - "version": "1.30.1", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.30.1.tgz", - "integrity": "sha512-piWx3z4wN8J8z3+O5kO74+yr6ze/dKmPnI7vLqfSqI8bccaTGY5xiSGVIJBDd5K5BHlvVLpUB3S2YCfelyJ1bw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-x64-musl": { - "version": "1.30.1", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.30.1.tgz", - "integrity": "sha512-rRomAK7eIkL+tHY0YPxbc5Dra2gXlI63HL+v1Pdi1a3sC+tJTcFrHX+E86sulgAXeI7rSzDYhPSeHHjqFhqfeQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-win32-arm64-msvc": { - "version": "1.30.1", - "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.30.1.tgz", - "integrity": "sha512-mSL4rqPi4iXq5YVqzSsJgMVFENoa4nGTT/GjO2c0Yl9OuQfPsIfncvLrEW6RbbB24WtZ3xP/2CCmI3tNkNV4oA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-win32-x64-msvc": { - "version": "1.30.1", - "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.30.1.tgz", - "integrity": "sha512-PVqXh48wh4T53F/1CCu8PIPCxLzWyCnn/9T5W1Jpmdy5h9Cwd+0YQS6/LwhHXSafuc61/xg9Lv5OrCby6a++jg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } + "license": "MIT" }, "node_modules/locate-path": { "version": "6.0.0", @@ -6373,6 +6198,13 @@ "loose-envify": "cli.js" } }, + "node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, + "license": "ISC" + }, "node_modules/lucide-react": { "version": "0.545.0", "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.545.0.tgz", @@ -6382,16 +6214,6 @@ "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, - "node_modules/magic-string": { - "version": "0.30.19", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.19.tgz", - "integrity": "sha512-2N21sPY9Ws53PZvsEpVtNuSW+ScYbQdp4b9qUaL+9QkHUrGFKo56Lg9Emg5s9V/qrtNBmiR01sYhUOwu3H+VOw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.5" - } - }, "node_modules/math-intrinsics": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", @@ -6459,19 +6281,6 @@ "node": ">=16 || 14 >=14.17" } }, - "node_modules/minizlib": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.1.0.tgz", - "integrity": "sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==", - "dev": true, - "license": "MIT", - "dependencies": { - "minipass": "^7.1.2" - }, - "engines": { - "node": ">= 18" - } - }, "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -6479,6 +6288,18 @@ "dev": true, "license": "MIT" }, + "node_modules/mz": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" + } + }, "node_modules/nanoid": { "version": "3.3.11", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", @@ -6572,6 +6393,22 @@ } } }, + "node_modules/next/node_modules/@next/swc-win32-x64-msvc": { + "version": "15.5.4", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-15.5.4.tgz", + "integrity": "sha512-1ur2tSHZj8Px/KMAthmuI9FMp/YFusMMGoRNJaRZMOlSkgvLjzosSdQI0cJAKogdHl3qXUQKL9MGaYvKwA7DXg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, "node_modules/next/node_modules/postcss": { "version": "8.4.31", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", @@ -6600,6 +6437,33 @@ "node": "^10 || ^12 || >=14" } }, + "node_modules/node-releases": { + "version": "2.0.25", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.25.tgz", + "integrity": "sha512-4auku8B/vw5psvTiiN9j1dAOsXvMoGqJuKJcR+dTdqiXEK20mMTk1UEo3HS16LeGQsVG6+qKTPM9u/qQ2LqATA==", + "dev": true, + "license": "MIT" + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-range": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -6610,6 +6474,16 @@ "node": ">=0.10.0" } }, + "node_modules/object-hash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", + "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, "node_modules/object-inspect": { "version": "1.13.4", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", @@ -6791,6 +6665,13 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "dev": true, + "license": "BlueOak-1.0.0" + }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -6831,6 +6712,23 @@ "dev": true, "license": "MIT" }, + "node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/pg": { "version": "8.16.3", "resolved": "https://registry.npmjs.org/pg/-/pg-8.16.3.tgz", @@ -6939,6 +6837,26 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pirates": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", + "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, "node_modules/possible-typed-array-names": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", @@ -6978,6 +6896,140 @@ "node": "^10 || ^12 || >=14" } }, + "node_modules/postcss-import": { + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", + "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", + "dev": true, + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.0.0", + "read-cache": "^1.0.0", + "resolve": "^1.1.7" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "postcss": "^8.0.0" + } + }, + "node_modules/postcss-js": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.1.0.tgz", + "integrity": "sha512-oIAOTqgIo7q2EOwbhb8UalYePMvYoIeRY2YKntdpFQXNosSu3vLrniGgmH9OKs/qAkfoj5oB3le/7mINW1LCfw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "camelcase-css": "^2.0.1" + }, + "engines": { + "node": "^12 || ^14 || >= 16" + }, + "peerDependencies": { + "postcss": "^8.4.21" + } + }, + "node_modules/postcss-load-config": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-6.0.1.tgz", + "integrity": "sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "lilconfig": "^3.1.1" + }, + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "jiti": ">=1.21.0", + "postcss": ">=8.0.9", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + }, + "postcss": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/postcss-nested": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.2.0.tgz", + "integrity": "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "postcss-selector-parser": "^6.1.1" + }, + "engines": { + "node": ">=12.0" + }, + "peerDependencies": { + "postcss": "^8.2.14" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", + "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "dev": true, + "license": "MIT" + }, "node_modules/postgres-array": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", @@ -7167,6 +7219,29 @@ } } }, + "node_modules/read-cache": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", + "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "pify": "^2.3.0" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, "node_modules/reflect.getprototypeof": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz", @@ -7212,13 +7287,13 @@ } }, "node_modules/resolve": { - "version": "1.22.10", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", - "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==", + "version": "1.22.11", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", + "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", "dev": true, "license": "MIT", "dependencies": { - "is-core-module": "^2.16.0", + "is-core-module": "^2.16.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, @@ -7552,6 +7627,19 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -7624,6 +7712,70 @@ "node": ">= 0.4" } }, + "node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/string-width-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/string.prototype.includes": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/string.prototype.includes/-/string.prototype.includes-2.0.1.tgz", @@ -7737,6 +7889,46 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/strip-ansi": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", + "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/strip-bom": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", @@ -7783,6 +7975,29 @@ } } }, + "node_modules/sucrase": { + "version": "3.35.0", + "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz", + "integrity": "sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.2", + "commander": "^4.0.0", + "glob": "^10.3.10", + "lines-and-columns": "^1.1.6", + "mz": "^2.7.0", + "pirates": "^4.0.1", + "ts-interface-checker": "^0.1.9" + }, + "bin": { + "sucrase": "bin/sucrase", + "sucrase-node": "bin/sucrase-node" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, "node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -7820,41 +8035,94 @@ } }, "node_modules/tailwindcss": { - "version": "4.1.14", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.14.tgz", - "integrity": "sha512-b7pCxjGO98LnxVkKjaZSDeNuljC4ueKUddjENJOADtubtdo8llTaJy7HwBMeLNSSo2N5QIAgklslK1+Ir8r6CA==", - "dev": true, - "license": "MIT" - }, - "node_modules/tapable": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz", - "integrity": "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==", + "version": "3.4.18", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.18.tgz", + "integrity": "sha512-6A2rnmW5xZMdw11LYjhcI5846rt9pbLSabY5XPxo+XWdxwZaFEn47Go4NzFiHu9sNNmr/kXivP1vStfvMaK1GQ==", "dev": true, "license": "MIT", - "engines": { - "node": ">=6" + "dependencies": { + "@alloc/quick-lru": "^5.2.0", + "arg": "^5.0.2", + "chokidar": "^3.6.0", + "didyoumean": "^1.2.2", + "dlv": "^1.1.3", + "fast-glob": "^3.3.2", + "glob-parent": "^6.0.2", + "is-glob": "^4.0.3", + "jiti": "^1.21.7", + "lilconfig": "^3.1.3", + "micromatch": "^4.0.8", + "normalize-path": "^3.0.0", + "object-hash": "^3.0.0", + "picocolors": "^1.1.1", + "postcss": "^8.4.47", + "postcss-import": "^15.1.0", + "postcss-js": "^4.0.1", + "postcss-load-config": "^4.0.2 || ^5.0 || ^6.0", + "postcss-nested": "^6.2.0", + "postcss-selector-parser": "^6.1.2", + "resolve": "^1.22.8", + "sucrase": "^3.35.0" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" + "bin": { + "tailwind": "lib/cli.js", + "tailwindcss": "lib/cli.js" + }, + "engines": { + "node": ">=14.0.0" } }, - "node_modules/tar": { - "version": "7.5.1", - "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.1.tgz", - "integrity": "sha512-nlGpxf+hv0v7GkWBK2V9spgactGOp0qvfWRxUMjqHyzrt3SgwE48DIv/FhqPHJYLHpgW1opq3nERbz5Anq7n1g==", + "node_modules/tailwindcss/node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/tailwindcss/node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "dev": true, "license": "ISC", "dependencies": { - "@isaacs/fs-minipass": "^4.0.0", - "chownr": "^3.0.0", - "minipass": "^7.1.2", - "minizlib": "^3.1.0", - "yallist": "^5.0.0" + "is-glob": "^4.0.1" }, "engines": { - "node": ">=18" + "node": ">= 6" + } + }, + "node_modules/thenify": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", + "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "any-promise": "^1.0.0" + } + }, + "node_modules/thenify-all": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "thenify": ">= 3.1.0 < 4" + }, + "engines": { + "node": ">=0.8" } }, "node_modules/tinyglobby": { @@ -7931,6 +8199,13 @@ "typescript": ">=4.8.4" } }, + "node_modules/ts-interface-checker": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", + "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", + "dev": true, + "license": "Apache-2.0" + }, "node_modules/tsconfig-paths": { "version": "3.15.0", "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", @@ -8146,6 +8421,37 @@ "@unrs/resolver-binding-win32-x64-msvc": "1.11.1" } }, + "node_modules/update-browserslist-db": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz", + "integrity": "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, "node_modules/uri-js": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", @@ -8199,6 +8505,13 @@ } } }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true, + "license": "MIT" + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -8332,6 +8645,101 @@ "node": ">=0.10.0" } }, + "node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/wrap-ansi-cjs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, "node_modules/xlsx": { "version": "0.18.5", "resolved": "https://registry.npmjs.org/xlsx/-/xlsx-0.18.5.tgz", @@ -8362,16 +8770,6 @@ "node": ">=0.4" } }, - "node_modules/yallist": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz", - "integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==", - "dev": true, - "license": "BlueOak-1.0.0", - "engines": { - "node": ">=18" - } - }, "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", @@ -8384,6 +8782,21 @@ "funding": { "url": "https://github.com/sponsors/sindresorhus" } + }, + "node_modules/@next/swc-win32-x64-msvc": { + "version": "15.5.4", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-15.5.4.tgz", + "integrity": "sha512-1ur2tSHZj8Px/KMAthmuI9FMp/YFusMMGoRNJaRZMOlSkgvLjzosSdQI0cJAKogdHl3qXUQKL9MGaYvKwA7DXg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } } } } diff --git a/package.json b/package.json index aec9ed6..d7e1547 100644 --- a/package.json +++ b/package.json @@ -28,16 +28,17 @@ }, "devDependencies": { "@eslint/eslintrc": "^3", - "@tailwindcss/postcss": "^4", "@types/node": "^20", "@types/pg": "^8.15.5", "@types/react": "^19", "@types/react-dom": "^19", "@types/xlsx": "^0.0.35", + "autoprefixer": "^10.4.21", "drizzle-kit": "^0.31.5", "eslint": "^9", "eslint-config-next": "15.5.4", - "tailwindcss": "^4", + "postcss": "^8.5.6", + "tailwindcss": "^3.4.18", "tsx": "^4.20.6", "tw-animate-css": "^1.4.0", "typescript": "^5" diff --git a/postcss.config.js b/postcss.config.js new file mode 100644 index 0000000..33ad091 --- /dev/null +++ b/postcss.config.js @@ -0,0 +1,6 @@ +module.exports = { + plugins: { + tailwindcss: {}, + autoprefixer: {}, + }, +} diff --git a/postcss.config.mjs b/postcss.config.mjs deleted file mode 100644 index c7bcb4b..0000000 --- a/postcss.config.mjs +++ /dev/null @@ -1,5 +0,0 @@ -const config = { - plugins: ["@tailwindcss/postcss"], -}; - -export default config; diff --git a/src/app/DRE/analitico.tsx b/src/app/DRE/analitico.tsx index f1439f3..23377cc 100644 --- a/src/app/DRE/analitico.tsx +++ b/src/app/DRE/analitico.tsx @@ -335,10 +335,10 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { // Usar dados filtrados da tabela em vez dos dados originais - MESMA LÓGICA DO totalValor const filteredData = table.getRowModel().rows.map((row) => row.original); const valorRealizado = filteredData.reduce((sum, item) => { - const valor = + const valor = typeof item.valor === "string" ? parseFloat(item.valor) : item.valor; - return sum + (isNaN(valor) ? 0 : valor); - }, 0); + return sum + (isNaN(valor) ? 0 : valor); + }, 0); return { valorRealizado, @@ -475,17 +475,17 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { Limpar Filtros )} - {data.length > 0 && ( - - )} + > + + Exportar XLSX + + )} @@ -526,8 +526,8 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) {
Número do Lançamento
- + {/* Table Body */}
+
{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} -
+
+
- -
+
- -
+
- -
+
{row.original.historico} -
+
{row.original.historico2} -
+
- -
- + + ); })} - + )} - + {/* Footer com Totalizador das Colunas */} {data.length > 0 && ( @@ -694,8 +694,8 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) {
+ - )} {/* Summary Footer - Integrado */} @@ -782,7 +782,7 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { ))} - +
+ {!( cond.operator === "empty" || cond.operator === "notEmpty" @@ -829,7 +829,7 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { placeholder="Digite o valor" className="w-full bg-white border-gray-300" /> - + )} {conditions.length > 1 && ( @@ -845,8 +845,8 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { > ✕ - - )} + + )} ))} diff --git a/src/app/globals.css b/src/app/globals.css index b1364cc..df96d7e 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -1,71 +1,58 @@ -@import 'tailwindcss'; +@tailwind base; +@tailwind components; +@tailwind utilities; :root { - --radius: 0.65rem; - --background: oklch(1 0 0); - --foreground: oklch(0.145 0 0); - --card: oklch(1 0 0); - --card-foreground: oklch(0.145 0 0); - --popover: oklch(1 0 0); - --popover-foreground: oklch(0.145 0 0); - --primary: oklch(0.205 0 0); - --primary-foreground: oklch(0.985 0 0); - --secondary: oklch(0.97 0 0); - --secondary-foreground: oklch(0.205 0 0); - --muted: oklch(0.97 0 0); - --muted-foreground: oklch(0.556 0 0); - --accent: oklch(0.97 0 0); - --accent-foreground: oklch(0.205 0 0); - --destructive: oklch(0.577 0.245 27.325); - --border: oklch(0.922 0 0); - --input: oklch(0.922 0 0); - --ring: oklch(0.708 0 0); - --chart-1: oklch(0.646 0.222 41.116); - --chart-2: oklch(0.6 0.118 184.704); - --chart-3: oklch(0.398 0.07 227.392); - --chart-4: oklch(0.828 0.189 84.429); - --chart-5: oklch(0.769 0.188 70.08); - --radius: 0.625rem; - --sidebar: oklch(0.985 0 0); - --sidebar-foreground: oklch(0.145 0 0); - --sidebar-primary: oklch(0.205 0 0); - --sidebar-primary-foreground: oklch(0.985 0 0); - --sidebar-accent: oklch(0.97 0 0); - --sidebar-accent-foreground: oklch(0.205 0 0); - --sidebar-border: oklch(0.922 0 0); - --sidebar-ring: oklch(0.708 0 0); + --radius: 0.5rem; + --background: 0 0% 100%; + --foreground: 222.2 84% 4.9%; + --card: 0 0% 100%; + --card-foreground: 222.2 84% 4.9%; + --popover: 0 0% 100%; + --popover-foreground: 222.2 84% 4.9%; + --primary: 222.2 47.4% 11.2%; + --primary-foreground: 210 40% 98%; + --secondary: 210 40% 96%; + --secondary-foreground: 222.2 47.4% 11.2%; + --muted: 210 40% 96%; + --muted-foreground: 215.4 16.3% 46.9%; + --accent: 210 40% 96%; + --accent-foreground: 222.2 47.4% 11.2%; + --destructive: 0 84.2% 60.2%; + --destructive-foreground: 210 40% 98%; + --border: 214.3 31.8% 91.4%; + --input: 214.3 31.8% 91.4%; + --ring: 222.2 84% 4.9%; + --chart-1: 12 76% 61%; + --chart-2: 173 58% 39%; + --chart-3: 197 37% 24%; + --chart-4: 43 74% 66%; + --chart-5: 27 87% 67%; } .dark { - --background: oklch(0.145 0 0); - --foreground: oklch(0.985 0 0); - --card: oklch(0.205 0 0); - --card-foreground: oklch(0.985 0 0); - --popover: oklch(0.205 0 0); - --popover-foreground: oklch(0.985 0 0); - --primary: oklch(0.922 0 0); - --primary-foreground: oklch(0.205 0 0); - --secondary: oklch(0.269 0 0); - --secondary-foreground: oklch(0.985 0 0); - --muted: oklch(0.269 0 0); - --muted-foreground: oklch(0.708 0 0); - --accent: oklch(0.269 0 0); - --accent-foreground: oklch(0.985 0 0); - --destructive: oklch(0.704 0.191 22.216); - --border: oklch(1 0 0 / 10%); - --input: oklch(1 0 0 / 15%); - --ring: oklch(0.556 0 0); - --chart-1: oklch(0.488 0.243 264.376); - --chart-2: oklch(0.696 0.17 162.48); - --chart-3: oklch(0.769 0.188 70.08); - --chart-4: oklch(0.627 0.265 303.9); - --chart-5: oklch(0.645 0.246 16.439); - --sidebar: oklch(0.205 0 0); - --sidebar-foreground: oklch(0.985 0 0); - --sidebar-primary: oklch(0.488 0.243 264.376); - --sidebar-primary-foreground: oklch(0.985 0 0); - --sidebar-accent: oklch(0.269 0 0); - --sidebar-accent-foreground: oklch(0.985 0 0); - --sidebar-border: oklch(1 0 0 / 10%); - --sidebar-ring: oklch(0.556 0 0); + --background: 222.2 84% 4.9%; + --foreground: 210 40% 98%; + --card: 222.2 84% 4.9%; + --card-foreground: 210 40% 98%; + --popover: 222.2 84% 4.9%; + --popover-foreground: 210 40% 98%; + --primary: 210 40% 98%; + --primary-foreground: 222.2 47.4% 11.2%; + --secondary: 217.2 32.6% 17.5%; + --secondary-foreground: 210 40% 98%; + --muted: 217.2 32.6% 17.5%; + --muted-foreground: 215 20.2% 65.1%; + --accent: 217.2 32.6% 17.5%; + --accent-foreground: 210 40% 98%; + --destructive: 0 62.8% 30.6%; + --destructive-foreground: 210 40% 98%; + --border: 217.2 32.6% 17.5%; + --input: 217.2 32.6% 17.5%; + --ring: 212.7 26.8% 83.9%; + --chart-1: 220 70% 50%; + --chart-2: 160 60% 45%; + --chart-3: 30 80% 55%; + --chart-4: 280 65% 60%; + --chart-5: 340 75% 55%; } diff --git a/tailwind.config.js b/tailwind.config.js new file mode 100644 index 0000000..0229a6d --- /dev/null +++ b/tailwind.config.js @@ -0,0 +1,54 @@ +/** @type {import('tailwindcss').Config} */ +module.exports = { + content: [ + './src/pages/**/*.{js,ts,jsx,tsx,mdx}', + './src/components/**/*.{js,ts,jsx,tsx,mdx}', + './src/app/**/*.{js,ts,jsx,tsx,mdx}', + ], + theme: { + extend: { + colors: { + border: "hsl(var(--border))", + input: "hsl(var(--input))", + ring: "hsl(var(--ring))", + background: "hsl(var(--background))", + foreground: "hsl(var(--foreground))", + primary: { + DEFAULT: "hsl(var(--primary))", + foreground: "hsl(var(--primary-foreground))", + }, + secondary: { + DEFAULT: "hsl(var(--secondary))", + foreground: "hsl(var(--secondary-foreground))", + }, + destructive: { + DEFAULT: "hsl(var(--destructive))", + foreground: "hsl(var(--destructive-foreground))", + }, + muted: { + DEFAULT: "hsl(var(--muted))", + foreground: "hsl(var(--muted-foreground))", + }, + accent: { + DEFAULT: "hsl(var(--accent))", + foreground: "hsl(var(--accent-foreground))", + }, + popover: { + DEFAULT: "hsl(var(--popover))", + foreground: "hsl(var(--popover-foreground))", + }, + card: { + DEFAULT: "hsl(var(--card))", + foreground: "hsl(var(--card-foreground))", + }, + }, + borderRadius: { + lg: "var(--radius)", + md: "calc(var(--radius) - 2px)", + sm: "calc(var(--radius) - 4px)", + }, + }, + }, + plugins: [], +} + From 3269c8f5cb1b9b8c42ee73e4bdc7f6ae90d3ef55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alessandro=20Gon=C3=A7aalves?= Date: Mon, 20 Oct 2025 23:12:40 -0300 Subject: [PATCH 18/30] =?UTF-8?q?fix:=20corre=C3=A7=C3=A3o=20dos=20campos?= =?UTF-8?q?=20totalizadores=20no=20footer=20table?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/DRE/analitico.tsx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/app/DRE/analitico.tsx b/src/app/DRE/analitico.tsx index 23377cc..1ce3948 100644 --- a/src/app/DRE/analitico.tsx +++ b/src/app/DRE/analitico.tsx @@ -330,15 +330,15 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { setTotalValor(newTotal); }, [table, data, columnFilters, globalFilter]); - // Calcular totais das colunas de valores para o footer - mesmo princípio do Valor Total + // Calcular totais das colunas de valores para o footer - EXATAMENTE o mesmo padrão do Valor Total const columnTotals = React.useMemo(() => { - // Usar dados filtrados da tabela em vez dos dados originais - MESMA LÓGICA DO totalValor + // Usar EXATAMENTE a mesma lógica do totalValor const filteredData = table.getRowModel().rows.map((row) => row.original); const valorRealizado = filteredData.reduce((sum, item) => { - const valor = + const valor = typeof item.valor === "string" ? parseFloat(item.valor) : item.valor; - return sum + (isNaN(valor) ? 0 : valor); - }, 0); + return sum + (isNaN(valor) ? 0 : valor); + }, 0); return { valorRealizado, @@ -346,7 +346,7 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { valorConfirmado: 0, // Sempre 0 pois não há dados valorPago: 0, // Sempre 0 pois não há dados }; - }, [table]); + }, [table, data, columnFilters, globalFilter]); const exportToExcel = () => { if (data.length === 0) return; From 5acdff6dd2db381c431368b2aacab25ad2ec5d17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alessandro=20Gon=C3=A7aalves?= Date: Mon, 20 Oct 2025 23:28:51 -0300 Subject: [PATCH 19/30] =?UTF-8?q?fix:=20intergra=C3=A7=C3=A3o=20com=20o=20?= =?UTF-8?q?oracle=20funcional?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- next.config.js | 14 + next.config.ts | 7 - package-lock.json | 749 +++++++------------------------ package.json | 7 +- src/app/api/oracle-test/route.ts | 34 ++ src/db/index.ts | 3 + src/db/oracle.ts | 69 +++ 7 files changed, 282 insertions(+), 601 deletions(-) create mode 100644 next.config.js delete mode 100644 next.config.ts create mode 100644 src/app/api/oracle-test/route.ts create mode 100644 src/db/oracle.ts diff --git a/next.config.js b/next.config.js new file mode 100644 index 0000000..a0b5b28 --- /dev/null +++ b/next.config.js @@ -0,0 +1,14 @@ +/** @type {import('next').NextConfig} */ +const nextConfig = { + experimental: { + serverComponentsExternalPackages: ['oracledb'] + }, + webpack: (config, { isServer }) => { + if (isServer) { + config.externals.push('oracledb'); + } + return config; + } +}; + +module.exports = nextConfig; diff --git a/next.config.ts b/next.config.ts deleted file mode 100644 index e9ffa30..0000000 --- a/next.config.ts +++ /dev/null @@ -1,7 +0,0 @@ -import type { NextConfig } from "next"; - -const nextConfig: NextConfig = { - /* config options here */ -}; - -export default nextConfig; diff --git a/package-lock.json b/package-lock.json index 7870943..d37ba04 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,10 +18,11 @@ "dotenv": "^17.2.3", "drizzle-orm": "^0.44.6", "lucide-react": "^0.545.0", - "next": "15.5.4", + "next": "^14.2.33", + "oracledb": "^6.9.0", "pg": "^8.16.3", - "react": "19.1.0", - "react-dom": "19.1.0", + "react": "^18.3.1", + "react-dom": "^18.3.1", "tailwind-merge": "^3.3.1", "xlsx": "^0.18.5" }, @@ -64,9 +65,9 @@ "license": "Apache-2.0" }, "node_modules/@emnapi/core": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.5.0.tgz", - "integrity": "sha512-sbP8GzB1WDzacS8fgNPpHlp6C9VZe+SJP3F90W9rLemaQj2PzIuTEl1qDOYQf58YIpyjViI24y9aPWCjEzY2cg==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.6.0.tgz", + "integrity": "sha512-zq/ay+9fNIJJtJiZxdTnXS20PllcYMX3OE23ESc4HK/bdYu3cOWYVhsOhVnXALfU/uqJIxn5NBPd9z4v+SfoSg==", "dev": true, "license": "MIT", "optional": true, @@ -76,9 +77,10 @@ } }, "node_modules/@emnapi/runtime": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.5.0.tgz", - "integrity": "sha512-97/BJ3iXHww3djw6hYIfErCZFee7qCtrneuLa20UXFCOTCfBM2cvQHjWJ2EG0s0MtdNwInarqCTz35i4wWXHsQ==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.6.0.tgz", + "integrity": "sha512-obtUmAHTMjll499P+D9A3axeJFlhdjOWdKUNs/U6QIGT7V5RjcUW1xToAzjvmgTSQhDbYn/NwfTRoJcQ2rNBxA==", + "dev": true, "license": "MIT", "optional": true, "dependencies": { @@ -1208,434 +1210,6 @@ "url": "https://github.com/sponsors/nzakas" } }, - "node_modules/@img/colour": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@img/colour/-/colour-1.0.0.tgz", - "integrity": "sha512-A5P/LfWGFSl6nsckYtjw9da+19jB8hkJ6ACTGcDfEJ0aE+l2n2El7dsVM7UVHZQ9s2lmYMWlrS21YLy2IR1LUw==", - "license": "MIT", - "optional": true, - "engines": { - "node": ">=18" - } - }, - "node_modules/@img/sharp-darwin-arm64": { - "version": "0.34.4", - "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.4.tgz", - "integrity": "sha512-sitdlPzDVyvmINUdJle3TNHl+AG9QcwiAMsXmccqsCOMZNIdW2/7S26w0LyU8euiLVzFBL3dXPwVCq/ODnf2vA==", - "cpu": [ - "arm64" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-darwin-arm64": "1.2.3" - } - }, - "node_modules/@img/sharp-darwin-x64": { - "version": "0.34.4", - "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.4.tgz", - "integrity": "sha512-rZheupWIoa3+SOdF/IcUe1ah4ZDpKBGWcsPX6MT0lYniH9micvIU7HQkYTfrx5Xi8u+YqwLtxC/3vl8TQN6rMg==", - "cpu": [ - "x64" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-darwin-x64": "1.2.3" - } - }, - "node_modules/@img/sharp-libvips-darwin-arm64": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.2.3.tgz", - "integrity": "sha512-QzWAKo7kpHxbuHqUC28DZ9pIKpSi2ts2OJnoIGI26+HMgq92ZZ4vk8iJd4XsxN+tYfNJxzH6W62X5eTcsBymHw==", - "cpu": [ - "arm64" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "darwin" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-darwin-x64": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.2.3.tgz", - "integrity": "sha512-Ju+g2xn1E2AKO6YBhxjj+ACcsPQRHT0bhpglxcEf+3uyPY+/gL8veniKoo96335ZaPo03bdDXMv0t+BBFAbmRA==", - "cpu": [ - "x64" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "darwin" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linux-arm": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.2.3.tgz", - "integrity": "sha512-x1uE93lyP6wEwGvgAIV0gP6zmaL/a0tGzJs/BIDDG0zeBhMnuUPm7ptxGhUbcGs4okDJrk4nxgrmxpib9g6HpA==", - "cpu": [ - "arm" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linux-arm64": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.2.3.tgz", - "integrity": "sha512-I4RxkXU90cpufazhGPyVujYwfIm9Nk1QDEmiIsaPwdnm013F7RIceaCc87kAH+oUB1ezqEvC6ga4m7MSlqsJvQ==", - "cpu": [ - "arm64" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linux-ppc64": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.2.3.tgz", - "integrity": "sha512-Y2T7IsQvJLMCBM+pmPbM3bKT/yYJvVtLJGfCs4Sp95SjvnFIjynbjzsa7dY1fRJX45FTSfDksbTp6AGWudiyCg==", - "cpu": [ - "ppc64" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linux-s390x": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.2.3.tgz", - "integrity": "sha512-RgWrs/gVU7f+K7P+KeHFaBAJlNkD1nIZuVXdQv6S+fNA6syCcoboNjsV2Pou7zNlVdNQoQUpQTk8SWDHUA3y/w==", - "cpu": [ - "s390x" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linux-x64": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.2.3.tgz", - "integrity": "sha512-3JU7LmR85K6bBiRzSUc/Ff9JBVIFVvq6bomKE0e63UXGeRw2HPVEjoJke1Yx+iU4rL7/7kUjES4dZ/81Qjhyxg==", - "cpu": [ - "x64" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linuxmusl-arm64": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.2.3.tgz", - "integrity": "sha512-F9q83RZ8yaCwENw1GieztSfj5msz7GGykG/BA+MOUefvER69K/ubgFHNeSyUu64amHIYKGDs4sRCMzXVj8sEyw==", - "cpu": [ - "arm64" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linuxmusl-x64": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.2.3.tgz", - "integrity": "sha512-U5PUY5jbc45ANM6tSJpsgqmBF/VsL6LnxJmIf11kB7J5DctHgqm0SkuXzVWtIY90GnJxKnC/JT251TDnk1fu/g==", - "cpu": [ - "x64" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-linux-arm": { - "version": "0.34.4", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.4.tgz", - "integrity": "sha512-Xyam4mlqM0KkTHYVSuc6wXRmM7LGN0P12li03jAnZ3EJWZqj83+hi8Y9UxZUbxsgsK1qOEwg7O0Bc0LjqQVtxA==", - "cpu": [ - "arm" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-arm": "1.2.3" - } - }, - "node_modules/@img/sharp-linux-arm64": { - "version": "0.34.4", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.4.tgz", - "integrity": "sha512-YXU1F/mN/Wu786tl72CyJjP/Ngl8mGHN1hST4BGl+hiW5jhCnV2uRVTNOcaYPs73NeT/H8Upm3y9582JVuZHrQ==", - "cpu": [ - "arm64" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-arm64": "1.2.3" - } - }, - "node_modules/@img/sharp-linux-ppc64": { - "version": "0.34.4", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.34.4.tgz", - "integrity": "sha512-F4PDtF4Cy8L8hXA2p3TO6s4aDt93v+LKmpcYFLAVdkkD3hSxZzee0rh6/+94FpAynsuMpLX5h+LRsSG3rIciUQ==", - "cpu": [ - "ppc64" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-ppc64": "1.2.3" - } - }, - "node_modules/@img/sharp-linux-s390x": { - "version": "0.34.4", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.4.tgz", - "integrity": "sha512-qVrZKE9Bsnzy+myf7lFKvng6bQzhNUAYcVORq2P7bDlvmF6u2sCmK2KyEQEBdYk+u3T01pVsPrkj943T1aJAsw==", - "cpu": [ - "s390x" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-s390x": "1.2.3" - } - }, - "node_modules/@img/sharp-linux-x64": { - "version": "0.34.4", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.4.tgz", - "integrity": "sha512-ZfGtcp2xS51iG79c6Vhw9CWqQC8l2Ot8dygxoDoIQPTat/Ov3qAa8qpxSrtAEAJW+UjTXc4yxCjNfxm4h6Xm2A==", - "cpu": [ - "x64" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-x64": "1.2.3" - } - }, - "node_modules/@img/sharp-linuxmusl-arm64": { - "version": "0.34.4", - "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.4.tgz", - "integrity": "sha512-8hDVvW9eu4yHWnjaOOR8kHVrew1iIX+MUgwxSuH2XyYeNRtLUe4VNioSqbNkB7ZYQJj9rUTT4PyRscyk2PXFKA==", - "cpu": [ - "arm64" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linuxmusl-arm64": "1.2.3" - } - }, - "node_modules/@img/sharp-linuxmusl-x64": { - "version": "0.34.4", - "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.4.tgz", - "integrity": "sha512-lU0aA5L8QTlfKjpDCEFOZsTYGn3AEiO6db8W5aQDxj0nQkVrZWmN3ZP9sYKWJdtq3PWPhUNlqehWyXpYDcI9Sg==", - "cpu": [ - "x64" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linuxmusl-x64": "1.2.3" - } - }, - "node_modules/@img/sharp-wasm32": { - "version": "0.34.4", - "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.34.4.tgz", - "integrity": "sha512-33QL6ZO/qpRyG7woB/HUALz28WnTMI2W1jgX3Nu2bypqLIKx/QKMILLJzJjI+SIbvXdG9fUnmrxR7vbi1sTBeA==", - "cpu": [ - "wasm32" - ], - "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", - "optional": true, - "dependencies": { - "@emnapi/runtime": "^1.5.0" - }, - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-win32-arm64": { - "version": "0.34.4", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.4.tgz", - "integrity": "sha512-2Q250do/5WXTwxW3zjsEuMSv5sUU4Tq9VThWKlU2EYLm4MB7ZeMwF+SFJutldYODXF6jzc6YEOC+VfX0SZQPqA==", - "cpu": [ - "arm64" - ], - "license": "Apache-2.0 AND LGPL-3.0-or-later", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-win32-ia32": { - "version": "0.34.4", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.4.tgz", - "integrity": "sha512-3ZeLue5V82dT92CNL6rsal6I2weKw1cYu+rGKm8fOCCtJTR2gYeUfY3FqUnIJsMUPIH68oS5jmZ0NiJ508YpEw==", - "cpu": [ - "ia32" - ], - "license": "Apache-2.0 AND LGPL-3.0-or-later", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-win32-x64": { - "version": "0.34.4", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.4.tgz", - "integrity": "sha512-xIyj4wpYs8J18sVN3mSQjwrw7fKUqRw+Z5rnHNCy5fYTxigBz81u5mOMPmFumwjcn8+ld1ppptMBCLic1nz6ig==", - "cpu": [ - "x64" - ], - "license": "Apache-2.0 AND LGPL-3.0-or-later", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - } - }, "node_modules/@isaacs/cliui": { "version": "8.0.2", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", @@ -1707,9 +1281,9 @@ } }, "node_modules/@next/env": { - "version": "15.5.4", - "resolved": "https://registry.npmjs.org/@next/env/-/env-15.5.4.tgz", - "integrity": "sha512-27SQhYp5QryzIT5uO8hq99C69eLQ7qkzkDPsk3N+GuS2XgOgoYEeOav7Pf8Tn4drECOVDsDg8oj+/DVy8qQL2A==", + "version": "14.2.33", + "resolved": "https://registry.npmjs.org/@next/env/-/env-14.2.33.tgz", + "integrity": "sha512-CgVHNZ1fRIlxkLhIX22flAZI/HmpDaZ8vwyJ/B0SDPTBuLZ1PJ+DWMjCHhqnExfmSQzA/PbZi8OAc7PAq2w9IA==", "license": "MIT" }, "node_modules/@next/eslint-plugin-next": { @@ -1723,9 +1297,9 @@ } }, "node_modules/@next/swc-darwin-arm64": { - "version": "15.5.4", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-15.5.4.tgz", - "integrity": "sha512-nopqz+Ov6uvorej8ndRX6HlxCYWCO3AHLfKK2TYvxoSB2scETOcfm/HSS3piPqc3A+MUgyHoqE6je4wnkjfrOA==", + "version": "14.2.33", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.2.33.tgz", + "integrity": "sha512-HqYnb6pxlsshoSTubdXKu15g3iivcbsMXg4bYpjL2iS/V6aQot+iyF4BUc2qA/J/n55YtvE4PHMKWBKGCF/+wA==", "cpu": [ "arm64" ], @@ -1739,9 +1313,9 @@ } }, "node_modules/@next/swc-darwin-x64": { - "version": "15.5.4", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-15.5.4.tgz", - "integrity": "sha512-QOTCFq8b09ghfjRJKfb68kU9k2K+2wsC4A67psOiMn849K9ZXgCSRQr0oVHfmKnoqCbEmQWG1f2h1T2vtJJ9mA==", + "version": "14.2.33", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-14.2.33.tgz", + "integrity": "sha512-8HGBeAE5rX3jzKvF593XTTFg3gxeU4f+UWnswa6JPhzaR6+zblO5+fjltJWIZc4aUalqTclvN2QtTC37LxvZAA==", "cpu": [ "x64" ], @@ -1755,9 +1329,9 @@ } }, "node_modules/@next/swc-linux-arm64-gnu": { - "version": "15.5.4", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-15.5.4.tgz", - "integrity": "sha512-eRD5zkts6jS3VfE/J0Kt1VxdFqTnMc3QgO5lFE5GKN3KDI/uUpSyK3CjQHmfEkYR4wCOl0R0XrsjpxfWEA++XA==", + "version": "14.2.33", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.2.33.tgz", + "integrity": "sha512-JXMBka6lNNmqbkvcTtaX8Gu5by9547bukHQvPoLe9VRBx1gHwzf5tdt4AaezW85HAB3pikcvyqBToRTDA4DeLw==", "cpu": [ "arm64" ], @@ -1771,9 +1345,9 @@ } }, "node_modules/@next/swc-linux-arm64-musl": { - "version": "15.5.4", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-15.5.4.tgz", - "integrity": "sha512-TOK7iTxmXFc45UrtKqWdZ1shfxuL4tnVAOuuJK4S88rX3oyVV4ZkLjtMT85wQkfBrOOvU55aLty+MV8xmcJR8A==", + "version": "14.2.33", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.2.33.tgz", + "integrity": "sha512-Bm+QulsAItD/x6Ih8wGIMfRJy4G73tu1HJsrccPW6AfqdZd0Sfm5Imhgkgq2+kly065rYMnCOxTBvmvFY1BKfg==", "cpu": [ "arm64" ], @@ -1787,9 +1361,9 @@ } }, "node_modules/@next/swc-linux-x64-gnu": { - "version": "15.5.4", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-15.5.4.tgz", - "integrity": "sha512-7HKolaj+481FSW/5lL0BcTkA4Ueam9SPYWyN/ib/WGAFZf0DGAN8frNpNZYFHtM4ZstrHZS3LY3vrwlIQfsiMA==", + "version": "14.2.33", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.2.33.tgz", + "integrity": "sha512-FnFn+ZBgsVMbGDsTqo8zsnRzydvsGV8vfiWwUo1LD8FTmPTdV+otGSWKc4LJec0oSexFnCYVO4hX8P8qQKaSlg==", "cpu": [ "x64" ], @@ -1803,9 +1377,9 @@ } }, "node_modules/@next/swc-linux-x64-musl": { - "version": "15.5.4", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-15.5.4.tgz", - "integrity": "sha512-nlQQ6nfgN0nCO/KuyEUwwOdwQIGjOs4WNMjEUtpIQJPR2NUfmGpW2wkJln1d4nJ7oUzd1g4GivH5GoEPBgfsdw==", + "version": "14.2.33", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.2.33.tgz", + "integrity": "sha512-345tsIWMzoXaQndUTDv1qypDRiebFxGYx9pYkhwY4hBRaOLt8UGfiWKr9FSSHs25dFIf8ZqIFaPdy5MljdoawA==", "cpu": [ "x64" ], @@ -1819,9 +1393,9 @@ } }, "node_modules/@next/swc-win32-arm64-msvc": { - "version": "15.5.4", - "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-15.5.4.tgz", - "integrity": "sha512-PcR2bN7FlM32XM6eumklmyWLLbu2vs+D7nJX8OAIoWy69Kef8mfiN4e8TUv2KohprwifdpFKPzIP1njuCjD0YA==", + "version": "14.2.33", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.2.33.tgz", + "integrity": "sha512-nscpt0G6UCTkrT2ppnJnFsYbPDQwmum4GNXYTeoTIdsmMydSKFz9Iny2jpaRupTb+Wl298+Rh82WKzt9LCcqSQ==", "cpu": [ "arm64" ], @@ -1834,6 +1408,38 @@ "node": ">= 10" } }, + "node_modules/@next/swc-win32-ia32-msvc": { + "version": "14.2.33", + "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.2.33.tgz", + "integrity": "sha512-pc9LpGNKhJ0dXQhZ5QMmYxtARwwmWLpeocFmVG5Z0DzWq5Uf0izcI8tLc+qOpqxO1PWqZ5A7J1blrUIKrIFc7Q==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-x64-msvc": { + "version": "14.2.33", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.2.33.tgz", + "integrity": "sha512-nOjfZMy8B94MdisuzZo9/57xuFVLHJaDj5e/xrduJp9CV2/HrfxTRH2fbyLe+K9QT41WBLUd4iXX3R7jBp0EUg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -2463,13 +2069,20 @@ "dev": true, "license": "MIT" }, + "node_modules/@swc/counter": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz", + "integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==", + "license": "Apache-2.0" + }, "node_modules/@swc/helpers": { - "version": "0.5.15", - "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz", - "integrity": "sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==", + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.5.tgz", + "integrity": "sha512-KGYxvIOXcceOAbEk4bi/dVLEK9z8sZ0uBB3Il5b1rhfClSpcX0yfRO0KmTkqR2cnQDymwLB+25ZyMzICg/cm/A==", "license": "Apache-2.0", "dependencies": { - "tslib": "^2.8.0" + "@swc/counter": "^0.1.3", + "tslib": "^2.4.0" } }, "node_modules/@tanstack/react-table": { @@ -3651,6 +3264,17 @@ "dev": true, "license": "MIT" }, + "node_modules/busboy": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", + "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", + "dependencies": { + "streamsearch": "^1.1.0" + }, + "engines": { + "node": ">=10.16.0" + } + }, "node_modules/call-bind": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", @@ -4051,16 +3675,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/detect-libc": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", - "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", - "license": "Apache-2.0", - "optional": true, - "engines": { - "node": ">=8" - } - }, "node_modules/detect-node-es": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz", @@ -5392,6 +5006,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "license": "ISC" + }, "node_modules/graphemer": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", @@ -6032,7 +5652,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true, "license": "MIT" }, "node_modules/js-yaml": { @@ -6189,7 +5808,6 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "dev": true, "license": "MIT", "dependencies": { "js-tokens": "^3.0.0 || ^4.0.0" @@ -6342,40 +5960,41 @@ "license": "MIT" }, "node_modules/next": { - "version": "15.5.4", - "resolved": "https://registry.npmjs.org/next/-/next-15.5.4.tgz", - "integrity": "sha512-xH4Yjhb82sFYQfY3vbkJfgSDgXvBB6a8xPs9i35k6oZJRoQRihZH+4s9Yo2qsWpzBmZ3lPXaJ2KPXLfkvW4LnA==", + "version": "14.2.33", + "resolved": "https://registry.npmjs.org/next/-/next-14.2.33.tgz", + "integrity": "sha512-GiKHLsD00t4ACm1p00VgrI0rUFAC9cRDGReKyERlM57aeEZkOQGcZTpIbsGn0b562FTPJWmYfKwplfO9EaT6ng==", "license": "MIT", "dependencies": { - "@next/env": "15.5.4", - "@swc/helpers": "0.5.15", + "@next/env": "14.2.33", + "@swc/helpers": "0.5.5", + "busboy": "1.6.0", "caniuse-lite": "^1.0.30001579", + "graceful-fs": "^4.2.11", "postcss": "8.4.31", - "styled-jsx": "5.1.6" + "styled-jsx": "5.1.1" }, "bin": { "next": "dist/bin/next" }, "engines": { - "node": "^18.18.0 || ^19.8.0 || >= 20.0.0" + "node": ">=18.17.0" }, "optionalDependencies": { - "@next/swc-darwin-arm64": "15.5.4", - "@next/swc-darwin-x64": "15.5.4", - "@next/swc-linux-arm64-gnu": "15.5.4", - "@next/swc-linux-arm64-musl": "15.5.4", - "@next/swc-linux-x64-gnu": "15.5.4", - "@next/swc-linux-x64-musl": "15.5.4", - "@next/swc-win32-arm64-msvc": "15.5.4", - "@next/swc-win32-x64-msvc": "15.5.4", - "sharp": "^0.34.3" + "@next/swc-darwin-arm64": "14.2.33", + "@next/swc-darwin-x64": "14.2.33", + "@next/swc-linux-arm64-gnu": "14.2.33", + "@next/swc-linux-arm64-musl": "14.2.33", + "@next/swc-linux-x64-gnu": "14.2.33", + "@next/swc-linux-x64-musl": "14.2.33", + "@next/swc-win32-arm64-msvc": "14.2.33", + "@next/swc-win32-ia32-msvc": "14.2.33", + "@next/swc-win32-x64-msvc": "14.2.33" }, "peerDependencies": { "@opentelemetry/api": "^1.1.0", - "@playwright/test": "^1.51.1", - "babel-plugin-react-compiler": "*", - "react": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", - "react-dom": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", + "@playwright/test": "^1.41.2", + "react": "^18.2.0", + "react-dom": "^18.2.0", "sass": "^1.3.0" }, "peerDependenciesMeta": { @@ -6385,30 +6004,11 @@ "@playwright/test": { "optional": true }, - "babel-plugin-react-compiler": { - "optional": true - }, "sass": { "optional": true } } }, - "node_modules/next/node_modules/@next/swc-win32-x64-msvc": { - "version": "15.5.4", - "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-15.5.4.tgz", - "integrity": "sha512-1ur2tSHZj8Px/KMAthmuI9FMp/YFusMMGoRNJaRZMOlSkgvLjzosSdQI0cJAKogdHl3qXUQKL9MGaYvKwA7DXg==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, "node_modules/next/node_modules/postcss": { "version": "8.4.31", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", @@ -6615,6 +6215,16 @@ "node": ">= 0.8.0" } }, + "node_modules/oracledb": { + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/oracledb/-/oracledb-6.10.0.tgz", + "integrity": "sha512-kGUumXmrEWbSpBuKJyb9Ip3rXcNgKK6grunI3/cLPzrRvboZ6ZoLi9JQ+z6M/RIG924tY8BLflihL4CKKQAYMA==", + "hasInstallScript": true, + "license": "(Apache-2.0 OR UPL-1.0)", + "engines": { + "node": ">=14.17" + } + }, "node_modules/own-keys": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/own-keys/-/own-keys-1.0.1.tgz", @@ -7123,24 +6733,28 @@ "license": "MIT" }, "node_modules/react": { - "version": "19.1.0", - "resolved": "https://registry.npmjs.org/react/-/react-19.1.0.tgz", - "integrity": "sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg==", + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", + "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + }, "engines": { "node": ">=0.10.0" } }, "node_modules/react-dom": { - "version": "19.1.0", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.0.tgz", - "integrity": "sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g==", + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", "license": "MIT", "dependencies": { - "scheduler": "^0.26.0" + "loose-envify": "^1.1.0", + "scheduler": "^0.23.2" }, "peerDependencies": { - "react": "^19.1.0" + "react": "^18.3.1" } }, "node_modules/react-is": { @@ -7418,16 +7032,19 @@ } }, "node_modules/scheduler": { - "version": "0.26.0", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.26.0.tgz", - "integrity": "sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==", - "license": "MIT" + "version": "0.23.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", + "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + } }, "node_modules/semver": { "version": "7.7.3", "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", - "devOptional": true, + "dev": true, "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -7485,49 +7102,6 @@ "node": ">= 0.4" } }, - "node_modules/sharp": { - "version": "0.34.4", - "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.4.tgz", - "integrity": "sha512-FUH39xp3SBPnxWvd5iib1X8XY7J0K0X7d93sie9CJg2PO8/7gmg89Nve6OjItK53/MlAushNNxteBYfM6DEuoA==", - "hasInstallScript": true, - "license": "Apache-2.0", - "optional": true, - "dependencies": { - "@img/colour": "^1.0.0", - "detect-libc": "^2.1.0", - "semver": "^7.7.2" - }, - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-darwin-arm64": "0.34.4", - "@img/sharp-darwin-x64": "0.34.4", - "@img/sharp-libvips-darwin-arm64": "1.2.3", - "@img/sharp-libvips-darwin-x64": "1.2.3", - "@img/sharp-libvips-linux-arm": "1.2.3", - "@img/sharp-libvips-linux-arm64": "1.2.3", - "@img/sharp-libvips-linux-ppc64": "1.2.3", - "@img/sharp-libvips-linux-s390x": "1.2.3", - "@img/sharp-libvips-linux-x64": "1.2.3", - "@img/sharp-libvips-linuxmusl-arm64": "1.2.3", - "@img/sharp-libvips-linuxmusl-x64": "1.2.3", - "@img/sharp-linux-arm": "0.34.4", - "@img/sharp-linux-arm64": "0.34.4", - "@img/sharp-linux-ppc64": "0.34.4", - "@img/sharp-linux-s390x": "0.34.4", - "@img/sharp-linux-x64": "0.34.4", - "@img/sharp-linuxmusl-arm64": "0.34.4", - "@img/sharp-linuxmusl-x64": "0.34.4", - "@img/sharp-wasm32": "0.34.4", - "@img/sharp-win32-arm64": "0.34.4", - "@img/sharp-win32-ia32": "0.34.4", - "@img/sharp-win32-x64": "0.34.4" - } - }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -7712,6 +7286,14 @@ "node": ">= 0.4" } }, + "node_modules/streamsearch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", + "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/string-width": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", @@ -7953,9 +7535,9 @@ } }, "node_modules/styled-jsx": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.6.tgz", - "integrity": "sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.1.tgz", + "integrity": "sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw==", "license": "MIT", "dependencies": { "client-only": "0.0.1" @@ -7964,7 +7546,7 @@ "node": ">= 12.0.0" }, "peerDependencies": { - "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0" + "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0" }, "peerDependenciesMeta": { "@babel/core": { @@ -8782,21 +8364,6 @@ "funding": { "url": "https://github.com/sponsors/sindresorhus" } - }, - "node_modules/@next/swc-win32-x64-msvc": { - "version": "15.5.4", - "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-15.5.4.tgz", - "integrity": "sha512-1ur2tSHZj8Px/KMAthmuI9FMp/YFusMMGoRNJaRZMOlSkgvLjzosSdQI0cJAKogdHl3qXUQKL9MGaYvKwA7DXg==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } } } } diff --git a/package.json b/package.json index d7e1547..6a855d1 100644 --- a/package.json +++ b/package.json @@ -19,10 +19,11 @@ "dotenv": "^17.2.3", "drizzle-orm": "^0.44.6", "lucide-react": "^0.545.0", - "next": "15.5.4", + "next": "^14.2.33", + "oracledb": "^6.9.0", "pg": "^8.16.3", - "react": "19.1.0", - "react-dom": "19.1.0", + "react": "^18.3.1", + "react-dom": "^18.3.1", "tailwind-merge": "^3.3.1", "xlsx": "^0.18.5" }, diff --git a/src/app/api/oracle-test/route.ts b/src/app/api/oracle-test/route.ts new file mode 100644 index 0000000..65a6b86 --- /dev/null +++ b/src/app/api/oracle-test/route.ts @@ -0,0 +1,34 @@ +import { NextRequest, NextResponse } from 'next/server'; +import { executeOracleQuery } from '@/db/oracle'; + +export async function GET(request: NextRequest) { + try { + console.log('🔄 Testando conexão Oracle...'); + + // Query de teste conforme solicitado + const sql = `SELECT * FROM DRE_RESULTADO WHERE codgrupo = '08'`; + + const data = await executeOracleQuery(sql); + + console.log('✅ Query executada com sucesso:', data.length, 'registros encontrados'); + + return NextResponse.json({ + success: true, + data, + count: data.length, + message: `Encontrados ${data.length} registros na tabela DRE_RESULTADO` + }); + + } catch (error) { + console.error('❌ Erro ao conectar com Oracle:', error); + + return NextResponse.json( + { + success: false, + error: error instanceof Error ? error.message : 'Erro desconhecido', + details: error instanceof Error ? error.stack : undefined + }, + { status: 500 } + ); + } +} diff --git a/src/db/index.ts b/src/db/index.ts index 2fbe07a..891d3bc 100644 --- a/src/db/index.ts +++ b/src/db/index.ts @@ -3,6 +3,7 @@ import { drizzle } from 'drizzle-orm/node-postgres'; import { Pool } from 'pg'; import * as schema from './schema'; +// PostgreSQL Configuration const pool = new Pool({ database: process.env.POSTGRES_DB, host: process.env.POSTGRES_HOST, @@ -16,4 +17,6 @@ const db = drizzle({ schema, }); +// Export both PostgreSQL and Oracle connections export default db; +export { executeOracleQuery, getOraclePool, closeOraclePool } from './oracle'; diff --git a/src/db/oracle.ts b/src/db/oracle.ts new file mode 100644 index 0000000..a10357d --- /dev/null +++ b/src/db/oracle.ts @@ -0,0 +1,69 @@ +import 'dotenv/config'; +import oracledb from 'oracledb'; + +// Configurar o caminho do Oracle Instant Client +if (process.env.ORACLE_LIB_DIR) { + oracledb.initOracleClient({ libDir: process.env.ORACLE_LIB_DIR }); +} + +// Configuração do pool de conexões Oracle +const oracleConfig = { + user: process.env.ORACLE_USER, + password: process.env.ORACLE_PASSWORD, + connectString: process.env.ORACLE_CONNECTION_STRING, + poolMin: Number(process.env.ORACLE_POOL_MIN) || 1, + poolMax: Number(process.env.ORACLE_POOL_MAX) || 30, + poolIncrement: Number(process.env.ORACLE_POOL_INCREMENT) || 1, + queueTimeout: Number(process.env.ORACLE_QUEUE_TIMEOUT) || 60000, + poolTimeout: Number(process.env.ORACLE_INACTIVITY_TIMEOUT) || 20000, +}; + +// Criar pool de conexões +let pool: oracledb.Pool | null = null; + +export async function getOraclePool(): Promise { + if (!pool) { + try { + pool = await oracledb.createPool(oracleConfig); + console.log('✅ Pool Oracle criado com sucesso'); + } catch (error) { + console.error('❌ Erro ao criar pool Oracle:', error); + throw error; + } + } + return pool; +} + +export async function executeOracleQuery(sql: string, binds: any[] = []): Promise { + const pool = await getOraclePool(); + let connection: oracledb.Connection | null = null; + + try { + connection = await pool.getConnection(); + const result = await connection.execute(sql, binds, { + outFormat: oracledb.OUT_FORMAT_OBJECT, + }); + return result.rows || []; + } catch (error) { + console.error('❌ Erro ao executar query Oracle:', error); + throw error; + } finally { + if (connection) { + await connection.close(); + } + } +} + +export async function closeOraclePool(): Promise { + if (pool) { + await pool.close(); + pool = null; + console.log('✅ Pool Oracle fechado'); + } +} + +export default { + getOraclePool, + executeOracleQuery, + closeOraclePool, +}; From a1d22d3ac6db1af7062e8aa9360b016939c6b725 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alessandro=20Gon=C3=A7aalves?= Date: Mon, 20 Oct 2025 23:43:13 -0300 Subject: [PATCH 20/30] =?UTF-8?q?feat:=20integra=C3=A7=C3=A3o=20da=20consu?= =?UTF-8?q?lta=20sintetica=20com=20a=20aplica=C3=A7=C3=A3o?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/DRE/analitico.tsx | 6 ++--- src/app/DRE/teste.tsx | 2 +- src/app/api/dre-oracle/route.ts | 42 +++++++++++++++++++++++++++++++++ src/app/layout.tsx | 12 +++++----- 4 files changed, 52 insertions(+), 10 deletions(-) create mode 100644 src/app/api/dre-oracle/route.ts diff --git a/src/app/DRE/analitico.tsx b/src/app/DRE/analitico.tsx index 1ce3948..121c9ba 100644 --- a/src/app/DRE/analitico.tsx +++ b/src/app/DRE/analitico.tsx @@ -335,10 +335,10 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { // Usar EXATAMENTE a mesma lógica do totalValor const filteredData = table.getRowModel().rows.map((row) => row.original); const valorRealizado = filteredData.reduce((sum, item) => { - const valor = + const valor = typeof item.valor === "string" ? parseFloat(item.valor) : item.valor; - return sum + (isNaN(valor) ? 0 : valor); - }, 0); + return sum + (isNaN(valor) ? 0 : valor); + }, 0); return { valorRealizado, diff --git a/src/app/DRE/teste.tsx b/src/app/DRE/teste.tsx index 4df3065..f086d82 100644 --- a/src/app/DRE/teste.tsx +++ b/src/app/DRE/teste.tsx @@ -62,7 +62,7 @@ export default function Teste() { try { setLoading(true); setError(null); - const response = await fetch("/api/dre"); + const response = await fetch("/api/dre-oracle"); if (!response.ok) { throw new Error(`Erro ao carregar dados: ${response.status}`); diff --git a/src/app/api/dre-oracle/route.ts b/src/app/api/dre-oracle/route.ts new file mode 100644 index 0000000..a97f8d3 --- /dev/null +++ b/src/app/api/dre-oracle/route.ts @@ -0,0 +1,42 @@ +import { NextRequest, NextResponse } from 'next/server'; +import { executeOracleQuery } from '@/db/oracle'; + +export async function GET(request: NextRequest) { + try { + console.log('🔄 Buscando dados DRE do Oracle...'); + + // Query para buscar dados da tabela DRE_RESULTADO + const sql = `SELECT * FROM DRE_RESULTADO ORDER BY CODGRUPO, CODCONTA, CODCENTROCUSTO`; + + const data = await executeOracleQuery(sql); + + console.log('✅ Query executada com sucesso:', data.length, 'registros encontrados'); + + // Transformar os dados do Oracle para o formato esperado pelo componente + const transformedData = data.map((item: any) => ({ + codfilial: "001", // Valor padrão + data_competencia: item.DATA || "2023-03", // Usar DATA do Oracle + data_cai: item.DATA || "2023-03", // Usar DATA do Oracle + grupo: item.GRUPO || "", // Usar GRUPO do Oracle + subgrupo: item.CENTROCUSTO || "", // Usar CENTROCUSTO como subgrupo + centro_custo: item.CODIGOCENTROCUSTO || "", // Usar CODIGOCENTROCUSTO + codigo_conta: parseInt(item.CODCONTA) || 0, // Converter CODCONTA para número + conta: item.CONTA || "", // Usar CONTA do Oracle + valor: item.VALOR?.toString() || "0", // Converter VALOR para string + })); + + return NextResponse.json(transformedData); + + } catch (error) { + console.error('❌ Erro ao buscar dados DRE do Oracle:', error); + + return NextResponse.json( + { + success: false, + error: error instanceof Error ? error.message : 'Erro desconhecido', + details: error instanceof Error ? error.stack : undefined + }, + { status: 500 } + ); + } +} diff --git a/src/app/layout.tsx b/src/app/layout.tsx index e5bf306..ce493fe 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -1,14 +1,14 @@ import type { Metadata } from 'next'; -import { Geist, Geist_Mono } from 'next/font/google'; +import { Inter, JetBrains_Mono } from 'next/font/google'; import './globals.css'; -const geistSans = Geist({ - variable: '--font-geist-sans', +const inter = Inter({ + variable: '--font-inter', subsets: ['latin'], }); -const geistMono = Geist_Mono({ - variable: '--font-geist-mono', +const jetbrainsMono = JetBrains_Mono({ + variable: '--font-jetbrains-mono', subsets: ['latin'], }); @@ -25,7 +25,7 @@ export default function RootLayout({ return ( {children} From 6f14b655f5ae8ef398f820c4a032d33843f62359 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alessandro=20Gon=C3=A7aalves?= Date: Tue, 21 Oct 2025 00:07:52 -0300 Subject: [PATCH 21/30] =?UTF-8?q?fix:=20organiza=C3=A7=C3=A3o=20dos=20grup?= =?UTF-8?q?os=20por=20cod=5Fgrupo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/DRE/teste.tsx | 94 ++++++++---- src/app/api/dre-oracle/route.ts | 263 ++++++++++++++++++++++++++++++-- 2 files changed, 317 insertions(+), 40 deletions(-) diff --git a/src/app/DRE/teste.tsx b/src/app/DRE/teste.tsx index f086d82..681e0b8 100644 --- a/src/app/DRE/teste.tsx +++ b/src/app/DRE/teste.tsx @@ -14,6 +14,8 @@ interface DREItem { codigo_conta: number; conta: string; valor: string; + codgrupo?: string; + isCalculado?: boolean; } interface HierarchicalRow { @@ -257,38 +259,33 @@ export default function Teste() { const buildHierarchicalData = (): HierarchicalRow[] => { const rows: HierarchicalRow[] = []; - // Agrupar por grupo, mas tratar grupo 05 como subgrupo do grupo 04 + // Agrupar por grupo const grupos = data.reduce((acc, item) => { - // Se for grupo 05, adicionar ao grupo 04 como subgrupo - if (item.grupo.includes("05")) { - // Encontrar grupo 04 existente ou criar um - const grupo04Key = Object.keys(acc).find((key) => key.includes("04")); - if (grupo04Key) { - acc[grupo04Key].push(item); - } else { - // Se não existe grupo 04, criar um grupo especial - const grupo04Nome = - Object.keys(acc).find((key) => key.includes("04")) || - "04 - GRUPO 04"; - if (!acc[grupo04Nome]) { - acc[grupo04Nome] = []; - } - acc[grupo04Nome].push(item); - } - } else { - // Para outros grupos, agrupar normalmente - if (!acc[item.grupo]) { - acc[item.grupo] = []; - } - acc[item.grupo].push(item); + if (!acc[item.grupo]) { + acc[item.grupo] = []; } + acc[item.grupo].push(item); return acc; }, {} as Record); - // Ordenar grupos - const sortedGrupos = Object.entries(grupos).sort(([a], [b]) => - a.localeCompare(b) - ); + // Ordenar grupos pelo CODGRUPO numérico + const sortedGrupos = Object.entries(grupos).sort(([grupoA, itemsA], [grupoB, itemsB]) => { + // Pegar o CODGRUPO do primeiro item de cada grupo + const codgrupoA = itemsA[0]?.codgrupo || ""; + const codgrupoB = itemsB[0]?.codgrupo || ""; + + // Se ambos têm CODGRUPO, ordenar numericamente + if (codgrupoA && codgrupoB) { + return parseInt(codgrupoA) - parseInt(codgrupoB); + } + + // Se apenas um tem CODGRUPO, ele vem primeiro + if (codgrupoA && !codgrupoB) return -1; + if (!codgrupoA && codgrupoB) return 1; + + // Se nenhum tem CODGRUPO, ordenar alfabeticamente + return grupoA.localeCompare(grupoB); + }); sortedGrupos.forEach(([grupo, items]) => { const totalGrupo = items.reduce( @@ -461,8 +458,25 @@ export default function Teste() { " bg-gradient-to-r from-blue-100 to-indigo-100 border-l-4 border-blue-500 shadow-lg"; } + // Verificar se é um grupo calculado + const isCalculado = row.grupo?.includes("CALCULADO") || + row.grupo?.includes("FATURAMENTO LÍQUIDO") || + row.grupo?.includes("LUCRO BRUTO") || + row.grupo?.includes("MARGEM LOJA") || + row.grupo?.includes("RESULTADO OPERACIONAL") || + row.grupo?.includes("RESULTADO FINANCEIRO") || + row.grupo?.includes("OUTRAS RECEITAS / DESPESAS") || + row.grupo?.includes("LAIR") || + row.grupo?.includes("IR") || + row.grupo?.includes("CSLL") || + row.grupo?.includes("LUCRO LÍQUIDO") || + row.grupo?.includes("EBITDA"); + switch (row.type) { case "grupo": + if (isCalculado) { + return `${style} bg-gradient-to-r from-green-50/30 to-emerald-50/20 font-bold text-gray-900 border-b-2 border-green-200 border-l-4 border-green-400`; + } 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-gradient-to-r from-gray-50/30 to-blue-50/20 font-semibold text-gray-800`; @@ -480,6 +494,20 @@ export default function Teste() { }; const renderCellContent = (row: HierarchicalRow) => { + // Verificar se é um grupo calculado + const isCalculado = row.grupo?.includes("CALCULADO") || + row.grupo?.includes("FATURAMENTO LÍQUIDO") || + row.grupo?.includes("LUCRO BRUTO") || + row.grupo?.includes("MARGEM LOJA") || + row.grupo?.includes("RESULTADO OPERACIONAL") || + row.grupo?.includes("RESULTADO FINANCEIRO") || + row.grupo?.includes("OUTRAS RECEITAS / DESPESAS") || + row.grupo?.includes("LAIR") || + row.grupo?.includes("IR") || + row.grupo?.includes("CSLL") || + row.grupo?.includes("LUCRO LÍQUIDO") || + row.grupo?.includes("EBITDA"); + switch (row.type) { case "grupo": return ( @@ -498,7 +526,17 @@ export default function Teste() { onClick={() => handleRowClick(row)} className="flex-1 text-left hover:bg-blue-50/50 p-2 rounded-lg cursor-pointer transition-all duration-200 truncate" > - {row.grupo} +
+ {isCalculado && ( + + )} + + {row.grupo} + + {isCalculado && ( + (CALCULADO) + )} +
); diff --git a/src/app/api/dre-oracle/route.ts b/src/app/api/dre-oracle/route.ts index a97f8d3..f6efbdf 100644 --- a/src/app/api/dre-oracle/route.ts +++ b/src/app/api/dre-oracle/route.ts @@ -13,19 +13,31 @@ export async function GET(request: NextRequest) { console.log('✅ Query executada com sucesso:', data.length, 'registros encontrados'); // Transformar os dados do Oracle para o formato esperado pelo componente - const transformedData = data.map((item: any) => ({ - codfilial: "001", // Valor padrão - data_competencia: item.DATA || "2023-03", // Usar DATA do Oracle - data_cai: item.DATA || "2023-03", // Usar DATA do Oracle - grupo: item.GRUPO || "", // Usar GRUPO do Oracle - subgrupo: item.CENTROCUSTO || "", // Usar CENTROCUSTO como subgrupo - centro_custo: item.CODIGOCENTROCUSTO || "", // Usar CODIGOCENTROCUSTO - codigo_conta: parseInt(item.CODCONTA) || 0, // Converter CODCONTA para número - conta: item.CONTA || "", // Usar CONTA do Oracle - valor: item.VALOR?.toString() || "0", // Converter VALOR para string - })); + const transformedData = data.map((item: any) => { + const codgrupo = item.CODGRUPO || ""; + const nomeGrupo = item.GRUPO || ""; + + return { + codfilial: "001", // Valor padrão + data_competencia: item.DATA || "2023-03", // Usar DATA do Oracle + data_cai: item.DATA || "2023-03", // Usar DATA do Oracle + grupo: codgrupo ? `${codgrupo} - ${nomeGrupo}` : nomeGrupo, // Concatenar código + nome + subgrupo: item.CENTROCUSTO || "", // Usar CENTROCUSTO como subgrupo + centro_custo: item.CODIGOCENTROCUSTO || "", // Usar CODIGOCENTROCUSTO + codigo_conta: parseInt(item.CODCONTA) || 0, // Converter CODCONTA para número + conta: item.CONTA || "", // Usar CONTA do Oracle + valor: item.VALOR?.toString() || "0", // Converter VALOR para string + codgrupo: codgrupo, // Adicionar código do grupo para cálculos + }; + }); - return NextResponse.json(transformedData); + // Criar grupos calculados que não existem no Oracle + const gruposCalculados = criarGruposCalculados(transformedData); + + // Combinar dados originais com grupos calculados + const dadosCompletos = [...transformedData, ...gruposCalculados]; + + return NextResponse.json(dadosCompletos); } catch (error) { console.error('❌ Erro ao buscar dados DRE do Oracle:', error); @@ -40,3 +52,230 @@ export async function GET(request: NextRequest) { ); } } + +function criarGruposCalculados(dados: any[]) { + const gruposCalculados: any[] = []; + + // Agrupar dados por mês para cálculos + const dadosPorMes = dados.reduce((acc, item) => { + const mes = item.data_competencia; + if (!acc[mes]) acc[mes] = []; + acc[mes].push(item); + return acc; + }, {} as Record); + + // Para cada mês, criar os grupos calculados + Object.keys(dadosPorMes).forEach(mes => { + const dadosMes = dadosPorMes[mes]; + + // Calcular valores por grupo usando código numérico + const valoresPorGrupo = dadosMes.reduce((acc, item) => { + const codgrupo = item.codgrupo; + if (!acc[codgrupo]) acc[codgrupo] = 0; + acc[codgrupo] += parseFloat(item.valor); + return acc; + }, {} as Record); + + // 03 - Faturamento Líquido (01 + 02) + const faturamentoBruto = valoresPorGrupo['01'] || 0; + const devolucao = valoresPorGrupo['02'] || 0; + const faturamentoLiquido = faturamentoBruto + devolucao; + + gruposCalculados.push({ + codfilial: "001", + data_competencia: mes, + data_cai: mes, + grupo: "03 - FATURAMENTO LÍQUIDO", + subgrupo: "CALCULADO", + centro_custo: "CALCULADO", + codigo_conta: 0, + conta: "FATURAMENTO LÍQUIDO", + valor: faturamentoLiquido.toString(), + codgrupo: "03", + isCalculado: true + }); + + // 05 - Lucro Bruto (03 + 04) + const cmv = valoresPorGrupo['04'] || 0; + const lucroBruto = faturamentoLiquido + cmv; + + gruposCalculados.push({ + codfilial: "001", + data_competencia: mes, + data_cai: mes, + grupo: "05 - LUCRO BRUTO", + subgrupo: "CALCULADO", + centro_custo: "CALCULADO", + codigo_conta: 0, + conta: "LUCRO BRUTO", + valor: lucroBruto.toString(), + codgrupo: "05", + isCalculado: true + }); + + // 07 - Margem Loja (05 + 06) + const receitasGastosDiretos = valoresPorGrupo['06'] || 0; + const margemLoja = lucroBruto + receitasGastosDiretos; + + gruposCalculados.push({ + codfilial: "001", + data_competencia: mes, + data_cai: mes, + grupo: "07 - MARGEM LOJA", + subgrupo: "CALCULADO", + centro_custo: "CALCULADO", + codigo_conta: 0, + conta: "MARGEM LOJA", + valor: margemLoja.toString(), + codgrupo: "07", + isCalculado: true + }); + + // 10 - Resultado Operacional (07 + 08 + 09) + const verba = valoresPorGrupo['08'] || 0; + const receitasGastosIndiretos = valoresPorGrupo['09'] || 0; + const resultadoOperacional = margemLoja + verba + receitasGastosIndiretos; + + gruposCalculados.push({ + codfilial: "001", + data_competencia: mes, + data_cai: mes, + grupo: "10 - RESULTADO OPERACIONAL", + subgrupo: "CALCULADO", + centro_custo: "CALCULADO", + codigo_conta: 0, + conta: "RESULTADO OPERACIONAL", + valor: resultadoOperacional.toString(), + codgrupo: "10", + isCalculado: true + }); + + // 13 - Resultado Financeiro (11 + 12) + const receitaFinanceira = valoresPorGrupo['11'] || 0; + const despesaFinanceira = valoresPorGrupo['12'] || 0; + const resultadoFinanceiro = receitaFinanceira + despesaFinanceira; + + gruposCalculados.push({ + codfilial: "001", + data_competencia: mes, + data_cai: mes, + grupo: "13 - RESULTADO FINANCEIRO", + subgrupo: "CALCULADO", + centro_custo: "CALCULADO", + codigo_conta: 0, + conta: "RESULTADO FINANCEIRO", + valor: resultadoFinanceiro.toString(), + codgrupo: "13", + isCalculado: true + }); + + // 18 - Outras Receitas / Despesas (14 + 15 + 16 + 17) + const prejuizosPerdas = valoresPorGrupo['14'] || 0; + const inativas = valoresPorGrupo['15'] || 0; + const diretoria = valoresPorGrupo['16'] || 0; + const lancamentosSemCC = valoresPorGrupo['17'] || 0; + const outrasReceitasDespesas = prejuizosPerdas + inativas + diretoria + lancamentosSemCC; + + gruposCalculados.push({ + codfilial: "001", + data_competencia: mes, + data_cai: mes, + grupo: "18 - OUTRAS RECEITAS / DESPESAS", + subgrupo: "CALCULADO", + centro_custo: "CALCULADO", + codigo_conta: 0, + conta: "OUTRAS RECEITAS / DESPESAS", + valor: outrasReceitasDespesas.toString(), + codgrupo: "18", + isCalculado: true + }); + + // 19 - LAIR (10 + 13 + 18) + const lair = resultadoOperacional + resultadoFinanceiro + outrasReceitasDespesas; + + gruposCalculados.push({ + codfilial: "001", + data_competencia: mes, + data_cai: mes, + grupo: "19 - LAIR", + subgrupo: "CALCULADO", + centro_custo: "CALCULADO", + codigo_conta: 0, + conta: "LAIR", + valor: lair.toString(), + codgrupo: "19", + isCalculado: true + }); + + // 20 - IR (se LAIR > 0 calcular 20% e resultado negativo, se não 0) + const ir = lair > 0 ? -(lair * 0.20) : 0; + + gruposCalculados.push({ + codfilial: "001", + data_competencia: mes, + data_cai: mes, + grupo: "20 - IR", + subgrupo: "CALCULADO", + centro_custo: "CALCULADO", + codigo_conta: 0, + conta: "IMPOSTO DE RENDA", + valor: ir.toString(), + codgrupo: "20", + isCalculado: true + }); + + // 21 - CSLL (se LAIR > 0 calcular 9% e resultado negativo, se não 0) + const csll = lair > 0 ? -(lair * 0.09) : 0; + + gruposCalculados.push({ + codfilial: "001", + data_competencia: mes, + data_cai: mes, + grupo: "21 - CSLL", + subgrupo: "CALCULADO", + centro_custo: "CALCULADO", + codigo_conta: 0, + conta: "CONTRIBUIÇÃO SOCIAL SOBRE LUCRO LÍQUIDO", + valor: csll.toString(), + codgrupo: "21", + isCalculado: true + }); + + // 22 - Lucro Líquido (19 + 20 + 21) + const lucroLiquido = lair + ir + csll; + + gruposCalculados.push({ + codfilial: "001", + data_competencia: mes, + data_cai: mes, + grupo: "22 - LUCRO LÍQUIDO", + subgrupo: "CALCULADO", + centro_custo: "CALCULADO", + codigo_conta: 0, + conta: "LUCRO LÍQUIDO", + valor: lucroLiquido.toString(), + codgrupo: "22", + isCalculado: true + }); + + // 24 - EBITDA (19 - (13 + 18 + 23)) + const despesaTributaria = valoresPorGrupo['23'] || 0; + const ebitda = lair - (resultadoFinanceiro + outrasReceitasDespesas + despesaTributaria); + + gruposCalculados.push({ + codfilial: "001", + data_competencia: mes, + data_cai: mes, + grupo: "24 - EBITDA", + subgrupo: "CALCULADO", + centro_custo: "CALCULADO", + codigo_conta: 0, + conta: "EBITDA", + valor: ebitda.toString(), + codgrupo: "24", + isCalculado: true + }); + }); + + return gruposCalculados; +} From b80e4ab970eb1b288e968bc1860f9505c76aec46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alessandro=20Gon=C3=A7aalves?= Date: Tue, 21 Oct 2025 00:19:21 -0300 Subject: [PATCH 22/30] =?UTF-8?q?fix:=20ajuste=20na=20estiliza=C3=A7=C3=A3?= =?UTF-8?q?o=20do=20grupos=20calculados?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/DRE/teste.tsx | 24 ++---------------------- 1 file changed, 2 insertions(+), 22 deletions(-) diff --git a/src/app/DRE/teste.tsx b/src/app/DRE/teste.tsx index 681e0b8..8a8fa62 100644 --- a/src/app/DRE/teste.tsx +++ b/src/app/DRE/teste.tsx @@ -458,25 +458,8 @@ export default function Teste() { " bg-gradient-to-r from-blue-100 to-indigo-100 border-l-4 border-blue-500 shadow-lg"; } - // Verificar se é um grupo calculado - const isCalculado = row.grupo?.includes("CALCULADO") || - row.grupo?.includes("FATURAMENTO LÍQUIDO") || - row.grupo?.includes("LUCRO BRUTO") || - row.grupo?.includes("MARGEM LOJA") || - row.grupo?.includes("RESULTADO OPERACIONAL") || - row.grupo?.includes("RESULTADO FINANCEIRO") || - row.grupo?.includes("OUTRAS RECEITAS / DESPESAS") || - row.grupo?.includes("LAIR") || - row.grupo?.includes("IR") || - row.grupo?.includes("CSLL") || - row.grupo?.includes("LUCRO LÍQUIDO") || - row.grupo?.includes("EBITDA"); - switch (row.type) { case "grupo": - if (isCalculado) { - return `${style} bg-gradient-to-r from-green-50/30 to-emerald-50/20 font-bold text-gray-900 border-b-2 border-green-200 border-l-4 border-green-400`; - } 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-gradient-to-r from-gray-50/30 to-blue-50/20 font-semibold text-gray-800`; @@ -527,14 +510,11 @@ export default function Teste() { className="flex-1 text-left hover:bg-blue-50/50 p-2 rounded-lg cursor-pointer transition-all duration-200 truncate" >
- {isCalculado && ( - - )} - + {row.grupo} {isCalculado && ( - (CALCULADO) + )}
From be48b04ee7f26426e2923b438568cb9b19990ec3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alessandro=20Gon=C3=A7aalves?= Date: Tue, 21 Oct 2025 00:49:20 -0300 Subject: [PATCH 23/30] fix: ajuste no fechamento do sheet --- package-lock.json | 24 ++ package.json | 1 + src/app/DRE/teste.tsx | 602 ++++++++++++++++++++++++++++-------- src/components/ui/label.tsx | 24 ++ src/components/ui/sheet.tsx | 138 +++++++++ 5 files changed, 658 insertions(+), 131 deletions(-) create mode 100644 src/components/ui/label.tsx create mode 100644 src/components/ui/sheet.tsx diff --git a/package-lock.json b/package-lock.json index d37ba04..99c4410 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,7 @@ "version": "0.1.0", "dependencies": { "@radix-ui/react-dialog": "^1.1.15", + "@radix-ui/react-label": "^2.1.7", "@radix-ui/react-select": "^2.2.6", "@radix-ui/react-slot": "^1.2.3", "@tanstack/react-table": "^8.21.3", @@ -1726,6 +1727,29 @@ } } }, + "node_modules/@radix-ui/react-label": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-label/-/react-label-2.1.7.tgz", + "integrity": "sha512-YT1GqPSL8kJn20djelMX7/cTRp/Y9w5IZHvfxQTVHrOqa2yMl7i/UfMqKRU5V7mEyKTrUVgJXhNQPVCG8PBLoQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-popper": { "version": "1.2.8", "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.8.tgz", diff --git a/package.json b/package.json index 6a855d1..2c24f01 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ }, "dependencies": { "@radix-ui/react-dialog": "^1.1.15", + "@radix-ui/react-label": "^2.1.7", "@radix-ui/react-select": "^2.2.6", "@radix-ui/react-slot": "^1.2.3", "@tanstack/react-table": "^8.21.3", diff --git a/src/app/DRE/teste.tsx b/src/app/DRE/teste.tsx index 8a8fa62..496e985 100644 --- a/src/app/DRE/teste.tsx +++ b/src/app/DRE/teste.tsx @@ -1,8 +1,27 @@ "use client"; -import { LoaderPinwheel, ChevronDown, ChevronRight } from "lucide-react"; +import { LoaderPinwheel, ChevronDown, ChevronRight, Filter } from "lucide-react"; import { useEffect, useState } from "react"; import AnaliticoComponent from "./analitico"; +import { Button } from "@/components/ui/button"; +import { Input } from "@/components/ui/input"; +import { Label } from "@/components/ui/label"; +import { + Sheet, + SheetContent, + SheetDescription, + SheetFooter, + SheetHeader, + SheetTitle, + SheetTrigger, +} from "@/components/ui/sheet"; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "@/components/ui/select"; interface DREItem { codfilial: string; @@ -34,7 +53,7 @@ interface HierarchicalRow { export default function Teste() { const [data, setData] = useState([]); - const [loading, setLoading] = useState(true); + const [loading, setLoading] = useState(false); const [error, setError] = useState(null); const [expandedGroups, setExpandedGroups] = useState>(new Set()); const [expandedSubgrupos, setExpandedSubgrupos] = useState>( @@ -45,6 +64,28 @@ export default function Teste() { ); const [mesesDisponiveis, setMesesDisponiveis] = useState([]); + // Estados para filtros + const [filtros, setFiltros] = useState({ + periodoDe: "", + periodoAte: "", + grupo: "Todos", + subgrupo: "Todos", + centroCusto: "Todos", + conta: "Todas", + valorMin: "", + valorMax: "", + buscaTextual: "" + }); + const [isFilterOpen, setIsFilterOpen] = useState(false); + const [dadosFiltrados, setDadosFiltrados] = useState([]); + const [filtrosAplicados, setFiltrosAplicados] = useState(false); + + // Estados para opções dos filtros + const [opcoesGrupos, setOpcoesGrupos] = useState([]); + const [opcoesSubgrupos, setOpcoesSubgrupos] = useState([]); + const [opcoesCentrosCusto, setOpcoesCentrosCusto] = useState([]); + const [opcoesContas, setOpcoesContas] = useState([]); + // Estados para analítico const [analiticoFiltros, setAnaliticoFiltros] = useState({ dataInicio: "", @@ -57,9 +98,56 @@ export default function Teste() { const [linhaSelecionada, setLinhaSelecionada] = useState(null); useEffect(() => { - fetchData(); + // Carregar períodos disponíveis da API + carregarPeriodosDisponiveis(); + + // Inicializar filtros com período atual + const agora = new Date(); + const anoAtual = agora.getFullYear(); + const mesAtual = String(agora.getMonth() + 1).padStart(2, '0'); + const periodoAtual = `${anoAtual}-${mesAtual}`; + + setFiltros(prev => ({ + ...prev, + periodoDe: `${anoAtual}-01`, + periodoAte: periodoAtual + })); }, []); + const carregarPeriodosDisponiveis = async () => { + try { + const response = await fetch("/api/dre-oracle"); + if (!response.ok) { + throw new Error(`Erro HTTP: ${response.status}`); + } + + const dadosCompletos = await response.json(); + + // Extrair períodos únicos dos dados + const periodosUnicos = [...new Set(dadosCompletos.map((item: DREItem) => item.data_competencia))].sort(); + setMesesDisponiveis(periodosUnicos); + + // Extrair grupos únicos + const gruposUnicos = [...new Set(dadosCompletos.map((item: DREItem) => item.grupo))].sort(); + setOpcoesGrupos(gruposUnicos); + + // Extrair subgrupos únicos + const subgruposUnicos = [...new Set(dadosCompletos.map((item: DREItem) => item.subgrupo))].sort(); + setOpcoesSubgrupos(subgruposUnicos); + + // Extrair centros de custo únicos + const centrosCustoUnicos = [...new Set(dadosCompletos.map((item: DREItem) => item.centro_custo))].sort(); + setOpcoesCentrosCusto(centrosCustoUnicos); + + // Extrair contas únicas + const contasUnicas = [...new Set(dadosCompletos.map((item: DREItem) => item.conta))].sort(); + setOpcoesContas(contasUnicas); + + } catch (error) { + console.error("Erro ao carregar períodos:", error); + } + }; + const fetchData = async () => { try { setLoading(true); @@ -195,6 +283,139 @@ export default function Teste() { setExpandedCentros(newExpanded); }; + const handleFiltroChange = (campo: string, valor: string) => { + setFiltros(prev => ({ + ...prev, + [campo]: valor + })); + }; + + const limparFiltros = () => { + const agora = new Date(); + const anoAtual = agora.getFullYear(); + const mesAtual = String(agora.getMonth() + 1).padStart(2, '0'); + const periodoAtual = `${anoAtual}-${mesAtual}`; + + setFiltros({ + periodoDe: `${anoAtual}-01`, + periodoAte: periodoAtual, + grupo: "Todos", + subgrupo: "Todos", + centroCusto: "Todos", + conta: "Todas", + valorMin: "", + valorMax: "", + buscaTextual: "" + }); + + // Limpar dados da tabela + setData([]); + setDadosFiltrados([]); + setFiltrosAplicados(false); + setMesesDisponiveis([]); + }; + + const aplicarFiltros = async () => { + // Fechar o Sheet primeiro + setIsFilterOpen(false); + + // Aguardar um pouco para a animação de fechamento + setTimeout(async () => { + try { + setLoading(true); + setError(null); + + // Carregar dados da API + const response = await fetch("/api/dre-oracle"); + if (!response.ok) { + throw new Error(`Erro HTTP: ${response.status}`); + } + + const dadosCompletos = await response.json(); + + // Aplicar filtros nos dados + let dadosFiltrados = dadosCompletos; + + // Filtro por período + if (filtros.periodoDe && filtros.periodoAte) { + dadosFiltrados = dadosFiltrados.filter((item: DREItem) => { + const dataItem = item.data_competencia; + return dataItem >= filtros.periodoDe && dataItem <= filtros.periodoAte; + }); + } + + // Filtro por grupo + if (filtros.grupo !== "Todos") { + dadosFiltrados = dadosFiltrados.filter((item: DREItem) => + item.grupo === filtros.grupo + ); + } + + // Filtro por subgrupo + if (filtros.subgrupo !== "Todos") { + dadosFiltrados = dadosFiltrados.filter((item: DREItem) => + item.subgrupo === filtros.subgrupo + ); + } + + // Filtro por centro de custo + if (filtros.centroCusto !== "Todos") { + dadosFiltrados = dadosFiltrados.filter((item: DREItem) => + item.centro_custo === filtros.centroCusto + ); + } + + // Filtro por conta + if (filtros.conta !== "Todas") { + dadosFiltrados = dadosFiltrados.filter((item: DREItem) => + item.conta === filtros.conta + ); + } + + // Filtro por valor mínimo + if (filtros.valorMin) { + const valorMin = parseFloat(filtros.valorMin.replace(',', '.')); + dadosFiltrados = dadosFiltrados.filter((item: DREItem) => + parseFloat(item.valor) >= valorMin + ); + } + + // Filtro por valor máximo + if (filtros.valorMax) { + const valorMax = parseFloat(filtros.valorMax.replace(',', '.')); + dadosFiltrados = dadosFiltrados.filter((item: DREItem) => + parseFloat(item.valor) <= valorMax + ); + } + + // Filtro por busca textual + if (filtros.buscaTextual) { + const termoBusca = filtros.buscaTextual.toLowerCase(); + dadosFiltrados = dadosFiltrados.filter((item: DREItem) => + item.grupo.toLowerCase().includes(termoBusca) || + item.subgrupo.toLowerCase().includes(termoBusca) || + item.centro_custo.toLowerCase().includes(termoBusca) || + item.conta.toLowerCase().includes(termoBusca) + ); + } + + setData(dadosFiltrados); + setDadosFiltrados(dadosFiltrados); + setFiltrosAplicados(true); + + // Extrair meses únicos dos dados filtrados + const mesesUnicos = [...new Set(dadosFiltrados.map(item => item.data_competencia))].sort(); + setMesesDisponiveis(mesesUnicos); + + } catch (error) { + console.error("Erro ao aplicar filtros:", error); + setError(error instanceof Error ? error.message : "Erro desconhecido"); + } finally { + setLoading(false); + } + }, 300); // Aguardar 300ms para a animação de fechamento + }; + const calcularValoresPorMes = (items: DREItem[]): Record => { const valoresPorMes: Record = {}; @@ -587,113 +808,9 @@ export default function Teste() { } }; - if (loading) { - return ( -
-
-
- {/*
- - - -
*/} -
-

- DRE Gerencial -

-

- Demonstração do Resultado do Exercício -

-
-
-
+ // Loading será tratado dentro do componente principal -
-
-
- -
-

- Carregando dados... -

-

- Aguarde enquanto processamos as informações -

-
-
-
- ); - } - - if (error) { - return ( -
-
-
- {/*
- - - -
*/} -
-

- DRE Gerencial -

-

- Demonstração do Resultado do Exercício -

-
-
-
- -
-
-
- - - -
-

- Erro ao carregar DRE Gerencial -

-

- {error} -

-
-
-
- ); - } + // Error será tratado dentro do componente principal const hierarchicalData = buildHierarchicalData(); @@ -701,33 +818,255 @@ export default function Teste() {
{/* Header Section */}
-
- {/*
- - - -
*/} -
-

DRE Gerencial

-

- Demonstração do Resultado do Exercício -

+
+
+
+

DRE Gerencial

+

+ Demonstração do Resultado do Exercício +

+
+ + {/* Botão de Filtro */} + + + + + + + Filtros + + Ajuste os critérios e clique em Pesquisar para atualizar a visão. + + + +
+ {/* Período */} +
+ +
+
+ + +
+
+ + +
+
+
+ + {/* Grupo */} +
+ + +
+ + {/* Subgrupo */} +
+ + +
+ + {/* Centro de Custo */} +
+ + +
+ + {/* Conta */} +
+ + +
+ + {/* Valor */} +
+ +
+
+ +
+ R$ + handleFiltroChange('valorMin', e.target.value)} + className="pl-8" + placeholder="0,00" + /> +
+
+
+ +
+ R$ + handleFiltroChange('valorMax', e.target.value)} + className="pl-8" + placeholder="0,00" + /> +
+
+
+
+ + {/* Busca Textual */} +
+ + handleFiltroChange('buscaTextual', e.target.value)} + placeholder="Pesquise por grupo, subgrupo, centro ou conta" + /> +
+
+ + + + + + +
+
+ {/* Loading quando aplicando filtros */} + {loading && ( +
+
+
+ +
+
+

+ Aplicando filtros... +

+

+ Aguarde enquanto processamos os dados. +

+
+
+
+ )} + + {/* Erro */} + {error && !loading && ( +
+
+
+ + + +
+
+

+ Erro ao carregar dados +

+

{error}

+ +
+
+
+ )} + + {/* Mensagem quando não há dados */} + {!filtrosAplicados && !loading && !error && ( +
+
+
+ +
+
+

+ Nenhum dado exibido +

+

+ Clique no botão "Filtros" para definir os critérios de busca e visualizar os dados do DRE. +

+ +
+
+
+ )} + {/* Table Container */} -
+ {filtrosAplicados && !loading && !error && ( +
{/* Table Header */}
@@ -829,6 +1168,7 @@ export default function Teste() { ))}
+ )} {/* Componente Analítico */} {!loading && data.length > 0 && ( diff --git a/src/components/ui/label.tsx b/src/components/ui/label.tsx new file mode 100644 index 0000000..683faa7 --- /dev/null +++ b/src/components/ui/label.tsx @@ -0,0 +1,24 @@ +import * as React from "react" +import * as LabelPrimitive from "@radix-ui/react-label" +import { cva, type VariantProps } from "class-variance-authority" + +import { cn } from "@/lib/utils" + +const labelVariants = cva( + "text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70" +) + +const Label = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef & + VariantProps +>(({ className, ...props }, ref) => ( + +)) +Label.displayName = LabelPrimitive.Root.displayName + +export { Label } diff --git a/src/components/ui/sheet.tsx b/src/components/ui/sheet.tsx new file mode 100644 index 0000000..d3422d0 --- /dev/null +++ b/src/components/ui/sheet.tsx @@ -0,0 +1,138 @@ +import * as React from "react" +import * as SheetPrimitive from "@radix-ui/react-dialog" +import { cva, type VariantProps } from "class-variance-authority" +import { X } from "lucide-react" + +import { cn } from "@/lib/utils" + +const Sheet = SheetPrimitive.Root + +const SheetTrigger = SheetPrimitive.Trigger + +const SheetClose = SheetPrimitive.Close + +const SheetPortal = SheetPrimitive.Portal + +const SheetOverlay = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +SheetOverlay.displayName = SheetPrimitive.Overlay.displayName + +const sheetVariants = cva( + "fixed z-50 gap-4 bg-background p-6 shadow-lg transition ease-in-out data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:duration-300 data-[state=open]:duration-500", + { + variants: { + side: { + top: "inset-x-0 top-0 border-b data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top", + bottom: + "inset-x-0 bottom-0 border-t data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom", + left: "inset-y-0 left-0 h-full w-3/4 border-r data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left sm:max-w-sm", + right: + "inset-y-0 right-0 h-full w-3/4 border-l data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right sm:max-w-sm", + }, + }, + defaultVariants: { + side: "right", + }, + } +) + +interface SheetContentProps + extends React.ComponentPropsWithoutRef, + VariantProps {} + +const SheetContent = React.forwardRef< + React.ElementRef, + SheetContentProps +>(({ side = "right", className, children, ...props }, ref) => ( + + + + {children} + + + Close + + + +)) +SheetContent.displayName = SheetPrimitive.Content.displayName + +const SheetHeader = ({ + className, + ...props +}: React.HTMLAttributes) => ( +
+) +SheetHeader.displayName = "SheetHeader" + +const SheetFooter = ({ + className, + ...props +}: React.HTMLAttributes) => ( +
+) +SheetFooter.displayName = "SheetFooter" + +const SheetTitle = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +SheetTitle.displayName = SheetPrimitive.Title.displayName + +const SheetDescription = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +SheetDescription.displayName = SheetPrimitive.Description.displayName + +export { + Sheet, + SheetPortal, + SheetOverlay, + SheetTrigger, + SheetClose, + SheetContent, + SheetHeader, + SheetFooter, + SheetTitle, + SheetDescription, +} From e6c957e28a689ee9a8f08de41e87f92c83b27e33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alessandro=20Gon=C3=A7aalves?= Date: Tue, 21 Oct 2025 00:52:33 -0300 Subject: [PATCH 24/30] =?UTF-8?q?fix:=20Campos=20do=20filtro=20sint=C3=A9t?= =?UTF-8?q?ico=20ocultados?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/DRE/teste.tsx | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/app/DRE/teste.tsx b/src/app/DRE/teste.tsx index 496e985..0ae7f42 100644 --- a/src/app/DRE/teste.tsx +++ b/src/app/DRE/teste.tsx @@ -878,7 +878,7 @@ export default function Teste() {
- {/* Grupo */} + {/* Grupo
-
+
*/} - {/* Subgrupo */} + {/* Subgrupo
-
+
*/} - {/* Centro de Custo */} + {/* Centro de Custo
-
+
*/} - {/* Conta */} + {/* Conta
-
+
*/} - {/* Valor */} + {/* Valor
@@ -973,9 +973,9 @@ export default function Teste() {
- + */} - {/* Busca Textual */} + {/* Busca Textual
handleFiltroChange('buscaTextual', e.target.value)} placeholder="Pesquise por grupo, subgrupo, centro ou conta" /> -
+ */} From 241141f7945dd1ddfb3d0bf2102922e6a2006017 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alessandro=20Gon=C3=A7aalves?= Date: Tue, 21 Oct 2025 10:08:00 -0300 Subject: [PATCH 25/30] =?UTF-8?q?fix:=20Adi=C3=A7=C3=A3o=20da=20rela=C3=A7?= =?UTF-8?q?=C3=A3o=20sintetico=20x=20anal=C3=ADtico?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/DRE/analitico.tsx | 300 +++++++++++++++++++++----- src/app/DRE/teste.tsx | 4 +- src/app/api/analitico-oracle/route.ts | 61 ++++++ 3 files changed, 314 insertions(+), 51 deletions(-) create mode 100644 src/app/api/analitico-oracle/route.ts diff --git a/src/app/DRE/analitico.tsx b/src/app/DRE/analitico.tsx index 121c9ba..91bc38c 100644 --- a/src/app/DRE/analitico.tsx +++ b/src/app/DRE/analitico.tsx @@ -6,6 +6,7 @@ import { getCoreRowModel, getSortedRowModel, getFilteredRowModel, + ColumnFiltersState, } from "@tanstack/react-table"; import { useVirtualizer } from "@tanstack/react-virtual"; import { Input } from "@/components/ui/input"; @@ -47,6 +48,15 @@ interface AnaliticoItem { 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; } interface AnaliticoProps { @@ -64,36 +74,67 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { const [data, setData] = React.useState([]); const [loading, setLoading] = React.useState(false); const [globalFilter, setGlobalFilter] = React.useState(""); - const [columnFilters, setColumnFilters] = React.useState([]); + const [columnFilters, setColumnFilters] = React.useState([]); const [open, setOpen] = React.useState(false); const [conditions, setConditions] = React.useState([ { column: "", operator: "contains", value: "" }, ]); + + // Estado para armazenar filtros externos (vindos do teste.tsx) + const [filtrosExternos, setFiltrosExternos] = React.useState(filtros); + + // Atualizar filtros externos quando os props mudarem, mas preservar filtros internos + React.useEffect(() => { + setFiltrosExternos(filtros); + }, [filtros]); const fetchData = React.useCallback(async () => { - // Só faz a requisição se tiver dataInicio e dataFim - if (!filtros.dataInicio || !filtros.dataFim) { + // Só faz a requisição se tiver dataInicio e dataFim nos filtros externos + if (!filtrosExternos.dataInicio || !filtrosExternos.dataFim) { setData([]); return; } setLoading(true); try { - const params = new URLSearchParams({ - dataInicio: filtros.dataInicio, - dataFim: filtros.dataFim, - ...(filtros.centroCusto && { centroCusto: filtros.centroCusto }), - ...(filtros.codigoGrupo && { codigoGrupo: filtros.codigoGrupo }), - ...(filtros.codigoSubgrupo && { - codigoSubgrupo: filtros.codigoSubgrupo, - }), - ...(filtros.codigoConta && { codigoConta: filtros.codigoConta }), - }); - - const response = await fetch(`/api/analitico?${params}`); + // Usar a nova API do Oracle + const response = await fetch("/api/analitico-oracle"); if (response.ok) { const result = await response.json(); - setData(result as AnaliticoItem[]); + + // Aplicar filtros externos (vindos do teste.tsx) nos dados retornados + let filteredData = result as AnaliticoItem[]; + + // Filtro por período se especificado nos filtros externos + if (filtrosExternos.dataInicio && filtrosExternos.dataFim) { + filteredData = filteredData.filter((item: AnaliticoItem) => { + const dataItem = item.data_competencia || item.ano_mes_comp; + return dataItem && dataItem >= filtrosExternos.dataInicio && dataItem <= filtrosExternos.dataFim; + }); + } + + // Filtro por centro de custo se especificado nos filtros externos + if (filtrosExternos.centroCusto) { + filteredData = filteredData.filter((item: AnaliticoItem) => + item.codigo_centrocusto === filtrosExternos.centroCusto + ); + } + + // Filtro por código do grupo se especificado nos filtros externos + if (filtrosExternos.codigoGrupo) { + filteredData = filteredData.filter((item: AnaliticoItem) => + item.codgrupo === filtrosExternos.codigoGrupo + ); + } + + // Filtro por código da conta se especificado nos filtros externos + if (filtrosExternos.codigoConta) { + filteredData = filteredData.filter((item: AnaliticoItem) => + item.codigo_conta === filtrosExternos.codigoConta + ); + } + + setData(filteredData); } else { console.error("Erro ao buscar dados:", await response.text()); } @@ -102,7 +143,7 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { } finally { setLoading(false); } - }, [filtros]); + }, [filtrosExternos]); React.useEffect(() => { fetchData(); @@ -132,7 +173,10 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { accessorKey: "entidade", header: "Entidade", filterFn: "advancedText", - cell: () => "-", + cell: ({ getValue }: { getValue: () => string }) => { + const value = getValue(); + return value || "-"; + }, }, { accessorKey: "codigo_fornecedor", @@ -181,19 +225,58 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { accessorKey: "valor_previsto", header: "Valor Previsto", filterFn: "advancedText", - cell: () => "-", + cell: ({ getValue }: { getValue: () => number }) => { + const value = getValue(); + if (!value || value === 0) return "-"; + const formatted = new Intl.NumberFormat("pt-BR", { + style: "currency", + currency: "BRL", + }).format(value); + const isNegative = value < 0; + return ( + + {formatted} + + ); + }, }, { accessorKey: "valor_confirmado", header: "Valor Confirmado", filterFn: "advancedText", - cell: () => "-", + cell: ({ getValue }: { getValue: () => number }) => { + const value = getValue(); + if (!value || value === 0) return "-"; + const formatted = new Intl.NumberFormat("pt-BR", { + style: "currency", + currency: "BRL", + }).format(value); + const isNegative = value < 0; + return ( + + {formatted} + + ); + }, }, { accessorKey: "valor_pago", header: "Valor Pago", filterFn: "advancedText", - cell: () => "-", + cell: ({ getValue }: { getValue: () => number }) => { + const value = getValue(); + if (!value || value === 0) return "-"; + const formatted = new Intl.NumberFormat("pt-BR", { + style: "currency", + currency: "BRL", + }).format(value); + const isNegative = value < 0; + return ( + + {formatted} + + ); + }, }, { accessorKey: "historico", @@ -209,7 +292,10 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { accessorKey: "numero_lancamento", header: "Número do Lançamento", filterFn: "advancedText", - cell: () => "-", + cell: ({ getValue }: { getValue: () => number }) => { + const value = getValue(); + return value || "-"; + }, }, ], [] @@ -217,7 +303,7 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { const filterFns = React.useMemo( () => ({ - advancedText: (row: any, columnId: string, filters: any[]) => { + advancedText: (row: any, columnId: string, filters: ColumnFiltersState) => { if (!filters || filters.length === 0) return true; // Se veio um único filtro (objeto), transforma em array @@ -256,7 +342,7 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { const table = useReactTable({ data, - columns, + columns: columns as any, state: { globalFilter, columnFilters }, onGlobalFilterChange: setGlobalFilter, onColumnFiltersChange: setColumnFilters, @@ -306,6 +392,7 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { setConditions([{ column: "", operator: "contains", value: "" }]); setColumnFilters([]); setGlobalFilter(""); + // Não limpar os filtros externos - eles vêm do teste.tsx }; const [totalValor, setTotalValor] = React.useState(0); @@ -314,7 +401,7 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { // Usar dados filtrados da tabela em vez dos dados originais const filteredData = table.getRowModel().rows.map((row) => row.original); const newTotal = filteredData.reduce((sum, item) => { - const valor = + const valor = typeof item.valor === "string" ? parseFloat(item.valor) : item.valor; return sum + (isNaN(valor) ? 0 : valor); }, 0); @@ -335,18 +422,32 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { // Usar EXATAMENTE a mesma lógica do totalValor const filteredData = table.getRowModel().rows.map((row) => row.original); const valorRealizado = filteredData.reduce((sum, item) => { - const valor = - typeof item.valor === "string" ? parseFloat(item.valor) : item.valor; + const valor = typeof item.valor === "string" ? parseFloat(item.valor) : item.valor; + return sum + (isNaN(valor) ? 0 : valor); + }, 0); + + const valorPrevisto = filteredData.reduce((sum, item) => { + const valor = typeof item.valor_previsto === "string" ? parseFloat(item.valor_previsto) : (item.valor_previsto || 0); + return sum + (isNaN(valor) ? 0 : valor); + }, 0); + + const valorConfirmado = filteredData.reduce((sum, item) => { + const valor = typeof item.valor_confirmado === "string" ? parseFloat(item.valor_confirmado) : (item.valor_confirmado || 0); + return sum + (isNaN(valor) ? 0 : valor); + }, 0); + + const valorPago = filteredData.reduce((sum, item) => { + const valor = typeof item.valor_pago === "string" ? parseFloat(item.valor_pago) : (item.valor_pago || 0); return sum + (isNaN(valor) ? 0 : valor); }, 0); return { valorRealizado, - valorPrevisto: 0, // Sempre 0 pois não há dados - valorConfirmado: 0, // Sempre 0 pois não há dados - valorPago: 0, // Sempre 0 pois não há dados + valorPrevisto, + valorConfirmado, + valorPago, }; - }, [table, data, columnFilters, globalFilter]); + }, [table]); const exportToExcel = () => { if (data.length === 0) return; @@ -442,6 +543,38 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { + {/* Filtros Externos Ativos */} + {(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 */}
- Limpar Filtros + Limpar Filtros Avançados )} {data.length > 0 && ( @@ -590,7 +723,7 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { )}
- - + {row.original.entidade || "-"}
{row.original.codigo_fornecedor} @@ -625,21 +758,54 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { currency: "BRL", }).format(row.original.valor)}
-
- - +
+ {row.original.valor_previsto && row.original.valor_previsto !== 0 ? ( + + {new Intl.NumberFormat("pt-BR", { + style: "currency", + currency: "BRL", + }).format(row.original.valor_previsto)} + + ) : ( + - + )}
-
- - +
+ {row.original.valor_confirmado && row.original.valor_confirmado !== 0 ? ( + + {new Intl.NumberFormat("pt-BR", { + style: "currency", + currency: "BRL", + }).format(row.original.valor_confirmado)} + + ) : ( + - + )}
-
- - -
+
+ {row.original.valor_pago && row.original.valor_pago !== 0 ? ( + + {new Intl.NumberFormat("pt-BR", { + style: "currency", + currency: "BRL", + }).format(row.original.valor_pago)} + + ) : ( + - + )} +
{row.original.historico} -
+
- - + {row.original.numero_lancamento || "-"}
); @@ -682,14 +848,47 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { currency: "BRL", }).format(columnTotals.valorRealizado)}
-
- - +
+ {columnTotals.valorPrevisto !== 0 ? ( + + {new Intl.NumberFormat("pt-BR", { + style: "currency", + currency: "BRL", + }).format(columnTotals.valorPrevisto)} + + ) : ( + - + )}
-
- - +
+ {columnTotals.valorConfirmado !== 0 ? ( + + {new Intl.NumberFormat("pt-BR", { + style: "currency", + currency: "BRL", + }).format(columnTotals.valorConfirmado)} + + ) : ( + - + )}
-
- - +
+ {columnTotals.valorPago !== 0 ? ( + + {new Intl.NumberFormat("pt-BR", { + style: "currency", + currency: "BRL", + }).format(columnTotals.valorPago)} + + ) : ( + - + )}
@@ -748,6 +947,9 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { Filtros Avançados +

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

@@ -873,7 +1075,7 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { onClick={clearFilters} className="flex-1 border-gray-300 text-gray-700 hover:bg-gray-50" > - Limpar todos + Limpar filtros avançados + */} diff --git a/src/app/api/analitico-oracle/route.ts b/src/app/api/analitico-oracle/route.ts new file mode 100644 index 0000000..e22ddf7 --- /dev/null +++ b/src/app/api/analitico-oracle/route.ts @@ -0,0 +1,61 @@ +import { NextRequest, NextResponse } from 'next/server'; +import { executeOracleQuery } from '@/db/oracle'; + +export async function GET(request: NextRequest) { + try { + console.log('🔄 Buscando dados analíticos do Oracle...'); + + // Query para buscar dados da tabela DRE_RESULTADO_ANALITICO + const sql = `SELECT * FROM DRE_RESULTADO_ANALITICO ORDER BY DTVENC, CODFORNEC, CODCONTA`; + + const data = await executeOracleQuery(sql); + + console.log('✅ Query executada com sucesso:', data.length, 'registros encontrados'); + + // Transformar os dados do Oracle para o formato esperado pelo componente + const transformedData = data.map((item: any) => ({ + codigo_grupo: item.CODGRUPO || "", + codigo_subgrupo: "", // Não existe na tabela Oracle + codigo_fornecedor: item.CODFORNEC || "", + nome_fornecedor: item.FORNECEDOR || "", + id: item.NUMLANC || 0, + codfilial: "001", // Valor padrão + recnum: item.NUMLANC || 0, + data_competencia: item.ANOMESCOMP || "", + data_vencimento: item.DTVENC ? new Date(item.DTVENC).toISOString().split('T')[0] : "", + data_pagamento: "", // Não existe na tabela Oracle + data_caixa: item.DTCAIXA ? new Date(item.DTCAIXA).toISOString().split('T')[0] : "", + codigo_conta: item.CODCONTA || "", + conta: item.CONTA || "", + codigo_centrocusto: item.CODIGOCENTROCUSTO || "", + valor: item.VLREALIZADO || 0, + historico: item.HISTORICO || "", + historico2: item.HISTORICO2 || "", + created_at: new Date().toISOString(), + updated_at: new Date().toISOString(), + // Campos adicionais do Oracle + entidade: item.ENTIDADE || "", + tipo_parceiro: item.TIPOPARCEIRO || "", + valor_previsto: item.VLPREVISTO || 0, + valor_confirmado: item.VLCONFIRMADO || 0, + valor_pago: item.VLPAGO || 0, + numero_lancamento: item.NUMLANC || 0, + ano_mes_comp: item.ANOMESCOMP || "", + codgrupo: item.CODGRUPO || "" + })); + + return NextResponse.json(transformedData); + + } catch (error) { + console.error('❌ Erro ao buscar dados analíticos do Oracle:', error); + + return NextResponse.json( + { + success: false, + error: error instanceof Error ? error.message : 'Erro desconhecido', + details: error instanceof Error ? error.stack : undefined + }, + { status: 500 } + ); + } +} From 81792ec7e7ecdfae7400e3ee471bc6385c1f033f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alessandro=20Gon=C3=A7aalves?= Date: Tue, 21 Oct 2025 10:16:50 -0300 Subject: [PATCH 26/30] =?UTF-8?q?fix:=20ajuste=20na=20rela=C3=A7=C3=A3o=20?= =?UTF-8?q?analitico=20x=20sintetico?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/DRE/analitico.tsx | 72 +++++++++++++-------------- src/app/DRE/teste.tsx | 19 +++++-- src/app/api/analitico-oracle/route.ts | 68 +++++++++++++++++++++++-- 3 files changed, 116 insertions(+), 43 deletions(-) diff --git a/src/app/DRE/analitico.tsx b/src/app/DRE/analitico.tsx index 91bc38c..3837a1a 100644 --- a/src/app/DRE/analitico.tsx +++ b/src/app/DRE/analitico.tsx @@ -85,61 +85,59 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { // Atualizar filtros externos quando os props mudarem, mas preservar filtros internos React.useEffect(() => { + console.log('🔄 Analítico - useEffect dos filtros chamado'); + console.log('📋 Filtros recebidos via props:', filtros); + console.log('📋 Filtros externos atuais:', filtrosExternos); setFiltrosExternos(filtros); }, [filtros]); const fetchData = React.useCallback(async () => { + console.log('🔄 Analítico - fetchData chamado'); + console.log('📋 Filtros externos recebidos:', filtrosExternos); + // Só faz a requisição se tiver dataInicio e dataFim nos filtros externos if (!filtrosExternos.dataInicio || !filtrosExternos.dataFim) { + console.log('⚠️ Sem dataInicio ou dataFim, limpando dados'); setData([]); return; } setLoading(true); try { - // Usar a nova API do Oracle - const response = await fetch("/api/analitico-oracle"); + // Construir URL com parâmetros de query + 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); + } + + 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 3 registros:', result.slice(0, 3)); - // Aplicar filtros externos (vindos do teste.tsx) nos dados retornados - let filteredData = result as AnaliticoItem[]; - - // Filtro por período se especificado nos filtros externos - if (filtrosExternos.dataInicio && filtrosExternos.dataFim) { - filteredData = filteredData.filter((item: AnaliticoItem) => { - const dataItem = item.data_competencia || item.ano_mes_comp; - return dataItem && dataItem >= filtrosExternos.dataInicio && dataItem <= filtrosExternos.dataFim; - }); - } - - // Filtro por centro de custo se especificado nos filtros externos - if (filtrosExternos.centroCusto) { - filteredData = filteredData.filter((item: AnaliticoItem) => - item.codigo_centrocusto === filtrosExternos.centroCusto - ); - } - - // Filtro por código do grupo se especificado nos filtros externos - if (filtrosExternos.codigoGrupo) { - filteredData = filteredData.filter((item: AnaliticoItem) => - item.codgrupo === filtrosExternos.codigoGrupo - ); - } - - // Filtro por código da conta se especificado nos filtros externos - if (filtrosExternos.codigoConta) { - filteredData = filteredData.filter((item: AnaliticoItem) => - item.codigo_conta === filtrosExternos.codigoConta - ); - } - - setData(filteredData); + setData(result as AnaliticoItem[]); } else { - console.error("Erro ao buscar dados:", await response.text()); + console.error("❌ Erro ao buscar dados:", await response.text()); } } catch (error) { - console.error("Erro ao buscar dados:", error); + console.error("❌ Erro ao buscar dados:", error); } finally { setLoading(false); } diff --git a/src/app/DRE/teste.tsx b/src/app/DRE/teste.tsx index 24945e7..32aa5be 100644 --- a/src/app/DRE/teste.tsx +++ b/src/app/DRE/teste.tsx @@ -218,7 +218,13 @@ export default function Teste() { // Função para lidar com clique nas linhas const handleRowClick = (row: HierarchicalRow, mesSelecionado?: string) => { - if (!data.length) return; + console.log('🖱️ Clique na linha:', row); + console.log('📅 Mês selecionado:', mesSelecionado); + + if (!data.length) { + console.log('⚠️ Sem dados disponíveis'); + return; + } // Pegar todas as datas disponíveis para definir o período const datas = data.map((item) => item.data_competencia); @@ -228,11 +234,15 @@ export default function Teste() { const dataInicioStr = new Date(dataInicio).toISOString().substring(0, 7); // YYYY-MM const dataFimStr = new Date(dataFim).toISOString().substring(0, 7); // YYYY-MM + console.log('📅 Datas calculadas:', { dataInicioStr, dataFimStr }); + const { codigoGrupo, codigoSubgrupo } = extractCodes( row.grupo || "", row.subgrupo ); + console.log('🔍 Códigos extraídos:', { codigoGrupo, codigoSubgrupo }); + // Criar um identificador único para a linha const linhaId = `${row.type}-${row.grupo || ""}-${row.subgrupo || ""}-${ row.centro_custo || "" @@ -243,14 +253,17 @@ export default function Teste() { const dataInicioFiltro = mesSelecionado || dataInicioStr; const dataFimFiltro = mesSelecionado || dataFimStr; - setAnaliticoFiltros({ + const novosFiltros = { dataInicio: dataInicioFiltro, dataFim: dataFimFiltro, centroCusto: row.centro_custo || "", codigoGrupo, codigoSubgrupo, codigoConta: row.codigo_conta?.toString() || "", - }); + }; + + console.log('🎯 Novos filtros para analítico:', novosFiltros); + setAnaliticoFiltros(novosFiltros); }; const toggleGroup = (grupo: string) => { diff --git a/src/app/api/analitico-oracle/route.ts b/src/app/api/analitico-oracle/route.ts index e22ddf7..2c8037a 100644 --- a/src/app/api/analitico-oracle/route.ts +++ b/src/app/api/analitico-oracle/route.ts @@ -4,13 +4,72 @@ import { executeOracleQuery } from '@/db/oracle'; export async function GET(request: NextRequest) { try { console.log('🔄 Buscando dados analíticos do Oracle...'); + console.log('📋 URL completa:', request.url); + console.log('🔍 Query params:', request.nextUrl.searchParams.toString()); + console.log('📊 Headers:', Object.fromEntries(request.headers.entries())); - // Query para buscar dados da tabela DRE_RESULTADO_ANALITICO - const sql = `SELECT * FROM DRE_RESULTADO_ANALITICO ORDER BY DTVENC, CODFORNEC, CODCONTA`; + // Extrair parâmetros de query + const searchParams = request.nextUrl.searchParams; + const dataInicio = searchParams.get('dataInicio'); + const dataFim = searchParams.get('dataFim'); + const centroCusto = searchParams.get('centroCusto'); + const codigoGrupo = searchParams.get('codigoGrupo'); + const codigoConta = searchParams.get('codigoConta'); - const data = await executeOracleQuery(sql); + console.log('🎯 Filtros recebidos:', { + dataInicio, + dataFim, + centroCusto, + codigoGrupo, + codigoConta + }); + + // Construir query SQL com filtros + let sql = `SELECT * FROM DRE_RESULTADO_ANALITICO WHERE 1=1`; + const params: any[] = []; + let paramIndex = 1; + + // Filtro por período + if (dataInicio && dataFim) { + sql += ` AND ANOMESCOMP >= :${paramIndex} AND ANOMESCOMP <= :${paramIndex + 1}`; + params.push(dataInicio, dataFim); + paramIndex += 2; + console.log('📅 Adicionando filtro de período:', dataInicio, 'a', dataFim); + } + + // Filtro por centro de custo + if (centroCusto) { + sql += ` AND CODIGOCENTROCUSTO = :${paramIndex}`; + params.push(centroCusto); + paramIndex++; + console.log('🏢 Adicionando filtro de centro:', centroCusto); + } + + // Filtro por código do grupo + if (codigoGrupo) { + sql += ` AND CODGRUPO = :${paramIndex}`; + params.push(codigoGrupo); + paramIndex++; + console.log('📊 Adicionando filtro de grupo:', codigoGrupo); + } + + // Filtro por código da conta + if (codigoConta) { + sql += ` AND CODCONTA = :${paramIndex}`; + params.push(codigoConta); + paramIndex++; + console.log('💰 Adicionando filtro de conta:', codigoConta); + } + + sql += ` ORDER BY DTVENC, CODFORNEC, CODCONTA`; + + console.log('🗄️ Query SQL final:', sql); + console.log('📋 Parâmetros:', params); + + const data = await executeOracleQuery(sql, params); console.log('✅ Query executada com sucesso:', data.length, 'registros encontrados'); + console.log('📝 Primeiros 3 registros:', data.slice(0, 3)); // Transformar os dados do Oracle para o formato esperado pelo componente const transformedData = data.map((item: any) => ({ @@ -44,6 +103,9 @@ export async function GET(request: NextRequest) { codgrupo: item.CODGRUPO || "" })); + console.log('🔄 Dados transformados:', transformedData.length, 'registros'); + console.log('📝 Primeiros 3 transformados:', transformedData.slice(0, 3)); + return NextResponse.json(transformedData); } catch (error) { From 515c0d96338c57a820681f36d775093c660072f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alessandro=20Gon=C3=A7aalves?= Date: Tue, 21 Oct 2025 10:23:58 -0300 Subject: [PATCH 27/30] fix: ajuste nas colunas tolaizadoras --- src/app/DRE/analitico.tsx | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/src/app/DRE/analitico.tsx b/src/app/DRE/analitico.tsx index 3837a1a..9795e27 100644 --- a/src/app/DRE/analitico.tsx +++ b/src/app/DRE/analitico.tsx @@ -89,7 +89,7 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { console.log('📋 Filtros recebidos via props:', filtros); console.log('📋 Filtros externos atuais:', filtrosExternos); setFiltrosExternos(filtros); - }, [filtros]); + }, [filtros, filtrosExternos]); const fetchData = React.useCallback(async () => { console.log('🔄 Analítico - fetchData chamado'); @@ -439,13 +439,23 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { return sum + (isNaN(valor) ? 0 : valor); }, 0); + console.log("🔄 Calculando totais das colunas:", { + totalRows: table.getRowModel().rows.length, + valorRealizado, + valorPrevisto, + valorConfirmado, + valorPago, + columnFilters: columnFilters.length, + globalFilter, + }); + return { valorRealizado, valorPrevisto, valorConfirmado, valorPago, }; - }, [table]); + }, [table, columnFilters, globalFilter]); const exportToExcel = () => { if (data.length === 0) return; @@ -622,7 +632,7 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { {/* Table Container */}
-
+
{/* Table Header */}
@@ -649,7 +659,7 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) {
Valor Confirmado
-
+
Valor Pago
Histórico
@@ -784,7 +794,7 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { - )}
-
+
{row.original.valor_pago && row.original.valor_pago !== 0 ? ( - )}
-
+
{columnTotals.valorPago !== 0 ? ( Date: Tue, 21 Oct 2025 10:25:58 -0300 Subject: [PATCH 28/30] =?UTF-8?q?fix:=20corre=C3=A7=C3=A3o=20do=20espa?= =?UTF-8?q?=C3=A7amento?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/DRE/analitico.tsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/app/DRE/analitico.tsx b/src/app/DRE/analitico.tsx index 9795e27..43ff55a 100644 --- a/src/app/DRE/analitico.tsx +++ b/src/app/DRE/analitico.tsx @@ -632,7 +632,7 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { {/* Table Container */}
-
+
{/* Table Header */}
@@ -662,6 +662,7 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) {
Valor Pago
+
Histórico
Histórico 2
@@ -808,6 +809,7 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { - )}
+
- )}
+
From 13cfb0aa74575e849f43595d1fdba72e26ff6449 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alessandro=20Gon=C3=A7aalves?= Date: Tue, 21 Oct 2025 11:23:00 -0300 Subject: [PATCH 29/30] =?UTF-8?q?fix:=20estiliza=C3=A7=C3=A3o=20da=20tabel?= =?UTF-8?q?a=20sintetica?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/DRE/analitico.tsx | 18 +++++++++--------- src/app/DRE/teste.tsx | 17 ++++------------- 2 files changed, 13 insertions(+), 22 deletions(-) diff --git a/src/app/DRE/analitico.tsx b/src/app/DRE/analitico.tsx index 43ff55a..93b4159 100644 --- a/src/app/DRE/analitico.tsx +++ b/src/app/DRE/analitico.tsx @@ -640,9 +640,9 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { Data de Vencimento
Data de Caixa
-
Entidade
-
- Código do Fornecedor +
Entidade
+
+ Cód. Fornec
Nome do Fornecedor @@ -663,8 +663,8 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { Valor Pago
-
Histórico
-
Histórico 2
+
Histórico
+
Histórico 2
Número do Lançamento
@@ -731,10 +731,10 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { "pt-BR" )}
-
+
{row.original.entidade || "-"}
-
+
{row.original.codigo_fornecedor}
{row.original.historico}
{row.original.historico2} diff --git a/src/app/DRE/teste.tsx b/src/app/DRE/teste.tsx index 32aa5be..833995f 100644 --- a/src/app/DRE/teste.tsx +++ b/src/app/DRE/teste.tsx @@ -49,6 +49,7 @@ interface HierarchicalRow { isExpanded?: boolean; valoresPorMes?: Record; percentuaisPorMes?: Record; + isCalculado?: boolean; } export default function Teste() { @@ -537,6 +538,7 @@ export default function Teste() { isExpanded: expandedGroups.has(grupo), valoresPorMes, percentuaisPorMes: calcularPercentuaisPorMes(valoresPorMes, grupo), + isCalculado: items[0]?.isCalculado || false, // Usar a propriedade isCalculado do primeiro item }); if (expandedGroups.has(grupo)) { @@ -711,19 +713,8 @@ export default function Teste() { }; const renderCellContent = (row: HierarchicalRow) => { - // Verificar se é um grupo calculado - const isCalculado = row.grupo?.includes("CALCULADO") || - row.grupo?.includes("FATURAMENTO LÍQUIDO") || - row.grupo?.includes("LUCRO BRUTO") || - row.grupo?.includes("MARGEM LOJA") || - row.grupo?.includes("RESULTADO OPERACIONAL") || - row.grupo?.includes("RESULTADO FINANCEIRO") || - row.grupo?.includes("OUTRAS RECEITAS / DESPESAS") || - row.grupo?.includes("LAIR") || - row.grupo?.includes("IR") || - row.grupo?.includes("CSLL") || - row.grupo?.includes("LUCRO LÍQUIDO") || - row.grupo?.includes("EBITDA"); + // Verificar se é um grupo calculado usando a propriedade isCalculado + const isCalculado = row.isCalculado === true; switch (row.type) { case "grupo": From 70d301e2fb4a6e8d44b8670f95ae22d38dcd629c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alessandro=20Gon=C3=A7aalves?= Date: Tue, 21 Oct 2025 11:29:06 -0300 Subject: [PATCH 30/30] =?UTF-8?q?fix:=20corre=C3=A7=C3=A3o=20=20na=20largu?= =?UTF-8?q?ra=20das=20colunas=20da=20tabela?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/DRE/analitico.tsx | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/app/DRE/analitico.tsx b/src/app/DRE/analitico.tsx index 93b4159..f9d77e4 100644 --- a/src/app/DRE/analitico.tsx +++ b/src/app/DRE/analitico.tsx @@ -632,7 +632,7 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { {/* Table Container */}
-
+
{/* Table Header */}
@@ -664,8 +664,8 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) {
Histórico
-
Histórico 2
-
+
Histórico 2
+
Número do Lançamento
@@ -817,12 +817,12 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { {row.original.historico}
{row.original.historico2}
-
+
{row.original.numero_lancamento || "-"}
@@ -902,8 +902,8 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) {
-
-
+
+
)}