From 6d613fe6183c809bc31f789cb85b729e65f1de2e Mon Sep 17 00:00:00 2001 From: deyvisonwanderley Date: Tue, 4 Nov 2025 03:37:22 -0300 Subject: [PATCH] feat: add required field validation and error handling in file upload component - Introduced a `required` prop in the `FileUpload` component to enforce mandatory file uploads. - Enhanced error handling by implementing a modal for displaying error messages related to missing required fields and upload issues. - Updated the `+page.svelte` file to integrate the new error modal and improve user feedback during form submissions. - Ensured that all relevant file upload sections now validate the presence of documents before allowing form submission. --- apps/web/src/lib/components/ErrorModal.svelte | 54 ++ apps/web/src/lib/components/FileUpload.svelte | 553 +++++++++--------- .../atestados-licencas/+page.svelte | 124 +++- 3 files changed, 444 insertions(+), 287 deletions(-) create mode 100644 apps/web/src/lib/components/ErrorModal.svelte diff --git a/apps/web/src/lib/components/ErrorModal.svelte b/apps/web/src/lib/components/ErrorModal.svelte new file mode 100644 index 0000000..9684a28 --- /dev/null +++ b/apps/web/src/lib/components/ErrorModal.svelte @@ -0,0 +1,54 @@ + + +{#if open} + +{/if} + diff --git a/apps/web/src/lib/components/FileUpload.svelte b/apps/web/src/lib/components/FileUpload.svelte index f6d62c0..60e9e77 100644 --- a/apps/web/src/lib/components/FileUpload.svelte +++ b/apps/web/src/lib/components/FileUpload.svelte @@ -1,274 +1,279 @@ - - -
- - - - - {#if value || fileName} -
- -
- {#if previewUrl} - Preview - {:else if fileType === "application/pdf" || fileName.endsWith(".pdf")} -
- - - -
- {:else} -
- - - -
- {/if} -
- - -
-

{fileName || "Arquivo anexado"}

-

- {#if uploading} - Carregando... - {:else} - Enviado com sucesso - {/if} -

-
- - -
- {#if fileUrl} - - {/if} - - -
-
- {:else} - - {/if} - - {#if error} -
- {error} -
- {/if} -
- + + +
+ + + + + {#if value || fileName} +
+ +
+ {#if previewUrl} + Preview + {:else if fileType === "application/pdf" || fileName.endsWith(".pdf")} +
+ + + +
+ {:else} +
+ + + +
+ {/if} +
+ + +
+

{fileName || "Arquivo anexado"}

+

+ {#if uploading} + Carregando... + {:else} + Enviado com sucesso + {/if} +

+
+ + +
+ {#if fileUrl} + + {/if} + + +
+
+ {:else} + + {/if} + + {#if error} +
+ {error} +
+ {/if} +
+ diff --git a/apps/web/src/routes/(dashboard)/recursos-humanos/atestados-licencas/+page.svelte b/apps/web/src/routes/(dashboard)/recursos-humanos/atestados-licencas/+page.svelte index 65b5f26..1e1f21e 100644 --- a/apps/web/src/routes/(dashboard)/recursos-humanos/atestados-licencas/+page.svelte +++ b/apps/web/src/routes/(dashboard)/recursos-humanos/atestados-licencas/+page.svelte @@ -5,6 +5,7 @@ import { toast } from "svelte-sonner"; import FuncionarioSelect from "$lib/components/FuncionarioSelect.svelte"; import FileUpload from "$lib/components/FileUpload.svelte"; + import ErrorModal from "$lib/components/ErrorModal.svelte"; import type { Id } from "@sgse-app/backend/convex/_generated/dataModel"; const client = useConvexClient(); @@ -74,6 +75,14 @@ let salvandoMaternidade = $state(false); let salvandoPaternidade = $state(false); + // Modal de erro + let erroModal = $state({ + aberto: false, + titulo: "", + mensagem: "", + detalhes: "", + }); + // Licenças maternidade para prorrogação (derivar dos dados já carregados) const licencasMaternidade = $derived.by(() => { const dados = dadosQuery?.data; @@ -114,10 +123,33 @@ } } + // Função para mostrar erro em modal + function mostrarErro(titulo: string, mensagem: string, detalhes?: string) { + erroModal = { + aberto: true, + titulo, + mensagem, + detalhes: detalhes || "", + }; + } + // Salvar Atestado Médico async function salvarAtestadoMedico() { if (!atestadoMedico.funcionarioId || !atestadoMedico.dataInicio || !atestadoMedico.dataFim || !atestadoMedico.cid) { - toast.error("Preencha todos os campos obrigatórios"); + mostrarErro( + "Campos obrigatórios", + "Preencha todos os campos obrigatórios antes de salvar.", + "Campos obrigatórios: Funcionário, Data Início, Data Fim e CID" + ); + return; + } + + if (!atestadoMedico.documentoId) { + mostrarErro( + "Documento obrigatório", + "É necessário anexar o documento do atestado médico.", + "Por favor, faça o upload do arquivo PDF ou imagem do atestado antes de salvar." + ); return; } @@ -129,14 +161,16 @@ dataFim: atestadoMedico.dataFim, cid: atestadoMedico.cid, observacoes: atestadoMedico.observacoes || undefined, - documentoId: atestadoMedico.documentoId as Id<"_storage"> | undefined, + documentoId: atestadoMedico.documentoId as Id<"_storage">, }); toast.success("Atestado médico registrado com sucesso!"); resetarFormularioAtestado(); abaAtiva = "dashboard"; } catch (error: any) { - toast.error(error?.message || "Erro ao registrar atestado"); + const mensagemErro = error?.message || "Erro ao registrar atestado"; + const detalhesErro = error?.data?.message || error?.toString() || ""; + mostrarErro("Erro ao registrar", mensagemErro, detalhesErro); } finally { salvandoAtestado = false; } @@ -145,7 +179,20 @@ // Salvar Declaração async function salvarDeclaracao() { if (!declaracao.funcionarioId || !declaracao.dataInicio || !declaracao.dataFim) { - toast.error("Preencha todos os campos obrigatórios"); + mostrarErro( + "Campos obrigatórios", + "Preencha todos os campos obrigatórios antes de salvar.", + "Campos obrigatórios: Funcionário, Data Início e Data Fim" + ); + return; + } + + if (!declaracao.documentoId) { + mostrarErro( + "Documento obrigatório", + "É necessário anexar o documento da declaração.", + "Por favor, faça o upload do arquivo PDF ou imagem da declaração antes de salvar." + ); return; } @@ -156,14 +203,16 @@ dataInicio: declaracao.dataInicio, dataFim: declaracao.dataFim, observacoes: declaracao.observacoes || undefined, - documentoId: declaracao.documentoId as Id<"_storage"> | undefined, + documentoId: declaracao.documentoId as Id<"_storage">, }); toast.success("Declaração registrada com sucesso!"); resetarFormularioDeclaracao(); abaAtiva = "dashboard"; } catch (error: any) { - toast.error(error?.message || "Erro ao registrar declaração"); + const mensagemErro = error?.message || "Erro ao registrar declaração"; + const detalhesErro = error?.data?.message || error?.toString() || ""; + mostrarErro("Erro ao registrar", mensagemErro, detalhesErro); } finally { salvandoDeclaracao = false; } @@ -172,12 +221,29 @@ // Salvar Licença Maternidade async function salvarLicencaMaternidade() { if (!licencaMaternidade.funcionarioId || !licencaMaternidade.dataInicio || !licencaMaternidade.dataFim) { - toast.error("Preencha todos os campos obrigatórios"); + mostrarErro( + "Campos obrigatórios", + "Preencha todos os campos obrigatórios antes de salvar.", + "Campos obrigatórios: Funcionário, Data Início e Data Fim" + ); return; } if (licencaMaternidade.ehProrrogacao && !licencaMaternidade.licencaOriginalId) { - toast.error("Selecione a licença original para prorrogação"); + mostrarErro( + "Licença original obrigatória", + "Para prorrogações, é necessário selecionar a licença original.", + "Selecione a licença de maternidade original no campo 'Licença Original'." + ); + return; + } + + if (!licencaMaternidade.documentoId) { + mostrarErro( + "Documento obrigatório", + "É necessário anexar o documento da licença de maternidade.", + "Por favor, faça o upload do arquivo PDF ou imagem da licença antes de salvar." + ); return; } @@ -188,7 +254,7 @@ dataInicio: licencaMaternidade.dataInicio, dataFim: licencaMaternidade.dataFim, observacoes: licencaMaternidade.observacoes || undefined, - documentoId: licencaMaternidade.documentoId as Id<"_storage"> | undefined, + documentoId: licencaMaternidade.documentoId as Id<"_storage">, licencaOriginalId: licencaMaternidade.licencaOriginalId as Id<"licencas"> | undefined, }); @@ -196,7 +262,9 @@ resetarFormularioMaternidade(); abaAtiva = "dashboard"; } catch (error: any) { - toast.error(error?.message || "Erro ao registrar licença"); + const mensagemErro = error?.message || "Erro ao registrar licença"; + const detalhesErro = error?.data?.message || error?.toString() || ""; + mostrarErro("Erro ao registrar", mensagemErro, detalhesErro); } finally { salvandoMaternidade = false; } @@ -205,7 +273,20 @@ // Salvar Licença Paternidade async function salvarLicencaPaternidade() { if (!licencaPaternidade.funcionarioId || !licencaPaternidade.dataInicio || !licencaPaternidade.dataFim) { - toast.error("Preencha todos os campos obrigatórios"); + mostrarErro( + "Campos obrigatórios", + "Preencha todos os campos obrigatórios antes de salvar.", + "Campos obrigatórios: Funcionário, Data Início e Data Fim" + ); + return; + } + + if (!licencaPaternidade.documentoId) { + mostrarErro( + "Documento obrigatório", + "É necessário anexar o documento da licença de paternidade.", + "Por favor, faça o upload do arquivo PDF ou imagem da licença antes de salvar." + ); return; } @@ -216,14 +297,16 @@ dataInicio: licencaPaternidade.dataInicio, dataFim: licencaPaternidade.dataFim, observacoes: licencaPaternidade.observacoes || undefined, - documentoId: licencaPaternidade.documentoId as Id<"_storage"> | undefined, + documentoId: licencaPaternidade.documentoId as Id<"_storage">, }); toast.success("Licença paternidade registrada com sucesso!"); resetarFormularioPaternidade(); abaAtiva = "dashboard"; } catch (error: any) { - toast.error(error?.message || "Erro ao registrar licença"); + const mensagemErro = error?.message || "Erro ao registrar licença"; + const detalhesErro = error?.data?.message || error?.toString() || ""; + mostrarErro("Erro ao registrar", mensagemErro, detalhesErro); } finally { salvandoPaternidade = false; } @@ -1220,6 +1303,7 @@ { atestadoMedico.documentoId = await handleDocumentoUpload( file @@ -1305,6 +1389,7 @@ { declaracao.documentoId = await handleDocumentoUpload(file); }} @@ -1424,6 +1509,7 @@ { licencaMaternidade.documentoId = await handleDocumentoUpload( file @@ -1512,6 +1598,7 @@ { licencaPaternidade.documentoId = await handleDocumentoUpload( file @@ -1560,3 +1647,14 @@ {/if} + + { + erroModal.aberto = false; + }} +/> +