- Ao voltar para "Aguardando Aprovação", a solicitação ficará disponível para aprovação ou
- reprovação pelo gestor.
+ Ao cancelar as férias, o status será alterado para "Cancelado RH" e a solicitação não poderá mais ser processada.
@@ -179,8 +180,8 @@
{:else}
-
+
- Esta solicitação já está aguardando aprovação.
+ Esta solicitação já foi cancelada pelo RH.
{/if}
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 47e9ba1..c21d87f 100644
--- a/apps/web/src/routes/(dashboard)/recursos-humanos/ferias/+page.svelte
+++ b/apps/web/src/routes/(dashboard)/recursos-humanos/ferias/+page.svelte
@@ -45,17 +45,13 @@
// Estados de loading e error
const isLoading = $derived(todasSolicitacoesQuery?.isLoading ?? true);
- // Debug: Log dos dados carregados
+ // Debug: Log dos dados carregados (apenas uma vez quando dados mudam)
+ let ultimoTotalDados = $state(-1);
$effect(() => {
- if (todasSolicitacoesQuery?.data) {
- console.log('📦 [Backend] Dados carregados:', {
- total: todasSolicitacoesQuery.data.length,
- isLoading: todasSolicitacoesQuery.isLoading,
- dados: todasSolicitacoesQuery.data
- });
- }
- if (todasSolicitacoesQuery?.isLoading !== undefined) {
- console.log('🔄 [Backend] Estado de loading:', todasSolicitacoesQuery.isLoading);
+ const total = todasSolicitacoesQuery?.data?.length ?? 0;
+ if (total !== ultimoTotalDados && total > 0) {
+ ultimoTotalDados = total;
+ console.log('📦 [Backend] Dados carregados:', { total });
}
});
@@ -83,11 +79,18 @@
// Manter último valor válido para evitar dados desaparecendo
let ultimasSolicitacoesValidas = $state([]);
+ let ultimoDataHash = $state('');
- // Atualizar apenas quando temos dados válidos
+ // Atualizar apenas quando temos dados válidos e quando realmente mudou
$effect(() => {
- if (todasSolicitacoesQuery?.data && !hasError) {
- ultimasSolicitacoesValidas = todasSolicitacoesQuery.data;
+ const dataAtual = todasSolicitacoesQuery?.data;
+ if (dataAtual && !hasError) {
+ // Criar hash simples para comparar se os dados realmente mudaram
+ const dataHash = JSON.stringify(dataAtual.map(d => d._id));
+ if (dataHash !== ultimoDataHash) {
+ ultimoDataHash = dataHash;
+ ultimasSolicitacoesValidas = dataAtual;
+ }
}
});
@@ -259,31 +262,69 @@
let rangeInicioIndice = $state(0);
let rangeFimIndice = $state(0);
+ let ultimoTamanhoPeriodos = $state(0);
+ let atualizandoRanges = $state(false);
$effect(() => {
- if (periodosPorMes.length === 0) {
- rangeInicioIndice = 0;
- rangeFimIndice = 0;
+ // Prevenir loops infinitos
+ if (atualizandoRanges) {
return;
}
- const ultimoIndice = periodosPorMes.length - 1;
-
- if (rangeFimIndice === 0 && rangeInicioIndice === 0) {
- rangeFimIndice = ultimoIndice;
+ const tamanhoAtual = periodosPorMes.length;
+
+ // Só atualizar se o tamanho mudou
+ if (tamanhoAtual === 0) {
+ if (rangeInicioIndice !== 0 || rangeFimIndice !== 0) {
+ atualizandoRanges = true;
+ rangeInicioIndice = 0;
+ rangeFimIndice = 0;
+ ultimoTamanhoPeriodos = 0;
+ atualizandoRanges = false;
+ }
return;
}
- if (rangeInicioIndice > ultimoIndice) {
- rangeInicioIndice = ultimoIndice;
+ // Se o tamanho mudou, resetar os ranges
+ if (tamanhoAtual !== ultimoTamanhoPeriodos) {
+ atualizandoRanges = true;
+ ultimoTamanhoPeriodos = tamanhoAtual;
+ const ultimoIndice = tamanhoAtual - 1;
+
+ if (rangeFimIndice === 0 && rangeInicioIndice === 0) {
+ rangeFimIndice = ultimoIndice;
+ atualizandoRanges = false;
+ return;
+ }
+ atualizandoRanges = false;
}
- if (rangeFimIndice > ultimoIndice) {
- rangeFimIndice = ultimoIndice;
+ const ultimoIndice = tamanhoAtual - 1;
+ let precisaAtualizar = false;
+ let novoInicio = rangeInicioIndice;
+ let novoFim = rangeFimIndice;
+
+ if (novoInicio > ultimoIndice) {
+ novoInicio = ultimoIndice;
+ precisaAtualizar = true;
}
- if (rangeInicioIndice > rangeFimIndice) {
- rangeInicioIndice = rangeFimIndice;
+ if (novoFim > ultimoIndice) {
+ novoFim = ultimoIndice;
+ precisaAtualizar = true;
+ }
+
+ if (novoInicio > novoFim) {
+ novoInicio = novoFim;
+ precisaAtualizar = true;
+ }
+
+ // Só atualizar se realmente precisar e se os valores mudaram
+ if (precisaAtualizar && (novoInicio !== rangeInicioIndice || novoFim !== rangeFimIndice)) {
+ atualizandoRanges = true;
+ rangeInicioIndice = novoInicio;
+ rangeFimIndice = novoFim;
+ atualizandoRanges = false;
}
});
@@ -305,19 +346,16 @@
(() => {
const agregados = new SvelteMap();
- for (const solicitacao of solicitacoesAprovadas) {
- const totalDias = solicitacao.periodos.reduce(
- (acc, periodo) => acc + periodo.diasFerias,
- 0
- );
- const existente = agregados.get(solicitacao.anoReferencia) ?? {
- ano: solicitacao.anoReferencia,
+ for (const periodo of solicitacoesAprovadas) {
+ // solicitacoesAprovadas são períodos individuais, não agrupados
+ const existente = agregados.get(periodo.anoReferencia) ?? {
+ ano: periodo.anoReferencia,
solicitacoes: 0,
diasTotais: 0
};
existente.solicitacoes += 1;
- existente.diasTotais += totalDias;
- agregados.set(solicitacao.anoReferencia, existente);
+ existente.diasTotais += periodo.diasFerias;
+ agregados.set(periodo.anoReferencia, existente);
}
return Array.from(agregados.values()).sort((a, b) => a.ano - b.ano);
@@ -456,13 +494,13 @@
})
);
- // Debug: Log dos eventos gerados
+ // Debug: Log dos eventos gerados (apenas quando mudar significativamente)
+ let ultimoTotalEventos = $state(-1);
$effect(() => {
- console.log('📅 [Eventos] Total de eventos:', eventosFerias.length);
- console.log('📋 [Periodos] Total de períodos:', periodosDetalhados.length);
- console.log('✅ [Aprovadas] Total de solicitações aprovadas:', solicitacoesAprovadas.length);
- if (eventosFerias.length > 0) {
- console.log('📅 [Eventos] Primeiro evento:', eventosFerias[0]);
+ const totalEventos = eventosFerias.length;
+ if (totalEventos !== ultimoTotalEventos && import.meta.env.DEV) {
+ ultimoTotalEventos = totalEventos;
+ console.log('📅 [Eventos] Total:', totalEventos);
}
});
@@ -484,16 +522,9 @@
}
try {
- console.log('🔄 [Calendário] Iniciando inicialização...');
- console.log('📊 [Calendário] Estado:', {
- container: !!calendarioContainer,
- loading: isLoading,
- error: hasError,
- eventos: eventosFerias.length,
- solicitacoes: solicitacoes.length,
- solicitacoesAprovadas: solicitacoesAprovadas.length,
- periodosDetalhados: periodosDetalhados.length
- });
+ if (import.meta.env.DEV) {
+ console.log('🔄 [Calendário] Iniciando inicialização...');
+ }
const [coreModule, dayGridModule, interactionModule, localeModule] = await Promise.all([
import('@fullcalendar/core'),
@@ -510,7 +541,6 @@
calendarioInstance ||
calendarioInicializado
) {
- console.log('⚠️ [Calendário] Condições alteradas após imports');
return;
}
@@ -519,11 +549,6 @@
const interactionPlugin = interactionModule.default;
const ptBrLocale = localeModule.default;
- console.log('✅ [Calendário] Criando instância com', eventosFerias.length, 'eventos');
- if (eventosFerias.length > 0) {
- console.log('📅 [Calendário] Primeiro evento:', eventosFerias[0]);
- }
-
calendarioInstance = new CalendarClass(calendarioContainer, {
plugins: [dayGridPlugin, interactionPlugin],
initialView: 'dayGridMonth',
@@ -547,7 +572,9 @@
calendarioInstance.render();
calendarioInicializado = true;
- console.log('✅ [Calendário] Inicializado com sucesso!');
+ if (import.meta.env.DEV) {
+ console.log('✅ [Calendário] Inicializado com sucesso!');
+ }
} catch (error) {
console.error('❌ [Calendário] Erro ao inicializar:', error);
if (error instanceof Error) {
@@ -613,68 +640,87 @@
};
});
- // Sincronizar eventos do calendário quando mudarem
+ // Sincronizar eventos do calendário quando mudarem (com debounce)
+ let ultimosEventosSerializados = $state('');
+ let timeoutAtualizacaoCalendario = $state | null>(null);
+
$effect(() => {
// Não atualizar se o calendário não estiver inicializado ou estiver carregando
if (!calendarioInstance || !calendarioInicializado || isLoading || hasError) {
return;
}
- try {
- console.log('🔄 Atualizando eventos do calendário:', eventosFerias.length, 'eventos');
+ // Serializar eventos para comparar mudanças
+ const eventosSerializados = JSON.stringify(eventosFerias.map(e => ({
+ id: e.id,
+ start: e.start,
+ end: e.end,
+ title: e.title
+ })));
- // Remover todos os eventos existentes
- calendarioInstance.removeAllEvents();
-
- // Adicionar novos eventos
- const eventosClonados = eventosFerias.map((evento) => ({
- ...evento,
- extendedProps: { ...evento.extendedProps }
- }));
-
- // Adicionar eventos em lote
- for (const evento of eventosClonados) {
- calendarioInstance.addEvent(evento);
- }
-
- console.log('✅ Eventos atualizados com sucesso!');
- } catch (error) {
- // Log do erro, mas não interromper o fluxo
- if (error instanceof Error) {
- console.error('❌ Erro ao atualizar eventos do calendário:', error.message);
- } else {
- console.error('❌ Erro ao atualizar eventos do calendário:', error);
- }
+ // Se os eventos não mudaram, não fazer nada
+ if (eventosSerializados === ultimosEventosSerializados) {
+ return;
}
+
+ // Limpar timeout anterior se existir
+ if (timeoutAtualizacaoCalendario) {
+ clearTimeout(timeoutAtualizacaoCalendario);
+ }
+
+ // Atualizar referência serializada imediatamente para evitar re-execuções
+ ultimosEventosSerializados = eventosSerializados;
+
+ // Debounce para evitar atualizações muito frequentes
+ timeoutAtualizacaoCalendario = setTimeout(() => {
+ try {
+ // Verificar novamente se o calendário ainda está válido
+ if (!calendarioInstance || !calendarioInicializado) {
+ return;
+ }
+
+ // Remover todos os eventos existentes
+ calendarioInstance.removeAllEvents();
+
+ // Adicionar novos eventos
+ const eventosClonados = eventosFerias.map((evento) => ({
+ ...evento,
+ extendedProps: { ...evento.extendedProps }
+ }));
+
+ // Adicionar eventos em lote
+ for (const evento of eventosClonados) {
+ calendarioInstance.addEvent(evento);
+ }
+ } catch (error) {
+ // Log do erro, mas não interromper o fluxo
+ if (error instanceof Error) {
+ console.error('❌ Erro ao atualizar eventos do calendário:', error.message);
+ } else {
+ console.error('❌ Erro ao atualizar eventos do calendário:', error);
+ }
+ }
+ }, 300); // Debounce de 300ms
+
+ // Cleanup
+ return () => {
+ if (timeoutAtualizacaoCalendario) {
+ clearTimeout(timeoutAtualizacaoCalendario);
+ }
+ };
});
- if (typeof window !== 'undefined') {
- $effect(() => {
- (
- window as Window & typeof globalThis & { __feriasSolicitacoes: TodasSolicitacoes }
- ).__feriasSolicitacoes = solicitacoes;
- (
- window as Window & typeof globalThis & { __feriasFiltradas: TodasSolicitacoes }
- ).__feriasFiltradas = solicitacoesFiltradas;
- (
- window as Window & typeof globalThis & { __feriasAprovadas: TodasSolicitacoes }
- ).__feriasAprovadas = solicitacoesAprovadas;
- (
- window as Window & typeof globalThis & { __feriasPeriodos: PeriodoDetalhado[] }
- ).__feriasPeriodos = periodosDetalhados;
- (window as Window & typeof globalThis & { __feriasPorMes: PeriodoPorMes[] }).__feriasPorMes =
- periodosPorMes;
- (
- window as Window & typeof globalThis & { __feriasPorAno: SolicitacoesPorAnoResumo[] }
- ).__feriasPorAno = solicitacoesPorAno;
- });
- }
+ // Atualizar variáveis no window apenas em desenvolvimento (desabilitado temporariamente para evitar loops)
+ // if (typeof window !== 'undefined' && import.meta.env.DEV) {
+ // // Código comentado para evitar loops infinitos
+ // }
function getStatusBadge(status: string) {
const badges: Record = {
aguardando_aprovacao: 'badge-warning',
aprovado: 'badge-success',
reprovado: 'badge-error',
- data_ajustada_aprovada: 'badge-info'
+ data_ajustada_aprovada: 'badge-info',
+ Cancelado_RH: 'badge-error'
};
return badges[status] || 'badge-neutral';
}
@@ -684,7 +730,8 @@
aguardando_aprovacao: 'Aguardando',
aprovado: 'Aprovado',
reprovado: 'Reprovado',
- data_ajustada_aprovada: 'Ajustado'
+ data_ajustada_aprovada: 'Ajustado',
+ Cancelado_RH: 'Cancelado RH'
};
return textos[status] || status;
}
@@ -1320,6 +1367,7 @@
+