feat: enhance absence management with calendar integration and error handling

- Added functionality to check for date overlaps with existing absence requests in the absence calendar.
- Implemented a modal to display error messages when users attempt to create overlapping absence requests.
- Updated the calendar component to visually indicate blocked days due to existing approved or pending absence requests.
- Improved user feedback by providing alerts for unavailable periods and enhancing the overall user experience in absence management.
This commit is contained in:
2025-11-04 15:09:15 -03:00
parent a93d55f02b
commit c1e0998a5f
4 changed files with 552 additions and 15 deletions

View File

@@ -2,6 +2,7 @@
import { useConvexClient, useQuery } from "convex-svelte";
import { api } from "@sgse-app/backend/convex/_generated/api";
import CalendarioAusencias from "./CalendarioAusencias.svelte";
import ErrorModal from "../ErrorModal.svelte";
import { toast } from "svelte-sonner";
import type { Id } from "@sgse-app/backend/convex/_generated/dataModel";
@@ -25,17 +26,25 @@
let dataFim = $state<string>("");
let motivo = $state("");
let processando = $state(false);
// Estados para modal de erro
let mostrarModalErro = $state(false);
let mensagemErroModal = $state("");
let detalhesErroModal = $state("");
// Buscar ausências existentes para exibir no calendário
const ausenciasExistentesQuery = useQuery(api.ausencias.listarMinhasSolicitacoes, {
funcionarioId,
});
// Filtrar apenas ausências aprovadas ou aguardando aprovação (que bloqueiam novas solicitações)
const ausenciasExistentes = $derived(
(ausenciasExistentesQuery?.data || []).map((a) => ({
(ausenciasExistentesQuery?.data || [])
.filter((a) => a.status === "aprovado" || a.status === "aguardando_aprovacao")
.map((a) => ({
dataInicio: a.dataInicio,
dataFim: a.dataFim,
status: a.status as "aguardando_aprovacao" | "aprovado" | "reprovado",
status: a.status as "aguardando_aprovacao" | "aprovado",
}))
);
@@ -97,6 +106,8 @@
try {
processando = true;
mostrarModalErro = false;
mensagemErroModal = "";
await client.mutation(api.ausencias.criarSolicitacao, {
funcionarioId,
@@ -112,14 +123,32 @@
}
} catch (error) {
console.error("Erro ao criar solicitação:", error);
toast.error(
error instanceof Error ? error.message : "Erro ao criar solicitação de ausência"
);
const mensagemErro = error instanceof Error ? error.message : String(error);
// Verificar se é erro de sobreposição de período
if (
mensagemErro.includes("Já existe uma solicitação") ||
mensagemErro.includes("já existe") ||
mensagemErro.includes("solicitação aprovada ou pendente")
) {
mensagemErroModal = "Não é possível criar esta solicitação.";
detalhesErroModal = `Já existe uma solicitação aprovada ou pendente para o período selecionado:\n\nPeríodo selecionado: ${new Date(dataInicio).toLocaleDateString("pt-BR")} até ${new Date(dataFim).toLocaleDateString("pt-BR")}\n\nPor favor, escolha um período diferente ou aguarde a resposta da solicitação existente.`;
mostrarModalErro = true;
} else {
// Outros erros continuam usando toast
toast.error(mensagemErro);
}
} finally {
processando = false;
}
}
function fecharModalErro() {
mostrarModalErro = false;
mensagemErroModal = "";
detalhesErroModal = "";
}
function handlePeriodoSelecionado(periodo: { dataInicio: string; dataFim: string }) {
dataInicio = periodo.dataInicio;
dataFim = periodo.dataFim;
@@ -206,12 +235,19 @@
</p>
</div>
{#if ausenciasExistentesQuery === undefined}
<div class="flex items-center justify-center py-12">
<span class="loading loading-spinner loading-lg"></span>
<span class="ml-4 text-base-content/70">Carregando ausências existentes...</span>
</div>
{:else}
<CalendarioAusencias
dataInicio={dataInicio}
dataFim={dataFim}
ausenciasExistentes={ausenciasExistentes}
onPeriodoSelecionado={handlePeriodoSelecionado}
/>
{/if}
{#if dataInicio && dataFim}
<div class="alert alert-success shadow-lg">
@@ -428,6 +464,15 @@
</div>
</div>
<!-- Modal de Erro -->
<ErrorModal
open={mostrarModalErro}
title="Período Indisponível"
message={mensagemErroModal || "Já existe uma solicitação para este período."}
details={detalhesErroModal}
onClose={fecharModalErro}
/>
<style>
.wizard-ausencia {
max-width: 1000px;