From d27c0b6f911e383123b12e0e6325b84821695cb7 Mon Sep 17 00:00:00 2001 From: deyvisonwanderley Date: Wed, 10 Dec 2025 06:27:25 -0300 Subject: [PATCH] feat: enhance vacation approval process by adding notification system for employees, including email alerts and in-app notifications; improve error handling and user feedback during vacation management --- apps/web/src/lib/components/AlertModal.svelte | 125 ++++++++ .../src/lib/components/AprovarFerias.svelte | 3 +- .../components/CalendarioAfastamentos.svelte | 32 +- .../src/lib/components/ConfirmModal.svelte | 135 ++++++++ .../lib/components/ti/AlertConfigModal.svelte | 146 +++++++-- .../components/ti/AlertDiagnosticsCard.svelte | 204 +++++++++++++ .../ti/SystemMonitorCardLocal.svelte | 83 +++-- apps/web/src/lib/utils/fichaPontoPDF.ts | 3 + apps/web/src/routes/(dashboard)/+error.svelte | 3 + .../fluxos/[id]/editor/+page.svelte | 27 +- .../atestados-licencas/+page.svelte | 214 +++++++++---- .../gestao-ausencias/+page.svelte | 14 +- .../ti/erros-servidor/+page.svelte | 41 +-- .../(dashboard)/ti/monitoramento/+page.svelte | 52 +++- apps/web/src/routes/+error.svelte | 3 + packages/backend/convex/auth.ts | 3 +- packages/backend/convex/chat.ts | 11 +- packages/backend/convex/ferias.ts | 205 ++++++++++++- packages/backend/convex/monitoramento.ts | 287 +++++++++++++++--- packages/backend/convex/tables/ferias.ts | 3 +- packages/backend/convex/templatesMensagens.ts | 83 ++++- packages/backend/convex/usuarios.ts | 110 +++++++ 22 files changed, 1572 insertions(+), 215 deletions(-) create mode 100644 apps/web/src/lib/components/AlertModal.svelte create mode 100644 apps/web/src/lib/components/ConfirmModal.svelte create mode 100644 apps/web/src/lib/components/ti/AlertDiagnosticsCard.svelte diff --git a/apps/web/src/lib/components/AlertModal.svelte b/apps/web/src/lib/components/AlertModal.svelte new file mode 100644 index 0000000..1ed192a --- /dev/null +++ b/apps/web/src/lib/components/AlertModal.svelte @@ -0,0 +1,125 @@ + + +{#if open} + +{/if} + + + diff --git a/apps/web/src/lib/components/AprovarFerias.svelte b/apps/web/src/lib/components/AprovarFerias.svelte index 2597297..909d303 100644 --- a/apps/web/src/lib/components/AprovarFerias.svelte +++ b/apps/web/src/lib/components/AprovarFerias.svelte @@ -76,7 +76,8 @@ dataInicio: periodo.dataInicio, dataFim: periodo.dataFim } - ] + ], + feriasIdExcluir: periodo._id // Excluir este período do cálculo de saldo pendente }); if (!validacao.valido) { diff --git a/apps/web/src/lib/components/CalendarioAfastamentos.svelte b/apps/web/src/lib/components/CalendarioAfastamentos.svelte index 2c2fbe6..0002164 100644 --- a/apps/web/src/lib/components/CalendarioAfastamentos.svelte +++ b/apps/web/src/lib/components/CalendarioAfastamentos.svelte @@ -5,6 +5,7 @@ import interactionPlugin from '@fullcalendar/interaction'; import ptBrLocale from '@fullcalendar/core/locales/pt-br'; import type { EventInput } from '@fullcalendar/core/index.js'; + import { SvelteDate } from 'svelte/reactivity'; interface Props { eventos: Array<{ @@ -40,20 +41,31 @@ return eventos.filter((e) => e.tipo === filtroAtivo); }); + // Helper: Adicionar 1 dia à data fim (FullCalendar usa exclusive end) + function calcularDataFim(dataFim: string): string { + // Usar SvelteDate para evitar problemas de mutabilidade e timezone + const data = new SvelteDate(dataFim + 'T00:00:00'); + data.setDate(data.getDate() + 1); + return data.toISOString().split('T')[0]; + } + // Converter eventos para formato FullCalendar const eventosFullCalendar = $derived.by(() => { return eventosFiltrados.map((evento) => ({ id: evento.id, title: evento.title, start: evento.start, - end: evento.end, + end: calcularDataFim(evento.end), // Ajustar data fim (exclusive end) + allDay: true, // IMPORTANTE: Tratar como dia inteiro sem timezone backgroundColor: evento.color, borderColor: evento.color, textColor: '#ffffff', extendedProps: { tipo: evento.tipo, funcionarioNome: evento.funcionarioNome, - funcionarioId: evento.funcionarioId + funcionarioId: evento.funcionarioId, + dataInicioOriginal: evento.start, // Armazenar data original para exibição + dataFimOriginal: evento.end // Armazenar data original para exibição } })) as EventInput[]; }); @@ -79,12 +91,14 @@ }, events: eventosFullCalendar, eventClick: (info) => { + // Usar datas originais armazenadas nos extendedProps para exibição correta + const props = info.event.extendedProps; eventoSelecionado = { title: info.event.title, - start: info.event.startStr || '', - end: info.event.endStr || '', - tipo: info.event.extendedProps.tipo as string, - funcionarioNome: info.event.extendedProps.funcionarioNome as string + start: (props.dataInicioOriginal as string) || info.event.startStr || '', + end: (props.dataFimOriginal as string) || info.event.endStr || '', + tipo: props.tipo as string, + funcionarioNome: props.funcionarioNome as string }; showModal = true; }, @@ -359,8 +373,10 @@

Duração

{(() => { - const inicio = new Date(eventoSelecionado.start); - const fim = new Date(eventoSelecionado.end); + // Usar SvelteDate para evitar problemas de mutabilidade e timezone + const inicio = new SvelteDate(eventoSelecionado.start + 'T00:00:00'); + const fim = new SvelteDate(eventoSelecionado.end + 'T00:00:00'); + // Não precisa ajustar porque estamos usando as datas originais dos extendedProps const diffTime = Math.abs(fim.getTime() - inicio.getTime()); const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24)) + 1; return `${diffDays} ${diffDays === 1 ? 'dia' : 'dias'}`; diff --git a/apps/web/src/lib/components/ConfirmModal.svelte b/apps/web/src/lib/components/ConfirmModal.svelte new file mode 100644 index 0000000..9609a5b --- /dev/null +++ b/apps/web/src/lib/components/ConfirmModal.svelte @@ -0,0 +1,135 @@ + + +{#if open} +

+{/if} + + + diff --git a/apps/web/src/lib/components/ti/AlertConfigModal.svelte b/apps/web/src/lib/components/ti/AlertConfigModal.svelte index 5a3a4e8..b92fd75 100644 --- a/apps/web/src/lib/components/ti/AlertConfigModal.svelte +++ b/apps/web/src/lib/components/ti/AlertConfigModal.svelte @@ -1,17 +1,24 @@ -