From d5c01aabab69175d71e9dbf97cb516b9acb4e548 Mon Sep 17 00:00:00 2001 From: deyvisonwanderley Date: Tue, 4 Nov 2025 05:05:13 -0300 Subject: [PATCH] feat: add dependents management to employee registration - Introduced functionality to manage dependents during employee registration, allowing users to add details such as relationship, name, CPF, and birth date. - Updated the backend schema and mutation to support optional dependents, enhancing the employee data model. - Enhanced the frontend form to include fields for dependents, improving the user experience in the employee registration process. --- .../funcionarios/cadastro/+page.svelte | 2906 +++++++++-------- packages/backend/convex/funcionarios.ts | 34 + packages/backend/convex/schema.ts | 18 + 3 files changed, 1592 insertions(+), 1366 deletions(-) diff --git a/apps/web/src/routes/(dashboard)/recursos-humanos/funcionarios/cadastro/+page.svelte b/apps/web/src/routes/(dashboard)/recursos-humanos/funcionarios/cadastro/+page.svelte index 90dda4c..78addfc 100644 --- a/apps/web/src/routes/(dashboard)/recursos-humanos/funcionarios/cadastro/+page.svelte +++ b/apps/web/src/routes/(dashboard)/recursos-humanos/funcionarios/cadastro/+page.svelte @@ -1,1366 +1,1540 @@ - - -
- - - - -
-
-
- - - -
-
-

Cadastro de Funcionário

-

Preencha os campos abaixo para cadastrar um novo funcionário

-
-
-
- - - {#if notice} -
- - {#if notice.kind === "success"} - - {:else} - - {/if} - - {notice.text} -
- {/if} - - -
{ e.preventDefault(); handleSubmit(); }}> - - -
-
-

- - - - Informações Pessoais -

- -
- -
- - -
- - -
- - -
- - -
- - { - const target = e.target as HTMLInputElement; - cpf = maskCPF(target.value); - target.value = cpf; - }} - required - /> -
- - -
- - { - const target = e.target as HTMLInputElement; - rg = onlyDigits(target.value); - target.value = rg; - }} - required - /> -
- - -
- - -
- - -
- - { - const target = e.target as HTMLInputElement; - rgDataEmissao = maskDate(target.value); - target.value = rgDataEmissao; - }} - /> -
- - -
- - -
- - -
- - -
- - -
- - { - const target = e.target as HTMLInputElement; - nascimento = maskDate(target.value); - target.value = nascimento; - }} - required - /> -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
-
-
-
- - -
-
-

- - - - Documentos Pessoais -

- -
- -
- - -
- -
- - -
- -
- - { - const target = e.target as HTMLInputElement; - carteiraProfissionalDataEmissao = maskDate(target.value); - target.value = carteiraProfissionalDataEmissao; - }} - /> -
- - -
- - -
- -
- - -
- - -
- - -
- -
- - -
- -
- - -
- - -
- - -
-
-
-
- - -
-
-

- - - - Formação e Saúde -

- -
- -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
-
-
-
- - -
-
-

- - - - Cursos e Treinamentos -

- -

- Adicione até 7 cursos ou treinamentos realizados pelo funcionário (opcional) -

- - - {#if cursos.length > 0} -
-

Cursos adicionados ({cursos.length}/7)

- {#each cursos as curso} -
-
-

{curso.descricao}

-

{curso.data}

-
- -
- {/each} -
- {/if} - - - {#if cursos.length < 7} -
- -
- Adicionar Curso/Treinamento -
-
-
-
- - -
- -
- - cursoAtual.data = maskDate(e.currentTarget.value)} - /> -
- -
- - { - const file = e.currentTarget.files?.[0]; - if (file) cursoAtual.arquivo = file; - }} - /> -
- - -
-
-
- {:else} -
- - - - Limite de 7 cursos atingido -
- {/if} -
-
- - -
-
-

- - - - - Endereço e Contato -

- -
- -
- - { - const target = e.target as HTMLInputElement; - cep = maskCEP(target.value); - target.value = cep; - }} - onblur={() => fillFromCEP(cep)} - required - /> -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - { - const target = e.target as HTMLInputElement; - telefone = maskPhone(target.value); - target.value = telefone; - }} - required - /> -
-
-
-
- - -
-
-

- - - - Cargo e Vínculo -

- -
- -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- -
- - { - const target = e.target as HTMLInputElement; - nomeacaoData = maskDate(target.value); - target.value = nomeacaoData; - }} - /> -
- -
- - { - const target = e.target as HTMLInputElement; - nomeacaoDOE = maskDate(target.value); - target.value = nomeacaoDOE; - }} - /> -
- - -
- - { - const target = e.target as HTMLInputElement; - admissaoData = maskDate(target.value); - target.value = admissaoData; - }} - /> -
- - -
- -
- - - {#if pertenceOrgaoPublico} -
- - -
- {/if} - - -
- - -
-
-
-
- - -
-
-

- - - - Dados Bancários - Bradesco -

- -
- -
- - -
- - -
- - -
- - -
- - -
-
-
-
- - - - - -
-
-

- - - - Documentação Anexa -

- -

- Anexe os documentos necessários em formato PDF ou imagem (máximo 10MB cada) -

- - {#each categoriasDocumentos as categoria} -
-

{categoria}

-
- {#each getDocumentosByCategoria(categoria) as doc} - handleDocumentoUpload(doc.campo, file)} - onRemove={() => handleDocumentoRemove(doc.campo)} - disabled={loading} - /> - {/each} -
-
- {/each} -
-
- - -
-
-
- - -
-
-
- -
+ + +
+ + + + +
+
+
+ + + +
+
+

Cadastro de Funcionário

+

Preencha os campos abaixo para cadastrar um novo funcionário

+
+
+
+ + + {#if notice} +
+ + {#if notice.kind === "success"} + + {:else} + + {/if} + + {notice.text} +
+ {/if} + + +
{ e.preventDefault(); }}> + + +
+
+

+ + + + Informações Pessoais +

+ +
+ +
+ + +
+ + +
+ + +
+ + +
+ + { + const target = e.target as HTMLInputElement; + cpf = maskCPF(target.value); + target.value = cpf; + }} + required + /> +
+ + +
+ + { + const target = e.target as HTMLInputElement; + rg = onlyDigits(target.value); + target.value = rg; + }} + required + /> +
+ + +
+ + +
+ + +
+ + { + const target = e.target as HTMLInputElement; + rgDataEmissao = maskDate(target.value); + target.value = rgDataEmissao; + }} + /> +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + { + const target = e.target as HTMLInputElement; + nascimento = maskDate(target.value); + target.value = nascimento; + }} + required + /> +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+
+
+
+ + +
+
+

+ + + + Documentos Pessoais +

+ +
+ +
+ + +
+ +
+ + +
+ +
+ + { + const target = e.target as HTMLInputElement; + carteiraProfissionalDataEmissao = maskDate(target.value); + target.value = carteiraProfissionalDataEmissao; + }} + /> +
+ + +
+ + +
+ +
+ + +
+ + +
+ + +
+ +
+ + +
+ +
+ + +
+ + +
+ + +
+
+
+
+ + +
+
+

+ + + + Formação e Saúde +

+ +
+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+
+
+
+ + +
+
+

+ + + + Cursos e Treinamentos +

+ +

+ Adicione até 7 cursos ou treinamentos realizados pelo funcionário (opcional) +

+ + + {#if cursos.length > 0} +
+

Cursos adicionados ({cursos.length}/7)

+ {#each cursos as curso} +
+
+

{curso.descricao}

+

{curso.data}

+
+ +
+ {/each} +
+ {/if} + + + {#if cursos.length < 7} +
+ +
+ Adicionar Curso/Treinamento +
+
+
+
+ + +
+ +
+ + cursoAtual.data = maskDate(e.currentTarget.value)} + /> +
+ +
+ + { + const file = e.currentTarget.files?.[0]; + if (file) cursoAtual.arquivo = file; + }} + /> +
+ + +
+
+
+ {:else} +
+ + + + Limite de 7 cursos atingido +
+ {/if} +
+
+ + +
+
+

+ + + + + Endereço e Contato +

+ +
+ +
+ + { + const target = e.target as HTMLInputElement; + cep = maskCEP(target.value); + target.value = cep; + }} + onblur={() => fillFromCEP(cep)} + required + /> +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + { + const target = e.target as HTMLInputElement; + telefone = maskPhone(target.value); + target.value = telefone; + }} + required + /> +
+
+
+
+ + +
+
+

+ + + + Dependentes +

+ + {#if dependentes.length > 0} +
+

Dependentes adicionados ({dependentes.length}/10)

+ {#each dependentes as dep} +
+
+

{dep.nome} — {dep.parentesco}

+

CPF: {dep.cpf} • Nasc.: {dep.nascimento}

+
+ +
+ {/each} +
+ {/if} + + {#if dependentes.length < 10} +
+ +
Adicionar Dependente
+
+
+
+ + +
+ +
+ + +
+ +
+ + { const t = e.target as HTMLInputElement; dependenteAtual.cpf = maskCPF(t.value); t.value = dependenteAtual.cpf; }} /> +
+ +
+ + { const t = e.target as HTMLInputElement; dependenteAtual.nascimento = maskDate(t.value); t.value = dependenteAtual.nascimento; }} /> +
+ +
+ + { const file = e.currentTarget.files?.[0]; dependenteAtual.arquivo = file || null; if (file) { try { dependenteAtual.documentoId = await uploadDocumentoDependente(file); } catch { alert("Falha no upload do documento do dependente"); } } }} /> +
+ +
+ +
+
+
+
+ {/if} +
+
+ + +
+
+

+ + + + Cargo e Vínculo +

+ +
+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ +
+ + { + const target = e.target as HTMLInputElement; + nomeacaoData = maskDate(target.value); + target.value = nomeacaoData; + }} + /> +
+ +
+ + { + const target = e.target as HTMLInputElement; + nomeacaoDOE = maskDate(target.value); + target.value = nomeacaoDOE; + }} + /> +
+ + +
+ + { + const target = e.target as HTMLInputElement; + admissaoData = maskDate(target.value); + target.value = admissaoData; + }} + /> +
+ + +
+ +
+ + + {#if pertenceOrgaoPublico} +
+ + +
+ {/if} + + +
+ + +
+
+
+
+ + +
+
+

+ + + + Dados Bancários - Bradesco +

+ +
+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+
+
+
+ + + + + +
+
+

+ + + + Documentação Anexa +

+ +

+ Anexe os documentos necessários em formato PDF ou imagem (máximo 10MB cada) +

+ + {#each categoriasDocumentos as categoria} +
+

{categoria}

+
+ {#each getDocumentosByCategoria(categoria) as doc} + handleDocumentoUpload(doc.campo, file)} + onRemove={() => handleDocumentoRemove(doc.campo)} + disabled={loading} + /> + {/each} +
+
+ {/each} +
+
+ + +
+
+
+ + +
+
+
+ + + + + + +
diff --git a/packages/backend/convex/funcionarios.ts b/packages/backend/convex/funcionarios.ts index 295240c..fb90ba8 100644 --- a/packages/backend/convex/funcionarios.ts +++ b/packages/backend/convex/funcionarios.ts @@ -174,6 +174,23 @@ export const create = mutation({ declaracaoIdoneidade: v.optional(v.id("_storage")), termoNepotismo: v.optional(v.id("_storage")), termoOpcaoRemuneracao: v.optional(v.id("_storage")), + // Dependentes (opcional) + dependentes: v.optional( + v.array( + v.object({ + parentesco: v.union( + v.literal("filho"), + v.literal("filha"), + v.literal("conjuge"), + v.literal("outro") + ), + nome: v.string(), + cpf: v.string(), + nascimento: v.string(), + documentoId: v.optional(v.id("_storage")), + }) + ) + ), }, returns: v.id("funcionarios"), handler: async (ctx, args) => { @@ -303,6 +320,23 @@ export const update = mutation({ declaracaoIdoneidade: v.optional(v.id("_storage")), termoNepotismo: v.optional(v.id("_storage")), termoOpcaoRemuneracao: v.optional(v.id("_storage")), + // Dependentes (opcional) + dependentes: v.optional( + v.array( + v.object({ + parentesco: v.union( + v.literal("filho"), + v.literal("filha"), + v.literal("conjuge"), + v.literal("outro") + ), + nome: v.string(), + cpf: v.string(), + nascimento: v.string(), + documentoId: v.optional(v.id("_storage")), + }) + ) + ), }, returns: v.null(), handler: async (ctx, args) => { diff --git a/packages/backend/convex/schema.ts b/packages/backend/convex/schema.ts index 49bf0ad..1589dbf 100644 --- a/packages/backend/convex/schema.ts +++ b/packages/backend/convex/schema.ts @@ -134,6 +134,24 @@ export default defineSchema({ comprovanteResidencia: v.optional(v.id("_storage")), comprovanteContaBradesco: v.optional(v.id("_storage")), + // Dependentes do funcionário (uploads opcionais) + dependentes: v.optional( + v.array( + v.object({ + parentesco: v.union( + v.literal("filho"), + v.literal("filha"), + v.literal("conjuge"), + v.literal("outro") + ), + nome: v.string(), + cpf: v.string(), + nascimento: v.string(), + documentoId: v.optional(v.id("_storage")), + }) + ) + ), + // Declarações (Storage IDs) declaracaoAcumulacaoCargo: v.optional(v.id("_storage")), declaracaoDependentesIR: v.optional(v.id("_storage")),