From 298326e264709affb9755733e2efaf8b0415a5a5 Mon Sep 17 00:00:00 2001 From: deyvisonwanderley Date: Sat, 29 Nov 2025 23:25:14 -0300 Subject: [PATCH] fix: enhance data handling in vacation dashboard by adding array checks and improving chart data structure for better stability and performance --- .../recursos-humanos/ferias/+page.svelte | 113 +++++++++++------- 1 file changed, 72 insertions(+), 41 deletions(-) diff --git a/apps/web/src/routes/(dashboard)/recursos-humanos/ferias/+page.svelte b/apps/web/src/routes/(dashboard)/recursos-humanos/ferias/+page.svelte index dbe2863..40790b0 100644 --- a/apps/web/src/routes/(dashboard)/recursos-humanos/ferias/+page.svelte +++ b/apps/web/src/routes/(dashboard)/recursos-humanos/ferias/+page.svelte @@ -2,7 +2,7 @@ import { goto } from '$app/navigation'; import { resolve } from '$app/paths'; import { onMount, tick } from 'svelte'; - import { SvelteDate, SvelteMap } from 'svelte/reactivity'; + import { SvelteDate, SvelteMap, SvelteSet } from 'svelte/reactivity'; import { useQuery, useConvexClient } from 'convex-svelte'; import { api } from '@sgse-app/backend/convex/_generated/api'; import type { FunctionReturnType } from 'convex/server'; @@ -110,7 +110,7 @@ // Usar último valor válido ou array vazio const solicitacoes = $derived( - todasSolicitacoesQuery?.data ?? ultimasSolicitacoesValidas + (todasSolicitacoesQuery?.data ?? ultimasSolicitacoesValidas) || [] ); // Filtros Dashboard @@ -153,6 +153,9 @@ periodoFim: string; } ): TodasSolicitacoes { + if (!Array.isArray(lista)) { + return []; + } return lista.filter((periodo) => { if (filtros.status !== 'todos' && periodo.status !== filtros.status) { return false; @@ -271,14 +274,14 @@ }); const solicitacoesAprovadas = $derived( - solicitacoesFiltradas.filter( + (Array.isArray(solicitacoesFiltradas) ? solicitacoesFiltradas : []).filter( (p) => p.status === 'aprovado' || p.status === 'data_ajustada_aprovada' || p.status === 'EmFérias' ) ); const periodosDetalhados = $derived>( - solicitacoesAprovadas + (Array.isArray(solicitacoesAprovadas) ? solicitacoesAprovadas : []) .map((periodo) => ({ feriasId: periodo._id, funcionarioId: periodo.funcionarioId, @@ -303,6 +306,10 @@ (() => { const agregados = new SvelteMap(); + if (!Array.isArray(periodosDetalhados)) { + return []; + } + for (const periodo of periodosDetalhados) { const inicio = new SvelteDate(`${periodo.dataInicio}T00:00:00`); const chave = `${inicio.getFullYear()}-${String(inicio.getMonth() + 1).padStart(2, '0')}`; @@ -531,19 +538,41 @@ } // Dados para gráfico de área - Funcionários de férias nos próximos 12 meses - const chartDataFuncionariosFerias = $derived(() => { - const hoje = new Date(); + type ChartData = { + labels: string[]; + datasets: Array<{ + label: string; + data: number[]; + backgroundColor: string[]; + borderColor: string; + borderWidth: number; + pointBackgroundColor: string[]; + pointBorderColor: string; + pointBorderWidth: number; + pointRadius: number; + pointHoverRadius: number; + pointHoverBackgroundColor: string; + pointHoverBorderColor: string; + pointHoverBorderWidth: number; + fill: boolean; + tension: number; + spanGaps: boolean; + }>; + }; + const chartDataFuncionariosFerias: ChartData = $derived.by(() => { + // Sempre criar os 12 meses, mesmo sem dados + const hoje = new SvelteDate(); hoje.setHours(0, 0, 0, 0); // Criar array com os próximos 12 meses - const meses: Array<{ mes: string; dataInicio: Date; dataFim: Date; quantidade: number }> = []; + const meses: Array<{ mes: string; dataInicio: SvelteDate; dataFim: SvelteDate; quantidade: number }> = []; for (let i = 0; i < 12; i++) { - const dataInicioMes = new Date(hoje.getFullYear(), hoje.getMonth() + i, 1); - const dataFimMes = new Date(hoje.getFullYear(), hoje.getMonth() + i + 1, 0); + const dataInicioMes = new SvelteDate(hoje.getFullYear(), hoje.getMonth() + i, 1); + const dataFimMes = new SvelteDate(hoje.getFullYear(), hoje.getMonth() + i + 1, 0); dataFimMes.setHours(23, 59, 59, 999); - const mesLabel = format(dataInicioMes, 'MMM/yyyy', { locale: ptBR }); + const mesLabel = format(new Date(dataInicioMes.getTime()), 'MMM/yyyy', { locale: ptBR }); meses.push({ mes: mesLabel, dataInicio: dataInicioMes, @@ -552,36 +581,38 @@ }); } - // Filtrar apenas solicitações aprovadas que estão ou estarão em férias - const solicitacoesAprovadas = ultimasSolicitacoesValidas.filter( - (s) => - s.status === 'aprovado' || - s.status === 'data_ajustada_aprovada' || - s.status === 'EmFérias' - ); + // Verificação de segurança e filtrar apenas solicitações aprovadas + if (ultimasSolicitacoesValidas && Array.isArray(ultimasSolicitacoesValidas)) { + const solicitacoesAprovadas = ultimasSolicitacoesValidas.filter( + (s) => + s.status === 'aprovado' || + s.status === 'data_ajustada_aprovada' || + s.status === 'EmFérias' + ); - // Calcular quantos funcionários estarão de férias em cada mês - meses.forEach((mesInfo) => { - const funcionariosEmFerias = new Set(); - - solicitacoesAprovadas.forEach((solicitacao) => { - if (!solicitacao.funcionarioId) return; + // Calcular quantos funcionários estarão de férias em cada mês + meses.forEach((mesInfo) => { + const funcionariosEmFerias = new SvelteSet(); - const dataInicio = new Date(solicitacao.dataInicio); - const dataFim = new Date(solicitacao.dataFim); - dataInicio.setHours(0, 0, 0, 0); - dataFim.setHours(23, 59, 59, 999); + solicitacoesAprovadas.forEach((solicitacao) => { + if (!solicitacao.funcionarioId) return; + + const dataInicio = new SvelteDate(solicitacao.dataInicio); + const dataFim = new SvelteDate(solicitacao.dataFim); + dataInicio.setHours(0, 0, 0, 0); + dataFim.setHours(23, 59, 59, 999); + + // Verificar se o período de férias se sobrepõe com o mês + if ( + (dataInicio.getTime() <= mesInfo.dataFim.getTime() && dataFim.getTime() >= mesInfo.dataInicio.getTime()) + ) { + funcionariosEmFerias.add(String(solicitacao.funcionarioId)); + } + }); - // Verificar se o período de férias se sobrepõe com o mês - if ( - (dataInicio <= mesInfo.dataFim && dataFim >= mesInfo.dataInicio) - ) { - funcionariosEmFerias.add(String(solicitacao.funcionarioId)); - } + mesInfo.quantidade = funcionariosEmFerias.size; }); - - mesInfo.quantidade = funcionariosEmFerias.size; - }); + } // Cores harmoniosas com o tema (gradiente de azul primary para accent) const corBase = '#3b82f6'; // Azul primary @@ -2475,12 +2506,12 @@
- {#if chartDataFuncionariosFerias.labels.length === 0} -
-

Sem dados registrados até o momento.

-
- {:else} + {#if chartDataFuncionariosFerias.labels && chartDataFuncionariosFerias.labels.length > 0} + {:else} +
+

Carregando dados do gráfico...

+
{/if}