feat: enhance employee and symbol management with new features, improved UI components, and backend schema updates
This commit is contained in:
259
apps/web/src/routes/(dashboard)/solicitar-acesso/+page.svelte
Normal file
259
apps/web/src/routes/(dashboard)/solicitar-acesso/+page.svelte
Normal file
@@ -0,0 +1,259 @@
|
||||
<script lang="ts">
|
||||
import { goto } from "$app/navigation";
|
||||
import { useConvexClient } from "convex-svelte";
|
||||
import { api } from "@sgse-app/backend/convex/_generated/api";
|
||||
import { createForm } from "@tanstack/svelte-form";
|
||||
import z from "zod";
|
||||
|
||||
const convex = useConvexClient();
|
||||
|
||||
// Estado para mensagens
|
||||
let notice = $state<{ type: "success" | "error"; message: string } | null>(null);
|
||||
|
||||
// Schema de validação
|
||||
const formSchema = z.object({
|
||||
nome: z.string().min(3, "Nome deve ter no mínimo 3 caracteres"),
|
||||
matricula: z.string().min(1, "Matrícula é obrigatória"),
|
||||
email: z.string().email("E-mail inválido"),
|
||||
telefone: z.string().min(14, "Telefone inválido"),
|
||||
});
|
||||
|
||||
// Criar o formulário
|
||||
const form = createForm(() => ({
|
||||
defaultValues: {
|
||||
nome: "",
|
||||
matricula: "",
|
||||
email: "",
|
||||
telefone: "",
|
||||
},
|
||||
onSubmit: async ({ value }) => {
|
||||
try {
|
||||
notice = null;
|
||||
await convex.mutation(api.solicitacoesAcesso.create, {
|
||||
nome: value.nome,
|
||||
matricula: value.matricula,
|
||||
email: value.email,
|
||||
telefone: value.telefone,
|
||||
});
|
||||
notice = {
|
||||
type: "success",
|
||||
message: "Solicitação de acesso enviada com sucesso! Aguarde a análise da equipe de TI.",
|
||||
};
|
||||
// Limpar o formulário
|
||||
form.reset();
|
||||
// Redirecionar após 3 segundos
|
||||
setTimeout(() => {
|
||||
goto("/");
|
||||
}, 3000);
|
||||
} catch (error: any) {
|
||||
notice = {
|
||||
type: "error",
|
||||
message: error.message || "Erro ao enviar solicitação. Tente novamente.",
|
||||
};
|
||||
}
|
||||
},
|
||||
}));
|
||||
|
||||
// Máscaras
|
||||
function maskTelefone(value: string): string {
|
||||
const cleaned = value.replace(/\D/g, "");
|
||||
if (cleaned.length <= 10) {
|
||||
return cleaned
|
||||
.replace(/^(\d{2})(\d)/, "($1) $2")
|
||||
.replace(/(\d{4})(\d)/, "$1-$2");
|
||||
}
|
||||
return cleaned
|
||||
.replace(/^(\d{2})(\d)/, "($1) $2")
|
||||
.replace(/(\d{5})(\d)/, "$1-$2");
|
||||
}
|
||||
|
||||
function handleCancel() {
|
||||
goto("/");
|
||||
}
|
||||
</script>
|
||||
|
||||
<main class="container mx-auto px-4 py-4 max-w-4xl">
|
||||
<div class="mb-6">
|
||||
<h1 class="text-3xl font-bold text-primary mb-2">Solicitar Acesso ao SGSE</h1>
|
||||
<p class="text-base-content/70">
|
||||
Preencha o formulário abaixo para solicitar acesso ao Sistema de Gerenciamento da Secretaria de Esportes.
|
||||
Sua solicitação será analisada pela equipe de Tecnologia da Informação.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{#if notice}
|
||||
<div class="alert {notice.type === 'success' ? 'alert-success' : 'alert-error'} mb-6">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="stroke-current shrink-0 h-6 w-6"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
{#if notice.type === "success"}
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"
|
||||
/>
|
||||
{:else}
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z"
|
||||
/>
|
||||
{/if}
|
||||
</svg>
|
||||
<span>{notice.message}</span>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<div class="card bg-base-100 shadow-xl">
|
||||
<div class="card-body">
|
||||
<form
|
||||
onsubmit={(e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
form.handleSubmit();
|
||||
}}
|
||||
>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<!-- Nome -->
|
||||
<form.Field name="nome" validators={{ onChange: formSchema.shape.nome }}>
|
||||
{#snippet children(field)}
|
||||
<div class="form-control md:col-span-2">
|
||||
<label class="label" for="nome">
|
||||
<span class="label-text">Nome Completo *</span>
|
||||
</label>
|
||||
<input
|
||||
id="nome"
|
||||
type="text"
|
||||
placeholder="Digite seu nome completo"
|
||||
class="input input-bordered w-full"
|
||||
value={field.state.value}
|
||||
onblur={field.handleBlur}
|
||||
oninput={(e) => field.handleChange(e.currentTarget.value)}
|
||||
/>
|
||||
{#if field.state.meta.errors.length > 0}
|
||||
<span class="text-error text-sm mt-1">{field.state.meta.errors[0]}</span>
|
||||
{/if}
|
||||
</div>
|
||||
{/snippet}
|
||||
</form.Field>
|
||||
|
||||
<!-- Matrícula -->
|
||||
<form.Field name="matricula" validators={{ onChange: formSchema.shape.matricula }}>
|
||||
{#snippet children(field)}
|
||||
<div class="form-control">
|
||||
<label class="label" for="matricula">
|
||||
<span class="label-text">Matrícula *</span>
|
||||
</label>
|
||||
<input
|
||||
id="matricula"
|
||||
type="text"
|
||||
placeholder="Digite sua matrícula"
|
||||
class="input input-bordered w-full"
|
||||
value={field.state.value}
|
||||
onblur={field.handleBlur}
|
||||
oninput={(e) => field.handleChange(e.currentTarget.value)}
|
||||
/>
|
||||
{#if field.state.meta.errors.length > 0}
|
||||
<span class="text-error text-sm mt-1">{field.state.meta.errors[0]}</span>
|
||||
{/if}
|
||||
</div>
|
||||
{/snippet}
|
||||
</form.Field>
|
||||
|
||||
<!-- E-mail -->
|
||||
<form.Field name="email" validators={{ onChange: formSchema.shape.email }}>
|
||||
{#snippet children(field)}
|
||||
<div class="form-control">
|
||||
<label class="label" for="email">
|
||||
<span class="label-text">E-mail *</span>
|
||||
</label>
|
||||
<input
|
||||
id="email"
|
||||
type="email"
|
||||
placeholder="seu@email.com"
|
||||
class="input input-bordered w-full"
|
||||
value={field.state.value}
|
||||
onblur={field.handleBlur}
|
||||
oninput={(e) => field.handleChange(e.currentTarget.value)}
|
||||
/>
|
||||
{#if field.state.meta.errors.length > 0}
|
||||
<span class="text-error text-sm mt-1">{field.state.meta.errors[0]}</span>
|
||||
{/if}
|
||||
</div>
|
||||
{/snippet}
|
||||
</form.Field>
|
||||
|
||||
<!-- Telefone -->
|
||||
<form.Field name="telefone" validators={{ onChange: formSchema.shape.telefone }}>
|
||||
{#snippet children(field)}
|
||||
<div class="form-control md:col-span-2">
|
||||
<label class="label" for="telefone">
|
||||
<span class="label-text">Telefone *</span>
|
||||
</label>
|
||||
<input
|
||||
id="telefone"
|
||||
type="text"
|
||||
placeholder="(00) 00000-0000"
|
||||
class="input input-bordered w-full"
|
||||
value={field.state.value}
|
||||
onblur={field.handleBlur}
|
||||
oninput={(e) => {
|
||||
const masked = maskTelefone(e.currentTarget.value);
|
||||
e.currentTarget.value = masked;
|
||||
field.handleChange(masked);
|
||||
}}
|
||||
maxlength="15"
|
||||
/>
|
||||
{#if field.state.meta.errors.length > 0}
|
||||
<span class="text-error text-sm mt-1">{field.state.meta.errors[0]}</span>
|
||||
{/if}
|
||||
</div>
|
||||
{/snippet}
|
||||
</form.Field>
|
||||
</div>
|
||||
|
||||
<div class="card-actions justify-end mt-6 gap-2">
|
||||
<button type="button" class="btn btn-ghost" onclick={handleCancel}>
|
||||
Cancelar
|
||||
</button>
|
||||
<button type="submit" class="btn btn-primary">
|
||||
Solicitar Acesso
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="alert alert-info mt-6">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
class="stroke-current shrink-0 w-6 h-6"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
|
||||
></path>
|
||||
</svg>
|
||||
<div>
|
||||
<h3 class="font-bold">Informações Importantes</h3>
|
||||
<div class="text-sm">
|
||||
<ul class="list-disc list-inside mt-2">
|
||||
<li>Todos os campos marcados com * são obrigatórios</li>
|
||||
<li>Sua solicitação será analisada pela equipe de TI em até 48 horas úteis</li>
|
||||
<li>Você receberá um e-mail com o resultado da análise</li>
|
||||
<li>Em caso de dúvidas, entre em contato com o suporte técnico</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
Reference in New Issue
Block a user