|
|
|
|
@@ -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<number>(-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<TodasSolicitacoes>([]);
|
|
|
|
|
let ultimoDataHash = $state<string>('');
|
|
|
|
|
|
|
|
|
|
// 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;
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (rangeInicioIndice > ultimoIndice) {
|
|
|
|
|
rangeInicioIndice = ultimoIndice;
|
|
|
|
|
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<number, SolicitacoesPorAnoResumo>();
|
|
|
|
|
|
|
|
|
|
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<number>(-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 {
|
|
|
|
|
if (import.meta.env.DEV) {
|
|
|
|
|
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
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
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,15 +640,44 @@
|
|
|
|
|
};
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Sincronizar eventos do calendário quando mudarem
|
|
|
|
|
// Sincronizar eventos do calendário quando mudarem (com debounce)
|
|
|
|
|
let ultimosEventosSerializados = $state<string>('');
|
|
|
|
|
let timeoutAtualizacaoCalendario = $state<ReturnType<typeof setTimeout> | null>(null);
|
|
|
|
|
|
|
|
|
|
$effect(() => {
|
|
|
|
|
// Não atualizar se o calendário não estiver inicializado ou estiver carregando
|
|
|
|
|
if (!calendarioInstance || !calendarioInicializado || isLoading || hasError) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 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
|
|
|
|
|
})));
|
|
|
|
|
|
|
|
|
|
// 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 {
|
|
|
|
|
console.log('🔄 Atualizando eventos do calendário:', eventosFerias.length, 'eventos');
|
|
|
|
|
// Verificar novamente se o calendário ainda está válido
|
|
|
|
|
if (!calendarioInstance || !calendarioInicializado) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Remover todos os eventos existentes
|
|
|
|
|
calendarioInstance.removeAllEvents();
|
|
|
|
|
@@ -636,8 +692,6 @@
|
|
|
|
|
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) {
|
|
|
|
|
@@ -646,35 +700,27 @@
|
|
|
|
|
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<string, string> = {
|
|
|
|
|
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 @@
|
|
|
|
|
<option value="aguardando_aprovacao">Aguardando Aprovação</option>
|
|
|
|
|
<option value="aprovado">Aprovado</option>
|
|
|
|
|
<option value="reprovado">Reprovado</option>
|
|
|
|
|
<option value="data_ajustada_aprovada">Data Ajustada</option>
|
|
|
|
|
<option value="Cancelado_RH">Cancelado RH</option>
|
|
|
|
|
</select>
|
|
|
|
|
<p class="text-base-content/60 text-xs leading-relaxed">
|
|
|
|
|
|