260 lines
8.6 KiB
Svelte
260 lines
8.6 KiB
Svelte
<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>
|
|
|