frontend/app/routes/login.tsx
Nathan Lamy 938ed8a4df
Some checks failed
Deploy to Netlify / Deploy to Netlify (push) Failing after 1m10s
ui: add register page
2025-07-28 23:29:27 +02:00

108 lines
3.4 KiB
TypeScript

import type { Route } from "./+types/login";
import { Alert, AlertDescription } from "~/components/ui/alert";
import { AlertCircleIcon, LoaderCircle, LogIn, MailIcon } from "lucide-react";
import { Label } from "~/components/ui/label";
import { Input } from "~/components/ui/input";
import { Button } from "~/components/ui/button";
import { useState } from "react";
import AuthLayout from "~/layout";
import { requestLogin } from "~/lib/api";
import { useNavigate } from "react-router";
import { Turnstile } from "@marsidev/react-turnstile";
const siteKey = import.meta.env.VITE_TURNSTILE_SITE_KEY;
export function meta({}: Route.MetaArgs) {
return [
{ title: "Khollisé - Connexion" },
{ name: "description", content: "Connectez-vous à Khollisé" },
];
}
export default function Login() {
const navigate = useNavigate();
const [email, setEmail] = useState("");
const [token, setToken] = useState<string | null>(null);
const [error, setError] = useState<string | null>(null);
const [isLoading, setIsLoading] = useState(false);
const validateEmail = (email: string) => email.endsWith("@bginette.fr");
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
setError(null);
if (!validateEmail(email))
return setError("Seules les adresses email @bginette.fr sont autorisées");
if (!token)
return setError("Veuillez valider le captcha avant de continuer");
setIsLoading(true);
await requestLogin(email, token)
.then((data) => {
setIsLoading(false);
const url = `/verify?email=${encodeURIComponent(email)}`
// TODO: Magic link (wss connection token)
// &token=${
// data?.token
// }`;
navigate(url, {
replace: true,
});
})
.catch((err) => {
setIsLoading(false);
setError(err.message);
});
};
return (
<AuthLayout>
<form onSubmit={handleSubmit} className="space-y-4">
<div className="space-y-2">
<Label htmlFor="email">Email</Label>
<div className="relative">
<div className="absolute inset-y-0 left-0 flex items-center pl-3 pointer-events-none text-gray-500">
<MailIcon className="h-5 w-5" />
</div>
<Input
id="email"
type="email"
placeholder="prenom.nom@bginette.fr"
className="pl-10"
value={email}
onChange={(e) => setEmail(e.target.value)}
required
/>
</div>
<p className="text-xs text-muted-foreground">
Seules les adresses email{" "}
<span className="font-bold">@bginette.fr</span> sont acceptées.
</p>
</div>
{error && (
<Alert variant="destructive" className="pb-2">
<AlertCircleIcon className="h-4 w-4" />
<AlertDescription>{error}</AlertDescription>
</Alert>
)}
<Turnstile siteKey={siteKey} onSuccess={setToken} />
<Button type="submit" className="w-full" disabled={isLoading}>
{isLoading ? (
<>
<LoaderCircle className="h-4 w-4 animate-spin mr-2" />
Connexion en cours...
</>
) : (
<>
<LogIn className="h-4 w-4 mr-2" />
Se connecter
</>
)}
</Button>
</form>
</AuthLayout>
);
}