Fix page with lint errors #16
@@ -1,202 +1,216 @@
|
||||
<script lang="ts">
|
||||
import { useConvexClient } from "convex-svelte";
|
||||
import { api } from "@sgse-app/backend/convex/_generated/api";
|
||||
import { goto } from "$app/navigation";
|
||||
import type { SimboloTipo } from "@sgse-app/backend/convex/schema";
|
||||
import FileUpload from "$lib/components/FileUpload.svelte";
|
||||
import {
|
||||
maskCPF, maskCEP, maskPhone, maskDate, maskUF, onlyDigits,
|
||||
validateCPF, validateDate
|
||||
} from "$lib/utils/masks";
|
||||
import {
|
||||
SEXO_OPTIONS, ESTADO_CIVIL_OPTIONS, GRAU_INSTRUCAO_OPTIONS,
|
||||
GRUPO_SANGUINEO_OPTIONS, FATOR_RH_OPTIONS, APOSENTADO_OPTIONS, UFS_BRASIL
|
||||
} from "$lib/utils/constants";
|
||||
import { documentos, categoriasDocumentos, getDocumentosByCategoria } from "$lib/utils/documentos";
|
||||
import ModelosDeclaracoes from "$lib/components/ModelosDeclaracoes.svelte";
|
||||
import { useConvexClient } from 'convex-svelte';
|
||||
import { api } from '@sgse-app/backend/convex/_generated/api';
|
||||
import { goto } from '$app/navigation';
|
||||
import type { SimboloTipo } from '@sgse-app/backend/convex/schema';
|
||||
import FileUpload from '$lib/components/FileUpload.svelte';
|
||||
import {
|
||||
maskCPF,
|
||||
maskCEP,
|
||||
maskPhone,
|
||||
maskDate,
|
||||
onlyDigits,
|
||||
validateCPF,
|
||||
validateDate
|
||||
} from '$lib/utils/masks';
|
||||
import {
|
||||
SEXO_OPTIONS,
|
||||
ESTADO_CIVIL_OPTIONS,
|
||||
GRAU_INSTRUCAO_OPTIONS,
|
||||
GRUPO_SANGUINEO_OPTIONS,
|
||||
FATOR_RH_OPTIONS,
|
||||
APOSENTADO_OPTIONS,
|
||||
UFS_BRASIL
|
||||
} from '$lib/utils/constants';
|
||||
import { categoriasDocumentos, getDocumentosByCategoria } from '$lib/utils/documentos';
|
||||
import ModelosDeclaracoes from '$lib/components/ModelosDeclaracoes.svelte';
|
||||
import { resolve } from '$app/paths';
|
||||
import type { CreateArgs } from '@sgse-app/backend/convex/funcionarios';
|
||||
import type { Id } from '@sgse-app/backend/convex/_generated/dataModel';
|
||||
|
||||
const client = useConvexClient();
|
||||
const client = useConvexClient();
|
||||
|
||||
let simbolos: Array<{
|
||||
_id: string;
|
||||
nome: string;
|
||||
tipo: SimboloTipo;
|
||||
descricao: string;
|
||||
}> = $state([]);
|
||||
let simbolos: Array<{
|
||||
_id: string;
|
||||
nome: string;
|
||||
tipo: SimboloTipo;
|
||||
descricao: string;
|
||||
}> = $state([]);
|
||||
|
||||
let tipo = $state<SimboloTipo>('cargo_comissionado');
|
||||
let loading = $state(false);
|
||||
let notice = $state<{ kind: 'success' | 'error'; text: string } | null>(null);
|
||||
|
||||
// Cursos e Treinamentos
|
||||
let cursos = $state<Array<{
|
||||
id: string;
|
||||
descricao: string;
|
||||
data: string;
|
||||
certificadoId?: string;
|
||||
}>>([]);
|
||||
let mostrarFormularioCurso = $state(false);
|
||||
let cursoAtual = $state({ descricao: "", data: "", arquivo: null as File | null });
|
||||
// Campos obrigatórios
|
||||
let nome = $state('');
|
||||
let matricula = $state('');
|
||||
let cpf = $state('');
|
||||
let rg = $state('');
|
||||
let nascimento = $state('');
|
||||
let email = $state('');
|
||||
let telefone = $state('');
|
||||
let endereco = $state('');
|
||||
let cep = $state('');
|
||||
let cidade = $state('');
|
||||
let uf = $state('');
|
||||
let simboloId: Id<'simbolos'> | null = $derived.by(() => {
|
||||
if (tipo) {
|
||||
return null;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
});
|
||||
let admissaoData = $state('');
|
||||
|
||||
// Dependentes
|
||||
let dependentes = $state<Array<{ id: string; parentesco: string; nome: string; cpf: string; nascimento: string; documentoId?: string; salarioFamilia?: boolean; impostoRenda?: boolean }>>([]);
|
||||
let mostrarFormularioDependente = $state(false);
|
||||
let dependenteAtual = $state<{ parentesco: string; nome: string; cpf: string; nascimento: string; arquivo: File | null; documentoId?: string; salarioFamilia?: boolean; impostoRenda?: boolean }>({
|
||||
parentesco: "",
|
||||
nome: "",
|
||||
cpf: "",
|
||||
nascimento: "",
|
||||
arquivo: null,
|
||||
documentoId: undefined,
|
||||
salarioFamilia: false,
|
||||
impostoRenda: false,
|
||||
});
|
||||
// Dados Pessoais Adicionais
|
||||
let nomePai = $state('');
|
||||
let nomeMae = $state('');
|
||||
let naturalidade = $state('');
|
||||
let naturalidadeUF = $state('');
|
||||
let sexo = $state<'masculino' | 'feminino' | 'outro' | null>(null);
|
||||
let estadoCivil = $state<'solteiro' | 'casado' | 'divorciado' | 'viuvo' | 'uniao_estavel' | null>(
|
||||
null
|
||||
);
|
||||
let nacionalidade = $state('Brasileira');
|
||||
|
||||
function adicionarCurso() {
|
||||
if (!cursoAtual.descricao.trim() || !cursoAtual.data.trim()) {
|
||||
alert("Preencha a descrição e a data do curso");
|
||||
return;
|
||||
}
|
||||
cursos.push({
|
||||
id: crypto.randomUUID(),
|
||||
descricao: cursoAtual.descricao,
|
||||
data: cursoAtual.data,
|
||||
certificadoId: undefined
|
||||
});
|
||||
cursoAtual = { descricao: "", data: "", arquivo: null };
|
||||
}
|
||||
// Documentos Pessoais
|
||||
let rgOrgaoExpedidor = $state('');
|
||||
let rgDataEmissao = $state('');
|
||||
let carteiraProfissionalNumero = $state('');
|
||||
let carteiraProfissionalSerie = $state('');
|
||||
let carteiraProfissionalDataEmissao = $state('');
|
||||
let reservistaNumero = $state('');
|
||||
let reservistaSerie = $state('');
|
||||
let tituloEleitorNumero = $state('');
|
||||
let tituloEleitorZona = $state('');
|
||||
let tituloEleitorSecao = $state('');
|
||||
let pisNumero = $state('');
|
||||
|
||||
function removerCurso(id: string) {
|
||||
cursos = cursos.filter(c => c.id !== id);
|
||||
}
|
||||
// Formação e Saúde
|
||||
let grauInstrucao = $state<
|
||||
'fundamental' | 'medio' | 'superior' | 'pos_graduacao' | 'mestrado' | 'doutorado' | null
|
||||
>(null);
|
||||
let formacao = $state('');
|
||||
let formacaoRegistro = $state('');
|
||||
let grupoSanguineo = $state<'A' | 'B' | 'AB' | 'O' | null>(null);
|
||||
let fatorRH = $state<'positivo' | 'negativo' | null>(null);
|
||||
|
||||
async function uploadCertificado(file: File): Promise<string> {
|
||||
const storageId = await client.mutation(api.documentos.generateUploadUrl, {});
|
||||
const uploadUrl = await client.mutation(api.documentos.generateUploadUrl, {});
|
||||
const response = await fetch(uploadUrl, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": file.type },
|
||||
body: file,
|
||||
});
|
||||
const result = await response.json();
|
||||
return result.storageId;
|
||||
}
|
||||
// Cargo e Vínculo
|
||||
let descricaoCargo = $state('');
|
||||
let nomeacaoPortaria = $state('');
|
||||
let nomeacaoData = $state('');
|
||||
let nomeacaoDOE = $state('');
|
||||
let pertenceOrgaoPublico = $state(false);
|
||||
let orgaoOrigem = $state('');
|
||||
let aposentado = $state<'nao' | 'funape_ipsep' | 'inss' | null>('nao');
|
||||
let regimeTrabalho = $state<
|
||||
'clt' | 'estatutario_municipal' | 'estatutario_pe' | 'estatutario_federal' | null
|
||||
>(null);
|
||||
|
||||
async function uploadDocumentoDependente(file: File): Promise<string> {
|
||||
const uploadUrl = await client.mutation(api.documentos.generateUploadUrl, {});
|
||||
const response = await fetch(uploadUrl, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": file.type },
|
||||
body: file,
|
||||
});
|
||||
const result = await response.json();
|
||||
return result.storageId as string;
|
||||
}
|
||||
const REGIME_TRABALHO_OPTIONS = [
|
||||
{ value: 'clt', label: 'CLT' },
|
||||
{ value: 'estatutario_municipal', label: 'Estatutário Municipal' },
|
||||
{ value: 'estatutario_pe', label: 'Estatutário PE' },
|
||||
{ value: 'estatutario_federal', label: 'Estatutário Federal' }
|
||||
] as const;
|
||||
|
||||
function adicionarDependente() {
|
||||
if (dependentes.length >= 10) {
|
||||
alert("Limite de 10 dependentes atingido");
|
||||
return;
|
||||
}
|
||||
if (!dependenteAtual.parentesco || !dependenteAtual.nome.trim() || !dependenteAtual.cpf.trim() || !dependenteAtual.nascimento.trim()) {
|
||||
alert("Preencha Parentesco, Nome, CPF e Data de Nascimento do dependente");
|
||||
return;
|
||||
}
|
||||
if (!validateCPF(dependenteAtual.cpf)) {
|
||||
alert("CPF do dependente inválido");
|
||||
return;
|
||||
}
|
||||
if (!validateDate(dependenteAtual.nascimento)) {
|
||||
alert("Data de nascimento do dependente inválida");
|
||||
return;
|
||||
}
|
||||
dependentes.push({
|
||||
id: crypto.randomUUID(),
|
||||
parentesco: dependenteAtual.parentesco,
|
||||
nome: dependenteAtual.nome.trim(),
|
||||
cpf: onlyDigits(dependenteAtual.cpf),
|
||||
nascimento: dependenteAtual.nascimento,
|
||||
documentoId: dependenteAtual.documentoId,
|
||||
salarioFamilia: !!dependenteAtual.salarioFamilia,
|
||||
impostoRenda: !!dependenteAtual.impostoRenda,
|
||||
});
|
||||
dependenteAtual = { parentesco: "", nome: "", cpf: "", nascimento: "", arquivo: null, documentoId: undefined, salarioFamilia: false, impostoRenda: false };
|
||||
}
|
||||
// Dados Bancários
|
||||
let contaBradescoNumero = $state('');
|
||||
let contaBradescoDV = $state('');
|
||||
let contaBradescoAgencia = $state('');
|
||||
|
||||
function removerDependente(id: string) {
|
||||
dependentes = dependentes.filter((d) => d.id !== id);
|
||||
}
|
||||
// Documentos (Storage IDs)
|
||||
let documentosStorage: Record<string, string | undefined> = $state({});
|
||||
|
||||
async function loadSimbolos() {
|
||||
const list = await client.query(api.simbolos.getAll, {} as any);
|
||||
simbolos = list.map((s: any) => ({
|
||||
_id: s._id,
|
||||
nome: s.nome,
|
||||
tipo: s.tipo,
|
||||
descricao: s.descricao
|
||||
}));
|
||||
}
|
||||
// Cursos e Treinamentos
|
||||
let cursos = $state<
|
||||
Array<{
|
||||
id: string;
|
||||
descricao: string;
|
||||
data: string;
|
||||
certificadoId?: Id<'_storage'>;
|
||||
}>
|
||||
>([]);
|
||||
let mostrarFormularioCurso = $state(false);
|
||||
let cursoAtual = $state({ descricao: '', data: '', arquivo: null as File | null });
|
||||
|
||||
async function fillFromCEP(cepValue: string) {
|
||||
const cepDigits = onlyDigits(cepValue);
|
||||
if (cepDigits.length !== 8) return;
|
||||
// Dependentes
|
||||
let dependentes = $state<
|
||||
Array<{
|
||||
id: string;
|
||||
parentesco: 'outro' | 'filho' | 'filha' | 'conjuge' | null;
|
||||
nome: string;
|
||||
cpf: string;
|
||||
nascimento: string;
|
||||
documentoId?: Id<'_storage'>;
|
||||
salarioFamilia?: boolean;
|
||||
impostoRenda?: boolean;
|
||||
}>
|
||||
>([]);
|
||||
let mostrarFormularioDependente = $state(false);
|
||||
let dependenteAtual = $state<{
|
||||
parentesco: 'outro' | 'filho' | 'filha' | 'conjuge' | null;
|
||||
nome: string;
|
||||
cpf: string;
|
||||
nascimento: string;
|
||||
arquivo: File | null;
|
||||
documentoId?: Id<'_storage'>;
|
||||
salarioFamilia?: boolean;
|
||||
impostoRenda?: boolean;
|
||||
}>({
|
||||
parentesco: null,
|
||||
nome: '',
|
||||
cpf: '',
|
||||
nascimento: '',
|
||||
arquivo: null,
|
||||
documentoId: undefined,
|
||||
salarioFamilia: false,
|
||||
impostoRenda: false
|
||||
});
|
||||
|
||||
try {
|
||||
const res = await fetch(`https://viacep.com.br/ws/${cepDigits}/json/`);
|
||||
const data = await res.json();
|
||||
if (!data || data.erro) return;
|
||||
function adicionarCurso() {
|
||||
if (!cursoAtual.descricao.trim() || !cursoAtual.data.trim()) {
|
||||
alert('Preencha a descrição e a data do curso');
|
||||
return;
|
||||
}
|
||||
cursos.push({
|
||||
id: crypto.randomUUID(),
|
||||
descricao: cursoAtual.descricao,
|
||||
data: cursoAtual.data,
|
||||
certificadoId: undefined
|
||||
});
|
||||
cursoAtual = { descricao: '', data: '', arquivo: null };
|
||||
}
|
||||
|
||||
const enderecoFull = [data.logradouro, data.bairro].filter(Boolean).join(", ");
|
||||
endereco = enderecoFull;
|
||||
cidade = data.localidade || "";
|
||||
uf = data.uf || "";
|
||||
} catch {}
|
||||
}
|
||||
function removerCurso(id: string) {
|
||||
cursos = cursos.filter((c) => c.id !== id);
|
||||
}
|
||||
|
||||
async function handleDocumentoUpload(campo: string, file: File) {
|
||||
try {
|
||||
// Gerar URL de upload
|
||||
const uploadUrl = await client.mutation(api.documentos.generateUploadUrl, {});
|
||||
async function uploadCertificado(file: File): Promise<Id<'_storage'>> {
|
||||
const uploadUrl = await client.mutation(api.documentos.generateUploadUrl, {});
|
||||
const response = await fetch(uploadUrl, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': file.type },
|
||||
body: file
|
||||
});
|
||||
const result = await response.json();
|
||||
if (!result.storageId) {
|
||||
throw new Error('Erro ao fazer upload do certificado');
|
||||
}
|
||||
const storageId = result.storageId as unknown as Id<'_storage'>;
|
||||
return storageId;
|
||||
}
|
||||
|
||||
// Fazer upload do arquivo
|
||||
const result = await fetch(uploadUrl, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": file.type },
|
||||
body: file,
|
||||
});
|
||||
|
||||
const { storageId } = await result.json();
|
||||
documentosStorage[campo] = storageId;
|
||||
} catch (err: any) {
|
||||
throw new Error(err?.message || "Erro ao fazer upload");
|
||||
}
|
||||
}
|
||||
|
||||
async function handleDocumentoRemove(campo: string) {
|
||||
documentosStorage[campo] = undefined;
|
||||
}
|
||||
|
||||
async function handleSubmit() {
|
||||
// Validação básica
|
||||
if (!nome || !cpf || !rg || !nascimento || !email || !telefone) {
|
||||
notice = { kind: "error", text: "Preencha todos os campos obrigatórios" };
|
||||
return;
|
||||
}
|
||||
|
||||
if (!validateCPF(cpf)) {
|
||||
notice = { kind: "error", text: "CPF inválido" };
|
||||
return;
|
||||
}
|
||||
|
||||
if (!validateDate(nascimento)) {
|
||||
notice = { kind: "error", text: "Data de nascimento inválida" };
|
||||
return;
|
||||
}
|
||||
|
||||
if (!simboloId) {
|
||||
notice = { kind: "error", text: "Selecione um símbolo" };
|
||||
return;
|
||||
}
|
||||
async function uploadDocumentoDependente(file: File): Promise<Id<'_storage'>> {
|
||||
const uploadUrl = await client.mutation(api.documentos.generateUploadUrl, {});
|
||||
const response = await fetch(uploadUrl, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': file.type },
|
||||
body: file
|
||||
});
|
||||
const result = await response.json();
|
||||
return result.storageId as Id<'_storage'>;
|
||||
}
|
||||
|
||||
function adicionarDependente() {
|
||||
if (dependentes.length >= 10) {
|
||||
@@ -231,7 +245,7 @@
|
||||
impostoRenda: !!dependenteAtual.impostoRenda
|
||||
});
|
||||
dependenteAtual = {
|
||||
parentesco: '',
|
||||
parentesco: null,
|
||||
nome: '',
|
||||
cpf: '',
|
||||
nascimento: '',
|
||||
@@ -242,62 +256,232 @@
|
||||
};
|
||||
}
|
||||
|
||||
const novoFuncionarioId = await client.mutation(api.funcionarios.create, payload as any);
|
||||
function removerDependente(id: string) {
|
||||
dependentes = dependentes.filter((d) => d.id !== id);
|
||||
}
|
||||
|
||||
// Salvar cursos, se houver
|
||||
for (const curso of cursos) {
|
||||
let certificadoId = curso.certificadoId;
|
||||
// Se houver arquivo para upload, fazer o upload
|
||||
if (cursoAtual.arquivo && curso.id === cursos[cursos.length - 1].id) {
|
||||
try {
|
||||
certificadoId = await uploadCertificado(cursoAtual.arquivo);
|
||||
} catch (err) {
|
||||
console.error("Erro ao fazer upload do certificado:", err);
|
||||
}
|
||||
}
|
||||
async function loadSimbolos() {
|
||||
const list = await client.query(api.simbolos.getAll, {});
|
||||
simbolos = list.map((s) => ({
|
||||
_id: s._id,
|
||||
nome: s.nome,
|
||||
tipo: s.tipo,
|
||||
descricao: s.descricao
|
||||
}));
|
||||
}
|
||||
|
||||
await client.mutation(api.cursos.criar, {
|
||||
funcionarioId: novoFuncionarioId,
|
||||
descricao: curso.descricao,
|
||||
data: curso.data,
|
||||
certificadoId: certificadoId as any,
|
||||
});
|
||||
}
|
||||
async function fillFromCEP(cepValue: string) {
|
||||
const cepDigits = onlyDigits(cepValue);
|
||||
if (cepDigits.length !== 8) return;
|
||||
|
||||
notice = { kind: "success", text: "Funcionário cadastrado com sucesso!" };
|
||||
setTimeout(() => goto("/recursos-humanos/funcionarios"), 600);
|
||||
} catch (e: any) {
|
||||
const msg = e?.message || String(e);
|
||||
if (/CPF j[aá] cadastrado/i.test(msg)) {
|
||||
notice = { kind: "error", text: "CPF já cadastrado." };
|
||||
} else if (/Matr[ií]cula j[aá] cadastrada/i.test(msg)) {
|
||||
notice = { kind: "error", text: "Matrícula já cadastrada." };
|
||||
} else {
|
||||
notice = { kind: "error", text: "Erro ao cadastrar funcionário." };
|
||||
}
|
||||
} finally {
|
||||
loading = false;
|
||||
}
|
||||
}
|
||||
try {
|
||||
const res = await fetch(`https://viacep.com.br/ws/${cepDigits}/json/`);
|
||||
const data = await res.json();
|
||||
if (!data || data.erro) return;
|
||||
|
||||
$effect(() => {
|
||||
loadSimbolos();
|
||||
});
|
||||
const enderecoFull = [data.logradouro, data.bairro].filter(Boolean).join(', ');
|
||||
endereco = enderecoFull;
|
||||
cidade = data.localidade || '';
|
||||
uf = data.uf || '';
|
||||
} catch {}
|
||||
}
|
||||
|
||||
// Resetar simboloId quando tipo mudar
|
||||
$effect(() => {
|
||||
tipo; // track tipo
|
||||
simboloId = ""; // reset selection when tipo changes
|
||||
});
|
||||
async function handleDocumentoUpload(campo: string, file: File) {
|
||||
try {
|
||||
// Gerar URL de upload
|
||||
const uploadUrl = await client.mutation(api.documentos.generateUploadUrl, {});
|
||||
|
||||
// Fazer upload do arquivo
|
||||
const result = await fetch(uploadUrl, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': file.type },
|
||||
body: file
|
||||
});
|
||||
|
||||
const { storageId } = await result.json();
|
||||
documentosStorage[campo] = storageId;
|
||||
} catch (err) {
|
||||
if (err instanceof Error) {
|
||||
throw new Error(err.message);
|
||||
}
|
||||
throw new Error('Erro ao fazer upload');
|
||||
}
|
||||
}
|
||||
|
||||
async function handleDocumentoRemove(campo: string) {
|
||||
documentosStorage[campo] = undefined;
|
||||
}
|
||||
|
||||
async function handleSubmit() {
|
||||
// Validação básica
|
||||
if (!nome || !cpf || !rg || !nascimento || !email || !telefone) {
|
||||
notice = { kind: 'error', text: 'Preencha todos os campos obrigatórios' };
|
||||
return;
|
||||
}
|
||||
|
||||
if (!validateCPF(cpf)) {
|
||||
notice = { kind: 'error', text: 'CPF inválido' };
|
||||
return;
|
||||
}
|
||||
|
||||
if (!validateDate(nascimento)) {
|
||||
notice = { kind: 'error', text: 'Data de nascimento inválida' };
|
||||
return;
|
||||
}
|
||||
|
||||
if (!simboloId) {
|
||||
notice = { kind: 'error', text: 'Selecione um símbolo' };
|
||||
return;
|
||||
}
|
||||
|
||||
if (dependentes.some((d) => d.parentesco === null)) {
|
||||
notice = { kind: 'error', text: 'Preencha o parentesco de todos os dependentes' };
|
||||
return;
|
||||
}
|
||||
|
||||
if (!regimeTrabalho) {
|
||||
notice = { kind: 'error', text: 'Selecione um regime de trabalho' };
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
loading = true;
|
||||
|
||||
const payload: CreateArgs = {
|
||||
nome,
|
||||
matricula: matricula.trim() || undefined,
|
||||
cpf: onlyDigits(cpf),
|
||||
rg: onlyDigits(rg),
|
||||
nascimento,
|
||||
email,
|
||||
telefone: onlyDigits(telefone),
|
||||
endereco,
|
||||
cep: onlyDigits(cep),
|
||||
cidade,
|
||||
uf: uf.toUpperCase(),
|
||||
simboloId: simboloId,
|
||||
simboloTipo: tipo,
|
||||
admissaoData: admissaoData || undefined,
|
||||
desligamentoData: undefined,
|
||||
|
||||
// Dados Pessoais Adicionais
|
||||
nomePai: nomePai || undefined,
|
||||
nomeMae: nomeMae || undefined,
|
||||
naturalidade: naturalidade || undefined,
|
||||
naturalidadeUF: naturalidadeUF ? naturalidadeUF.toUpperCase() : undefined,
|
||||
sexo: sexo || undefined,
|
||||
estadoCivil: estadoCivil || undefined,
|
||||
nacionalidade: nacionalidade || undefined,
|
||||
|
||||
// Documentos Pessoais
|
||||
rgOrgaoExpedidor: rgOrgaoExpedidor || undefined,
|
||||
rgDataEmissao: rgDataEmissao || undefined,
|
||||
carteiraProfissionalNumero: carteiraProfissionalNumero || undefined,
|
||||
carteiraProfissionalSerie: carteiraProfissionalSerie || undefined,
|
||||
carteiraProfissionalDataEmissao: carteiraProfissionalDataEmissao || undefined,
|
||||
reservistaNumero: reservistaNumero || undefined,
|
||||
reservistaSerie: reservistaSerie || undefined,
|
||||
tituloEleitorNumero: tituloEleitorNumero || undefined,
|
||||
tituloEleitorZona: tituloEleitorZona || undefined,
|
||||
tituloEleitorSecao: tituloEleitorSecao || undefined,
|
||||
pisNumero: pisNumero || undefined,
|
||||
|
||||
// Formação e Saúde
|
||||
grauInstrucao: grauInstrucao || undefined,
|
||||
formacao: formacao || undefined,
|
||||
formacaoRegistro: formacaoRegistro || undefined,
|
||||
grupoSanguineo: grupoSanguineo || undefined,
|
||||
fatorRH: fatorRH || undefined,
|
||||
|
||||
// Cargo e Vínculo
|
||||
descricaoCargo: descricaoCargo || undefined,
|
||||
regimeTrabalho: regimeTrabalho,
|
||||
nomeacaoPortaria: nomeacaoPortaria || undefined,
|
||||
nomeacaoData: nomeacaoData || undefined,
|
||||
nomeacaoDOE: nomeacaoDOE || undefined,
|
||||
pertenceOrgaoPublico: pertenceOrgaoPublico || undefined,
|
||||
orgaoOrigem: orgaoOrigem || undefined,
|
||||
aposentado: aposentado || undefined,
|
||||
|
||||
// Dados Bancários
|
||||
contaBradescoNumero: contaBradescoNumero || undefined,
|
||||
contaBradescoDV: contaBradescoDV || undefined,
|
||||
contaBradescoAgencia: contaBradescoAgencia || undefined,
|
||||
|
||||
// Documentos
|
||||
...Object.fromEntries(
|
||||
Object.entries(documentosStorage).map(([key, value]) => [key, value])
|
||||
),
|
||||
// Dependentes (opcional)
|
||||
dependentes: dependentes.length
|
||||
? dependentes.map((d) => ({
|
||||
parentesco: d.parentesco as 'outro' | 'filho' | 'filha' | 'conjuge',
|
||||
nome: d.nome,
|
||||
cpf: d.cpf,
|
||||
nascimento: d.nascimento,
|
||||
documentoId: d.documentoId,
|
||||
salarioFamilia: !!d.salarioFamilia,
|
||||
impostoRenda: !!d.impostoRenda
|
||||
}))
|
||||
: undefined
|
||||
};
|
||||
|
||||
const novoFuncionarioId = await client.mutation(api.funcionarios.create, payload);
|
||||
|
||||
// Salvar cursos, se houver
|
||||
for (const curso of cursos) {
|
||||
let certificadoId = curso.certificadoId;
|
||||
// Se houver arquivo para upload, fazer o upload
|
||||
if (cursoAtual.arquivo && curso.id === cursos[cursos.length - 1].id) {
|
||||
try {
|
||||
certificadoId = await uploadCertificado(cursoAtual.arquivo);
|
||||
} catch (err) {
|
||||
console.error('Erro ao fazer upload do certificado:', err);
|
||||
}
|
||||
}
|
||||
|
||||
await client.mutation(api.cursos.criar, {
|
||||
funcionarioId: novoFuncionarioId,
|
||||
descricao: curso.descricao,
|
||||
data: curso.data,
|
||||
certificadoId: certificadoId
|
||||
});
|
||||
}
|
||||
|
||||
notice = { kind: 'success', text: 'Funcionário cadastrado com sucesso!' };
|
||||
setTimeout(() => goto(resolve('/recursos-humanos/funcionarios')), 600);
|
||||
} catch (e) {
|
||||
if (e instanceof Error) {
|
||||
const msg = e?.message || String(e);
|
||||
if (/CPF j[aá] cadastrado/i.test(msg)) {
|
||||
notice = { kind: 'error', text: 'CPF já cadastrado.' };
|
||||
} else if (/Matr[ií]cula j[aá] cadastrada/i.test(msg)) {
|
||||
notice = { kind: 'error', text: 'Matrícula já cadastrada.' };
|
||||
} else {
|
||||
notice = { kind: 'error', text: 'Erro ao cadastrar funcionário.' };
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
loading = false;
|
||||
}
|
||||
}
|
||||
|
||||
$effect(() => {
|
||||
loadSimbolos();
|
||||
});
|
||||
</script>
|
||||
|
||||
<main class="container mx-auto max-w-7xl px-4 py-4">
|
||||
<!-- Breadcrumb -->
|
||||
<div class="breadcrumbs mb-4 text-sm">
|
||||
<ul>
|
||||
<li><a href="/recursos-humanos" class="text-primary hover:underline">Recursos Humanos</a></li>
|
||||
<li>
|
||||
<a href="/recursos-humanos/funcionarios" class="text-primary hover:underline"
|
||||
<a href={resolve('/recursos-humanos')} class="text-primary hover:underline"
|
||||
>Recursos Humanos</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a href={resolve('/recursos-humanos/funcionarios')} class="text-primary hover:underline"
|
||||
>Funcionários</a
|
||||
>
|
||||
</li>
|
||||
@@ -575,7 +759,7 @@
|
||||
bind:value={naturalidadeUF}
|
||||
>
|
||||
<option value="">Selecione...</option>
|
||||
{#each UFS_BRASIL as ufOption}
|
||||
{#each UFS_BRASIL as ufOption (ufOption)}
|
||||
<option value={ufOption}>{ufOption}</option>
|
||||
{/each}
|
||||
</select>
|
||||
@@ -588,7 +772,7 @@
|
||||
</label>
|
||||
<select id="sexo" class="select select-bordered w-full" bind:value={sexo}>
|
||||
<option value="">Selecione...</option>
|
||||
{#each SEXO_OPTIONS as option}
|
||||
{#each SEXO_OPTIONS as option (option.value)}
|
||||
<option value={option.value}>{option.label}</option>
|
||||
{/each}
|
||||
</select>
|
||||
@@ -601,7 +785,7 @@
|
||||
</label>
|
||||
<select id="estadoCivil" class="select select-bordered w-full" bind:value={estadoCivil}>
|
||||
<option value="">Selecione...</option>
|
||||
{#each ESTADO_CIVIL_OPTIONS as option}
|
||||
{#each ESTADO_CIVIL_OPTIONS as option (option.value)}
|
||||
<option value={option.value}>{option.label}</option>
|
||||
{/each}
|
||||
</select>
|
||||
@@ -802,7 +986,7 @@
|
||||
bind:value={grauInstrucao}
|
||||
>
|
||||
<option value="">Selecione...</option>
|
||||
{#each GRAU_INSTRUCAO_OPTIONS as option}
|
||||
{#each GRAU_INSTRUCAO_OPTIONS as option (option.value)}
|
||||
<option value={option.value}>{option.label}</option>
|
||||
{/each}
|
||||
</select>
|
||||
@@ -847,7 +1031,7 @@
|
||||
bind:value={grupoSanguineo}
|
||||
>
|
||||
<option value="">Selecione...</option>
|
||||
{#each GRUPO_SANGUINEO_OPTIONS as option}
|
||||
{#each GRUPO_SANGUINEO_OPTIONS as option (option.value)}
|
||||
<option value={option.value}>{option.label}</option>
|
||||
{/each}
|
||||
</select>
|
||||
@@ -860,7 +1044,7 @@
|
||||
</label>
|
||||
<select id="fatorRH" class="select select-bordered w-full" bind:value={fatorRH}>
|
||||
<option value="">Selecione...</option>
|
||||
{#each FATOR_RH_OPTIONS as option}
|
||||
{#each FATOR_RH_OPTIONS as option (option.value)}
|
||||
<option value={option.value}>{option.label}</option>
|
||||
{/each}
|
||||
</select>
|
||||
@@ -898,7 +1082,7 @@
|
||||
{#if cursos.length > 0}
|
||||
<div class="space-y-2">
|
||||
<h3 class="text-sm font-semibold">Cursos adicionados ({cursos.length}/7)</h3>
|
||||
{#each cursos as curso}
|
||||
{#each cursos as curso (curso.id)}
|
||||
<div class="bg-base-200 flex items-center gap-3 rounded-lg p-3">
|
||||
<div class="flex-1">
|
||||
<p class="text-sm font-semibold">{curso.descricao}</p>
|
||||
@@ -906,7 +1090,7 @@
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-sm btn-error"
|
||||
class="btn btn-sm btn-error btn-square"
|
||||
aria-label="Remover curso"
|
||||
onclick={() => removerCurso(curso.id)}
|
||||
>
|
||||
@@ -1095,7 +1279,7 @@
|
||||
</label>
|
||||
<select id="uf" class="select select-bordered w-full" bind:value={uf} required>
|
||||
<option value="">Selecione...</option>
|
||||
{#each UFS_BRASIL as ufOption}
|
||||
{#each UFS_BRASIL as ufOption (ufOption)}
|
||||
<option value={ufOption}>{ufOption}</option>
|
||||
{/each}
|
||||
</select>
|
||||
@@ -1176,7 +1360,7 @@
|
||||
{#if dependentes.length > 0}
|
||||
<div class="space-y-2">
|
||||
<h3 class="text-sm font-semibold">Dependentes adicionados ({dependentes.length}/10)</h3>
|
||||
{#each dependentes as dep}
|
||||
{#each dependentes as dep (dep.id)}
|
||||
<div class="bg-base-200 flex items-center gap-3 rounded-lg p-3">
|
||||
<div class="flex-1 text-sm">
|
||||
<p class="font-semibold">{dep.nome} — {dep.parentesco}</p>
|
||||
@@ -1204,7 +1388,7 @@
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-sm btn-error"
|
||||
class="btn btn-sm btn-error btn-square"
|
||||
aria-label="Remover dependente"
|
||||
onclick={() => removerDependente(dep.id)}
|
||||
>
|
||||
@@ -1427,7 +1611,7 @@
|
||||
required
|
||||
>
|
||||
<option value="">Selecione...</option>
|
||||
{#each simbolos.filter((s) => s.tipo === tipo) as s}
|
||||
{#each simbolos.filter((s) => s.tipo === tipo) as s (s._id)}
|
||||
<option value={s._id}>{s.nome} — {s.descricao}</option>
|
||||
{/each}
|
||||
</select>
|
||||
@@ -1530,7 +1714,7 @@
|
||||
required
|
||||
>
|
||||
<option value="">Selecione...</option>
|
||||
{#each REGIME_TRABALHO_OPTIONS as option}
|
||||
{#each REGIME_TRABALHO_OPTIONS as option (option.value)}
|
||||
<option value={option.value}>{option.label}</option>
|
||||
{/each}
|
||||
</select>
|
||||
@@ -1573,7 +1757,7 @@
|
||||
<span class="label-text font-medium">Se Aposentado</span>
|
||||
</label>
|
||||
<select id="aposentado" class="select select-bordered w-full" bind:value={aposentado}>
|
||||
{#each APOSENTADO_OPTIONS as option}
|
||||
{#each APOSENTADO_OPTIONS as option (option.value)}
|
||||
<option value={option.value}>{option.label}</option>
|
||||
{/each}
|
||||
</select>
|
||||
@@ -1677,11 +1861,11 @@
|
||||
Anexe os documentos necessários em formato PDF ou imagem (máximo 10MB cada)
|
||||
</p>
|
||||
|
||||
{#each categoriasDocumentos as categoria}
|
||||
{#each categoriasDocumentos as categoria (categoria)}
|
||||
<div class="space-y-3">
|
||||
<h3 class="text-primary text-lg font-semibold">{categoria}</h3>
|
||||
<div class="grid grid-cols-1 gap-4 md:grid-cols-2">
|
||||
{#each getDocumentosByCategoria(categoria) as doc}
|
||||
{#each getDocumentosByCategoria(categoria) as doc (doc.campo)}
|
||||
<FileUpload
|
||||
label={doc.nome}
|
||||
helpUrl={doc.helpUrl}
|
||||
@@ -1705,7 +1889,7 @@
|
||||
type="button"
|
||||
class="btn btn-ghost btn-lg"
|
||||
disabled={loading}
|
||||
onclick={() => goto('/recursos-humanos/funcionarios')}
|
||||
onclick={() => goto(resolve('/recursos-humanos/funcionarios'))}
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { v } from 'convex/values';
|
||||
import { Infer, v } from 'convex/values';
|
||||
import { query, mutation } from './_generated/server';
|
||||
import { internal } from './_generated/api';
|
||||
import { simboloTipo } from './schema';
|
||||
@@ -109,119 +109,124 @@ export const getCurrent = query({
|
||||
}
|
||||
});
|
||||
|
||||
export const create = mutation({
|
||||
args: {
|
||||
// Campos obrigatórios
|
||||
nome: v.string(),
|
||||
matricula: v.optional(v.string()),
|
||||
simboloId: v.id('simbolos'),
|
||||
nascimento: v.string(),
|
||||
rg: v.string(),
|
||||
cpf: v.string(),
|
||||
endereco: v.string(),
|
||||
cep: v.string(),
|
||||
cidade: v.string(),
|
||||
uf: v.string(),
|
||||
telefone: v.string(),
|
||||
email: v.string(),
|
||||
admissaoData: v.optional(v.string()),
|
||||
desligamentoData: v.optional(v.string()),
|
||||
simboloTipo: simboloTipo,
|
||||
const createArgs = v.object({
|
||||
// Campos obrigatórios
|
||||
nome: v.string(),
|
||||
matricula: v.optional(v.string()),
|
||||
simboloId: v.id('simbolos'),
|
||||
nascimento: v.string(),
|
||||
rg: v.string(),
|
||||
cpf: v.string(),
|
||||
endereco: v.string(),
|
||||
cep: v.string(),
|
||||
cidade: v.string(),
|
||||
uf: v.string(),
|
||||
telefone: v.string(),
|
||||
email: v.string(),
|
||||
admissaoData: v.optional(v.string()),
|
||||
desligamentoData: v.optional(v.string()),
|
||||
simboloTipo: simboloTipo,
|
||||
|
||||
// Dados Pessoais Adicionais
|
||||
nomePai: v.optional(v.string()),
|
||||
nomeMae: v.optional(v.string()),
|
||||
naturalidade: v.optional(v.string()),
|
||||
naturalidadeUF: v.optional(v.string()),
|
||||
sexo: sexoValidator,
|
||||
estadoCivil: estadoCivilValidator,
|
||||
nacionalidade: v.optional(v.string()),
|
||||
// Dados Pessoais Adicionais
|
||||
nomePai: v.optional(v.string()),
|
||||
nomeMae: v.optional(v.string()),
|
||||
naturalidade: v.optional(v.string()),
|
||||
naturalidadeUF: v.optional(v.string()),
|
||||
sexo: sexoValidator,
|
||||
estadoCivil: estadoCivilValidator,
|
||||
nacionalidade: v.optional(v.string()),
|
||||
|
||||
// Documentos Pessoais
|
||||
rgOrgaoExpedidor: v.optional(v.string()),
|
||||
rgDataEmissao: v.optional(v.string()),
|
||||
carteiraProfissionalNumero: v.optional(v.string()),
|
||||
carteiraProfissionalSerie: v.optional(v.string()),
|
||||
carteiraProfissionalDataEmissao: v.optional(v.string()),
|
||||
reservistaNumero: v.optional(v.string()),
|
||||
reservistaSerie: v.optional(v.string()),
|
||||
tituloEleitorNumero: v.optional(v.string()),
|
||||
tituloEleitorZona: v.optional(v.string()),
|
||||
tituloEleitorSecao: v.optional(v.string()),
|
||||
pisNumero: v.optional(v.string()),
|
||||
// Documentos Pessoais
|
||||
rgOrgaoExpedidor: v.optional(v.string()),
|
||||
rgDataEmissao: v.optional(v.string()),
|
||||
carteiraProfissionalNumero: v.optional(v.string()),
|
||||
carteiraProfissionalSerie: v.optional(v.string()),
|
||||
carteiraProfissionalDataEmissao: v.optional(v.string()),
|
||||
reservistaNumero: v.optional(v.string()),
|
||||
reservistaSerie: v.optional(v.string()),
|
||||
tituloEleitorNumero: v.optional(v.string()),
|
||||
tituloEleitorZona: v.optional(v.string()),
|
||||
tituloEleitorSecao: v.optional(v.string()),
|
||||
pisNumero: v.optional(v.string()),
|
||||
|
||||
// Formação e Saúde
|
||||
grauInstrucao: grauInstrucaoValidator,
|
||||
formacao: v.optional(v.string()),
|
||||
formacaoRegistro: v.optional(v.string()),
|
||||
grupoSanguineo: grupoSanguineoValidator,
|
||||
fatorRH: fatorRHValidator,
|
||||
// Formação e Saúde
|
||||
grauInstrucao: grauInstrucaoValidator,
|
||||
formacao: v.optional(v.string()),
|
||||
formacaoRegistro: v.optional(v.string()),
|
||||
grupoSanguineo: grupoSanguineoValidator,
|
||||
fatorRH: fatorRHValidator,
|
||||
|
||||
// Cargo e Vínculo
|
||||
descricaoCargo: v.optional(v.string()),
|
||||
nomeacaoPortaria: v.optional(v.string()),
|
||||
nomeacaoData: v.optional(v.string()),
|
||||
nomeacaoDOE: v.optional(v.string()),
|
||||
pertenceOrgaoPublico: v.optional(v.boolean()),
|
||||
orgaoOrigem: v.optional(v.string()),
|
||||
aposentado: aposentadoValidator,
|
||||
// Cargo e Vínculo
|
||||
descricaoCargo: v.optional(v.string()),
|
||||
nomeacaoPortaria: v.optional(v.string()),
|
||||
nomeacaoData: v.optional(v.string()),
|
||||
nomeacaoDOE: v.optional(v.string()),
|
||||
pertenceOrgaoPublico: v.optional(v.boolean()),
|
||||
orgaoOrigem: v.optional(v.string()),
|
||||
aposentado: aposentadoValidator,
|
||||
regimeTrabalho: regimeTrabalhoValidator,
|
||||
|
||||
// Dados Bancários
|
||||
contaBradescoNumero: v.optional(v.string()),
|
||||
contaBradescoDV: v.optional(v.string()),
|
||||
contaBradescoAgencia: v.optional(v.string()),
|
||||
// Dados Bancários
|
||||
contaBradescoNumero: v.optional(v.string()),
|
||||
contaBradescoDV: v.optional(v.string()),
|
||||
contaBradescoAgencia: v.optional(v.string()),
|
||||
|
||||
// Documentos Anexos (Storage IDs)
|
||||
certidaoAntecedentesPF: v.optional(v.id('_storage')),
|
||||
certidaoAntecedentesJFPE: v.optional(v.id('_storage')),
|
||||
certidaoAntecedentesSDS: v.optional(v.id('_storage')),
|
||||
certidaoAntecedentesTJPE: v.optional(v.id('_storage')),
|
||||
certidaoImprobidade: v.optional(v.id('_storage')),
|
||||
rgFrente: v.optional(v.id('_storage')),
|
||||
rgVerso: v.optional(v.id('_storage')),
|
||||
cpfFrente: v.optional(v.id('_storage')),
|
||||
cpfVerso: v.optional(v.id('_storage')),
|
||||
situacaoCadastralCPF: v.optional(v.id('_storage')),
|
||||
tituloEleitorFrente: v.optional(v.id('_storage')),
|
||||
tituloEleitorVerso: v.optional(v.id('_storage')),
|
||||
comprovanteVotacao: v.optional(v.id('_storage')),
|
||||
carteiraProfissionalFrente: v.optional(v.id('_storage')),
|
||||
carteiraProfissionalVerso: v.optional(v.id('_storage')),
|
||||
comprovantePIS: v.optional(v.id('_storage')),
|
||||
certidaoRegistroCivil: v.optional(v.id('_storage')),
|
||||
certidaoNascimentoDependentes: v.optional(v.id('_storage')),
|
||||
cpfDependentes: v.optional(v.id('_storage')),
|
||||
reservistaDoc: v.optional(v.id('_storage')),
|
||||
comprovanteEscolaridade: v.optional(v.id('_storage')),
|
||||
comprovanteResidencia: v.optional(v.id('_storage')),
|
||||
comprovanteContaBradesco: v.optional(v.id('_storage')),
|
||||
// Documentos Anexos (Storage IDs)
|
||||
certidaoAntecedentesPF: v.optional(v.id('_storage')),
|
||||
certidaoAntecedentesJFPE: v.optional(v.id('_storage')),
|
||||
certidaoAntecedentesSDS: v.optional(v.id('_storage')),
|
||||
certidaoAntecedentesTJPE: v.optional(v.id('_storage')),
|
||||
certidaoImprobidade: v.optional(v.id('_storage')),
|
||||
rgFrente: v.optional(v.id('_storage')),
|
||||
rgVerso: v.optional(v.id('_storage')),
|
||||
cpfFrente: v.optional(v.id('_storage')),
|
||||
cpfVerso: v.optional(v.id('_storage')),
|
||||
situacaoCadastralCPF: v.optional(v.id('_storage')),
|
||||
tituloEleitorFrente: v.optional(v.id('_storage')),
|
||||
tituloEleitorVerso: v.optional(v.id('_storage')),
|
||||
comprovanteVotacao: v.optional(v.id('_storage')),
|
||||
carteiraProfissionalFrente: v.optional(v.id('_storage')),
|
||||
carteiraProfissionalVerso: v.optional(v.id('_storage')),
|
||||
comprovantePIS: v.optional(v.id('_storage')),
|
||||
certidaoRegistroCivil: v.optional(v.id('_storage')),
|
||||
certidaoNascimentoDependentes: v.optional(v.id('_storage')),
|
||||
cpfDependentes: v.optional(v.id('_storage')),
|
||||
reservistaDoc: v.optional(v.id('_storage')),
|
||||
comprovanteEscolaridade: v.optional(v.id('_storage')),
|
||||
comprovanteResidencia: v.optional(v.id('_storage')),
|
||||
comprovanteContaBradesco: v.optional(v.id('_storage')),
|
||||
|
||||
// Declarações (Storage IDs)
|
||||
declaracaoAcumulacaoCargo: v.optional(v.id('_storage')),
|
||||
declaracaoDependentesIR: v.optional(v.id('_storage')),
|
||||
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')),
|
||||
salarioFamilia: v.optional(v.boolean()),
|
||||
impostoRenda: v.optional(v.boolean())
|
||||
})
|
||||
)
|
||||
// Declarações (Storage IDs)
|
||||
declaracaoAcumulacaoCargo: v.optional(v.id('_storage')),
|
||||
declaracaoDependentesIR: v.optional(v.id('_storage')),
|
||||
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')),
|
||||
salarioFamilia: v.optional(v.boolean()),
|
||||
impostoRenda: v.optional(v.boolean())
|
||||
})
|
||||
)
|
||||
},
|
||||
)
|
||||
});
|
||||
|
||||
export type CreateArgs = Infer<typeof createArgs>;
|
||||
|
||||
export const create = mutation({
|
||||
args: createArgs,
|
||||
returns: v.id('funcionarios'),
|
||||
handler: async (ctx, args) => {
|
||||
// Autorização: criar
|
||||
|
||||
Reference in New Issue
Block a user