feat: enhance user management with matricula retrieval and validation

- Updated user-related queries and mutations to retrieve the matricula from associated funcionario records, improving data accuracy.
- Refactored user creation and listing functionalities to ensure matricula is correctly handled and displayed.
- Enhanced error handling and validation for user operations, ensuring a more robust user management experience.
- Improved the overall structure of user-related code for better maintainability and clarity.
This commit is contained in:
2025-11-04 14:37:28 -03:00
parent d0692c3608
commit fbec5c46c2
10 changed files with 1250 additions and 587 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -22,7 +22,6 @@
});
// Estados do formulário
let matricula = $state("");
let nome = $state("");
let email = $state("");
let roleId = $state("");
@@ -30,7 +29,9 @@
let senhaInicial = $state("");
let confirmarSenha = $state("");
let processando = $state(false);
let mensagem = $state<{ tipo: "success" | "error"; texto: string } | null>(null);
let mensagem = $state<{ tipo: "success" | "error"; texto: string } | null>(
null,
);
function mostrarMensagem(tipo: "success" | "error", texto: string) {
mensagem = { tipo, texto };
@@ -43,8 +44,7 @@
e.preventDefault();
// Validações
const matriculaStr = String(matricula).trim();
if (!matriculaStr || !nome.trim() || !email.trim() || !roleId || !senhaInicial) {
if (!nome.trim() || !email.trim() || !roleId || !senhaInicial) {
mostrarMensagem("error", "Preencha todos os campos obrigatórios");
return;
}
@@ -63,11 +63,12 @@
try {
const resultado = await client.mutation(api.usuarios.criar, {
matricula: matriculaStr,
nome: nome.trim(),
email: email.trim(),
roleId: roleId as Id<"roles">,
funcionarioId: funcionarioId ? (funcionarioId as Id<"funcionarios">) : undefined,
funcionarioId: funcionarioId
? (funcionarioId as Id<"funcionarios">)
: undefined,
senhaInicial: senhaInicial,
});
@@ -75,7 +76,7 @@
if (senhaGerada) {
mostrarMensagem(
"success",
`Usuário criado! SENHA TEMPORÁRIA: ${senhaGerada} - Anote esta senha, ela não será exibida novamente!`
`Usuário criado! SENHA TEMPORÁRIA: ${senhaGerada} - Anote esta senha, ela não será exibida novamente!`,
);
setTimeout(() => {
goto("/ti/usuarios");
@@ -102,17 +103,19 @@
// Auto-completar ao selecionar funcionário
$effect(() => {
if (funcionarioId && funcionarios?.data) {
const funcSelecionado = funcionarios.data.find((f: any) => f._id === funcionarioId);
const funcSelecionado = funcionarios.data.find(
(f: any) => f._id === funcionarioId,
);
if (funcSelecionado) {
email = funcSelecionado.email || email;
nome = funcSelecionado.nome || nome;
matricula = funcSelecionado.matricula || matricula;
}
}
});
function gerarSenhaAleatoria() {
const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789@#$!";
const chars =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789@#$!";
let senha = "";
for (let i = 0; i < 12; i++) {
senha += chars.charAt(Math.floor(Math.random() * chars.length));
@@ -154,8 +157,12 @@
</svg>
</div>
<div>
<h1 class="text-3xl font-bold text-base-content">Criar Novo Usuário</h1>
<p class="text-base-content/60 mt-1">Cadastre um novo usuário no sistema</p>
<h1 class="text-3xl font-bold text-base-content">
Criar Novo Usuário
</h1>
<p class="text-base-content/60 mt-1">
Cadastre um novo usuário no sistema
</p>
</div>
</div>
<a href="/ti/usuarios" class="btn btn-outline btn-primary gap-2">
@@ -248,7 +255,9 @@
<!-- Funcionário (primeiro) -->
<div class="form-control md:col-span-2">
<label class="label" for="funcionario">
<span class="label-text font-semibold">Vincular Funcionário (Opcional)</span>
<span class="label-text font-semibold"
>Vincular Funcionário (Opcional)</span
>
</label>
<select
id="funcionario"
@@ -256,34 +265,24 @@
bind:value={funcionarioId}
disabled={processando || !funcionarios?.data}
>
<option value="">Selecione um funcionário para auto-completar dados</option>
<option value=""
>Selecione um funcionário para auto-completar dados</option
>
{#if funcionarios?.data}
{#each funcionarios.data as func}
<option value={func._id}>{func.nome} - Mat: {func.matricula}</option>
<option value={func._id}
>{func.nome} - Mat: {func.matricula}</option
>
{/each}
{/if}
</select>
<div class="label">
<span class="label-text-alt">Ao selecionar, os campos serão preenchidos automaticamente</span>
<span class="label-text-alt"
>Ao selecionar, os campos serão preenchidos automaticamente</span
>
</div>
</div>
<!-- Matrícula -->
<div class="form-control">
<label class="label" for="matricula">
<span class="label-text font-semibold">Matrícula *</span>
</label>
<input
id="matricula"
type="number"
placeholder="Ex: 12345"
class="input input-bordered"
bind:value={matricula}
required
disabled={processando}
/>
</div>
<!-- Nome -->
<div class="form-control">
<label class="label" for="nome">
@@ -301,7 +300,7 @@
</div>
<!-- Email -->
<div class="form-control md:col-span-2">
<div class="form-control">
<label class="label" for="email">
<span class="label-text font-semibold">E-mail *</span>
</label>
@@ -341,7 +340,9 @@
</select>
{#if !roles?.data || !Array.isArray(roles.data)}
<div class="label">
<span class="label-text-alt text-warning">Carregando perfis disponíveis...</span>
<span class="label-text-alt text-warning"
>Carregando perfis disponíveis...</span
>
</div>
{/if}
</div>
@@ -446,7 +447,9 @@
<div class="flex-1">
<h3 class="font-bold">Senha Gerada:</h3>
<div class="flex items-center gap-2 mt-2">
<code class="bg-base-300 px-3 py-2 rounded text-lg font-mono select-all">
<code
class="bg-base-300 px-3 py-2 rounded text-lg font-mono select-all"
>
{senhaGerada}
</code>
<button
@@ -473,8 +476,8 @@
</button>
</div>
<p class="text-sm mt-2">
⚠️ <strong>IMPORTANTE:</strong> Anote esta senha! Você precisará repassá-la
manualmente ao usuário até que o SMTP seja configurado.
⚠️ <strong>IMPORTANTE:</strong> Anote esta senha! Você precisará
repassá-la manualmente ao usuário até que o SMTP seja configurado.
</p>
</div>
</div>
@@ -500,18 +503,27 @@
<h3 class="font-bold">Informações Importantes</h3>
<ul class="text-sm list-disc list-inside mt-2 space-y-1">
<li>O usuário deverá alterar a senha no primeiro acesso</li>
<li>As credenciais devem ser repassadas manualmente (por enquanto)</li>
<li>
Configure o SMTP em <a href="/ti/configuracoes-email" class="link"
>Configurações de Email</a
As credenciais devem ser repassadas manualmente (por enquanto)
</li>
<li>
Configure o SMTP em <a
href="/ti/configuracoes-email"
class="link">Configurações de Email</a
> para envio automático
</li>
</ul>
</div>
</div>
<div class="card-actions justify-end mt-8 pt-6 border-t border-base-300">
<a href="/ti/usuarios" class="btn btn-ghost gap-2" class:btn-disabled={processando}>
<div
class="card-actions justify-end mt-8 pt-6 border-t border-base-300"
>
<a
href="/ti/usuarios"
class="btn btn-ghost gap-2"
class:btn-disabled={processando}
>
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-5 w-5"
@@ -528,7 +540,11 @@
</svg>
Cancelar
</a>
<button type="submit" class="btn btn-primary gap-2" disabled={processando}>
<button
type="submit"
class="btn btn-primary gap-2"
disabled={processando}
>
{#if processando}
<span class="loading loading-spinner loading-sm"></span>
Criando Usuário...
@@ -556,4 +572,3 @@
</div>
</div>
</ProtectedRoute>