Primeiro commit

This commit is contained in:
joao.herculano
2026-08-06 11:13:33 -03:00
commit 4e1ebe861c
110 changed files with 18052 additions and 0 deletions
+164
View File
@@ -0,0 +1,164 @@
import { createFileRoute, useNavigate } from "@tanstack/react-router";
import { useEffect, useState } from "react";
import { toast } from "sonner";
import { Boxes, Loader2, LogIn, UserPlus } from "lucide-react";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { criarConta, entrar, obterSessaoAtual, normalizarNome } from "@/lib/auth";
export const Route = createFileRoute("/auth")({
head: () => ({
meta: [
{ title: "Entrar | Coleta de Caixas" },
{
name: "description",
content:
"Acesse sua conta para registrar o início e o fim das coletas de caixas. Novas contas precisam de aprovação de um administrador.",
},
{ property: "og:title", content: "Entrar | Coleta de Caixas" },
{
property: "og:description",
content:
"Acesse sua conta para registrar o início e o fim das coletas de caixas. Novas contas precisam de aprovação de um administrador.",
},
{ property: "og:type", content: "website" },
{ name: "twitter:card", content: "summary" },
],
}),
component: AuthPage,
});
function AuthPage() {
const navigate = useNavigate();
const [modo, setModo] = useState<"entrar" | "criar">("entrar");
const [nome, setNome] = useState("");
const [senha, setSenha] = useState("");
const [carregando, setCarregando] = useState(false);
const [verificando, setVerificando] = useState(true);
useEffect(() => {
let cancelado = false;
void obterSessaoAtual().then((sessao) => {
if (cancelado) return;
if (sessao) void navigate({ to: "/coleta", replace: true });
else setVerificando(false);
});
return () => {
cancelado = true;
};
}, [navigate]);
async function handleSubmit(e: React.FormEvent) {
e.preventDefault();
const usuario = normalizarNome(nome);
if (usuario.length < 3 || senha.length < 6) {
toast.error("Informe um nome com pelo menos 3 caracteres e senha com 6 ou mais.");
return;
}
setCarregando(true);
try {
if (modo === "criar") {
const resultado = await criarConta({ data: { nome: usuario, senha } });
toast.success(
resultado.aprovado
? "Conta criada e liberada. Faça login."
: "Conta criada! Aguarde a liberação de um administrador.",
);
} else {
await entrar({ data: { nome: usuario, senha } });
void navigate({ to: "/coleta", replace: true });
}
} catch (error) {
console.error(error);
const msg = (error as { message?: string })?.message ?? "";
toast.error(
msg.includes("incorretos")
? "Nome de usuário ou senha incorretos."
: msg.includes("já existe")
? "Este nome de usuário já existe. Faça login."
: "Não foi possível concluir. Tente novamente.",
);
} finally {
setCarregando(false);
}
}
if (verificando) {
return (
<div className="flex min-h-screen items-center justify-center bg-background">
<Loader2 className="h-6 w-6 animate-spin text-primary" />
</div>
);
}
return (
<div className="flex min-h-screen items-center justify-center bg-background px-4 py-10">
<div className="w-full max-w-sm space-y-6 rounded-2xl border border-border bg-card p-6 shadow-soft">
<div className="space-y-2 text-center">
<div className="mx-auto flex h-12 w-12 items-center justify-center rounded-2xl bg-primary/10">
<Boxes className="h-6 w-6 text-primary" />
</div>
<h1 className="text-xl font-semibold text-foreground">Coleta de Caixas</h1>
<p className="text-sm text-muted-foreground">
{modo === "entrar"
? "Entre com seu nome de usuário e senha."
: "Crie sua conta — o acesso é liberado por um administrador."}
</p>
</div>
<form className="space-y-4" onSubmit={handleSubmit}>
<div className="space-y-2">
<Label htmlFor="nome">Nome de usuário</Label>
<Input
id="nome"
type="text"
autoComplete="username"
autoCapitalize="none"
value={nome}
onChange={(e) => setNome(e.target.value)}
placeholder="joao.silva"
className="h-12 rounded-xl"
/>
</div>
<div className="space-y-2">
<Label htmlFor="senha">Senha</Label>
<Input
id="senha"
type="password"
autoComplete={modo === "entrar" ? "current-password" : "new-password"}
value={senha}
onChange={(e) => setSenha(e.target.value)}
placeholder="Mínimo de 6 caracteres"
className="h-12 rounded-xl"
/>
</div>
<Button
type="submit"
className="h-12 w-full rounded-xl text-base font-semibold"
disabled={carregando}
>
{carregando ? (
<Loader2 className="h-5 w-5 animate-spin" />
) : modo === "entrar" ? (
<LogIn className="h-5 w-5" />
) : (
<UserPlus className="h-5 w-5" />
)}
{modo === "entrar" ? "Entrar" : "Criar conta"}
</Button>
</form>
<button
type="button"
className="w-full text-center text-sm text-muted-foreground underline-offset-4 hover:underline"
onClick={() => setModo(modo === "entrar" ? "criar" : "entrar")}
>
{modo === "entrar" ? "Não tenho conta — criar agora" : "Já tenho conta — entrar"}
</button>
</div>
</div>
);
}