185 lines
7.6 KiB
TypeScript
185 lines
7.6 KiB
TypeScript
import { trpc } from "@/lib/trpc";
|
||
import { getLoginUrl } from "@/const";
|
||
import { useState } from "react";
|
||
import { useLocation } from "wouter";
|
||
import { toast } from "sonner";
|
||
import { Eye, EyeOff, Lock, User, ArrowLeft, ExternalLink } from "lucide-react";
|
||
|
||
const FEHAP_LOGO = "/manus-storage/logoFEHAP_69ddd0ee.PNG";
|
||
const SANTINOVA_LOGO_TEXT = "Santinova Soft";
|
||
|
||
export default function LoginLocal() {
|
||
const [, navigate] = useLocation();
|
||
const [loginOrEmail, setLoginOrEmail] = useState("");
|
||
const [password, setPassword] = useState("");
|
||
const [showPassword, setShowPassword] = useState(false);
|
||
|
||
const loginMutation = trpc.auth.loginLocal.useMutation({
|
||
onSuccess: () => {
|
||
// Forcer un rechargement complet pour réinitialiser le contexte auth
|
||
window.location.href = "/";
|
||
},
|
||
onError: (err) => {
|
||
toast.error(err.message || "Identifiant ou mot de passe incorrect");
|
||
},
|
||
});
|
||
|
||
const handleSubmit = (e: React.FormEvent) => {
|
||
e.preventDefault();
|
||
if (!loginOrEmail || !password) {
|
||
toast.error("Veuillez renseigner votre identifiant et votre mot de passe");
|
||
return;
|
||
}
|
||
loginMutation.mutate({ email: loginOrEmail, password });
|
||
};
|
||
|
||
return (
|
||
<div className="min-h-screen flex bg-background">
|
||
{/* ── Colonne gauche : branding SONUM ── */}
|
||
<div className="hidden lg:flex flex-col justify-between w-1/2 bg-primary px-14 py-12">
|
||
<div>
|
||
<img
|
||
src={FEHAP_LOGO}
|
||
alt="FEHAP – Santé Social, Privé Solidaire"
|
||
className="h-16 object-contain bg-white rounded-xl px-3 py-2 shadow"
|
||
/>
|
||
</div>
|
||
<div className="text-white">
|
||
<h1 className="text-5xl font-bold mb-4" style={{ fontFamily: "'Playfair Display', serif" }}>
|
||
SONUM
|
||
</h1>
|
||
<p className="text-lg text-white/80 max-w-sm leading-relaxed">
|
||
Cartographie des Solutions Numériques des établissements FEHAP
|
||
</p>
|
||
</div>
|
||
<div className="text-white/40 text-xs">
|
||
© {new Date().getFullYear()} FEHAP — Tous droits réservés
|
||
</div>
|
||
</div>
|
||
|
||
{/* ── Colonne droite : formulaire ── */}
|
||
<div className="flex flex-col justify-between flex-1 px-8 py-12 lg:px-16">
|
||
{/* Logo FEHAP en haut */}
|
||
<div className="flex justify-center lg:justify-end">
|
||
<img
|
||
src={FEHAP_LOGO}
|
||
alt="FEHAP"
|
||
className="h-12 object-contain bg-white rounded-lg px-2 py-1 shadow-sm border border-border"
|
||
/>
|
||
</div>
|
||
|
||
{/* Formulaire centré */}
|
||
<div className="w-full max-w-sm mx-auto">
|
||
{/* Titre mobile */}
|
||
<div className="text-center mb-8 lg:hidden">
|
||
<h1 className="text-3xl font-bold text-primary" style={{ fontFamily: "'Playfair Display', serif" }}>
|
||
SONUM
|
||
</h1>
|
||
</div>
|
||
|
||
<h2 className="text-2xl font-semibold text-foreground mb-2">Connexion locale</h2>
|
||
<p className="text-sm text-muted-foreground mb-8">
|
||
Connectez-vous avec votre identifiant (login ou email) et votre mot de passe
|
||
</p>
|
||
|
||
<div className="bg-card rounded-2xl border border-border shadow-sm p-8">
|
||
<form onSubmit={handleSubmit} className="space-y-5">
|
||
{/* Login ou email */}
|
||
<div>
|
||
<label className="block text-sm font-medium text-foreground mb-1.5">
|
||
Identifiant ou email
|
||
</label>
|
||
<div className="relative">
|
||
<User size={16} className="absolute left-3.5 top-1/2 -translate-y-1/2 text-muted-foreground" />
|
||
<input
|
||
type="text"
|
||
value={loginOrEmail}
|
||
onChange={(e) => setLoginOrEmail(e.target.value)}
|
||
placeholder="jdupont ou prenom.nom@etablissement.fr"
|
||
autoComplete="username"
|
||
className="w-full pl-10 pr-4 py-2.5 text-sm bg-background border border-border rounded-lg focus:outline-none focus:ring-2 focus:ring-primary/30 focus:border-primary transition-all"
|
||
required
|
||
/>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Mot de passe */}
|
||
<div>
|
||
<label className="block text-sm font-medium text-foreground mb-1.5">
|
||
Mot de passe
|
||
</label>
|
||
<div className="relative">
|
||
<Lock size={16} className="absolute left-3.5 top-1/2 -translate-y-1/2 text-muted-foreground" />
|
||
<input
|
||
type={showPassword ? "text" : "password"}
|
||
value={password}
|
||
onChange={(e) => setPassword(e.target.value)}
|
||
placeholder="••••••••"
|
||
autoComplete="current-password"
|
||
className="w-full pl-10 pr-10 py-2.5 text-sm bg-background border border-border rounded-lg focus:outline-none focus:ring-2 focus:ring-primary/30 focus:border-primary transition-all"
|
||
required
|
||
/>
|
||
<button
|
||
type="button"
|
||
onClick={() => setShowPassword(!showPassword)}
|
||
className="absolute right-3 top-1/2 -translate-y-1/2 text-muted-foreground hover:text-foreground transition-colors"
|
||
>
|
||
{showPassword ? <EyeOff size={16} /> : <Eye size={16} />}
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Bouton connexion */}
|
||
<button
|
||
type="submit"
|
||
disabled={loginMutation.isPending}
|
||
className="w-full py-2.5 px-4 bg-primary text-white rounded-lg font-medium text-sm hover:bg-primary/90 transition-colors shadow-sm disabled:opacity-60 disabled:cursor-not-allowed flex items-center justify-center gap-2"
|
||
>
|
||
{loginMutation.isPending ? (
|
||
<>
|
||
<div className="w-4 h-4 border-2 border-white/30 border-t-white rounded-full animate-spin" />
|
||
Connexion en cours...
|
||
</>
|
||
) : (
|
||
"Se connecter"
|
||
)}
|
||
</button>
|
||
</form>
|
||
</div>
|
||
|
||
{/* Liens */}
|
||
<div className="mt-6 space-y-3 text-center">
|
||
<button
|
||
onClick={() => navigate("/login")}
|
||
className="flex items-center justify-center gap-2 text-sm text-muted-foreground hover:text-foreground transition-colors mx-auto"
|
||
>
|
||
<ArrowLeft size={14} />
|
||
Retour aux options de connexion
|
||
</button>
|
||
|
||
<div className="flex items-center gap-3">
|
||
<div className="flex-1 h-px bg-border" />
|
||
<span className="text-xs text-muted-foreground">ou</span>
|
||
<div className="flex-1 h-px bg-border" />
|
||
</div>
|
||
|
||
<a
|
||
href={getLoginUrl()}
|
||
className="flex items-center justify-center gap-2 text-sm text-primary hover:text-primary/80 font-medium transition-colors"
|
||
>
|
||
<ExternalLink size={14} />
|
||
Se connecter via l'espace adhérent FEHAP
|
||
</a>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Pied de page : powered by Santinova */}
|
||
<div className="flex justify-center lg:justify-end items-center gap-2 mt-8">
|
||
<span className="text-xs text-muted-foreground">powered by</span>
|
||
<span className="text-xs font-semibold text-foreground/70">{SANTINOVA_LOGO_TEXT}</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
);
|
||
}
|