espace-paie-odentas/components/staff/CreateStaffForm.tsx
odentas 956d655b7a feat: Gestion complète des utilisateurs staff avec filtres et tri
- Ajout de la création d'utilisateurs staff (STAFF et SUPER_STAFF)
- Email de notification avec lien d'activation (paie.odentas.fr)
- API de révocation/restauration des utilisateurs staff
- Sécurité: SUPER_STAFF ne peut pas être révoqué
- Sécurité: Seul SUPER_STAFF peut créer d'autres SUPER_STAFF
- Tableau des utilisateurs clients avec filtres (organisation, niveau, statut)
- Tri dynamique sur toutes les colonnes (prénom, email, organisation, niveau, date)
- Utilisation du client admin pour contourner les RLS
- Interface avec recherche et filtres avancés
2025-11-28 00:48:14 +01:00

145 lines
5 KiB
TypeScript

"use client";
import { useState } from "react";
import { useRouter } from "next/navigation";
interface CreateStaffFormProps {
isSuperStaff: boolean;
}
export default function CreateStaffForm({ isSuperStaff }: CreateStaffFormProps) {
const router = useRouter();
const [loading, setLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
const [success, setSuccess] = useState(false);
const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
setLoading(true);
setError(null);
setSuccess(false);
const formData = new FormData(e.currentTarget);
const email = formData.get("email") as string;
const firstName = formData.get("firstName") as string;
const isSuperStaff = formData.get("isSuperStaff") === "on";
try {
const res = await fetch("/api/staff/users/create-staff", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ email, firstName, isSuperStaff }),
});
const data = await res.json();
if (!res.ok) {
throw new Error(data.error || data.message || "Erreur lors de la création");
}
setSuccess(true);
setTimeout(() => {
router.push("/staff/utilisateurs");
router.refresh();
}, 2000);
} catch (err: any) {
setError(err.message || "Erreur lors de la création de l'utilisateur staff");
} finally {
setLoading(false);
}
};
return (
<div className="rounded-2xl border bg-white p-6">
<h2 className="text-lg font-semibold mb-4">Créer un utilisateur staff</h2>
{error && (
<div className="mb-4 p-3 rounded-lg bg-red-50 border border-red-200 text-red-800 text-sm">
{error}
</div>
)}
{success && (
<div className="mb-4 p-3 rounded-lg bg-green-50 border border-green-200 text-green-800 text-sm">
Utilisateur staff créé avec succès ! Un email d&apos;activation a é envoyé. Redirection...
</div>
)}
<form onSubmit={handleSubmit} className="space-y-4">
<div>
<label htmlFor="email" className="block text-sm font-medium text-slate-700 mb-1">
Email *
</label>
<input
type="email"
id="email"
name="email"
required
disabled={loading || success}
className="w-full px-3 py-2 border border-slate-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-500 disabled:bg-slate-100"
placeholder="utilisateur@odentas.fr"
/>
</div>
<div>
<label htmlFor="firstName" className="block text-sm font-medium text-slate-700 mb-1">
Prénom
</label>
<input
type="text"
id="firstName"
name="firstName"
disabled={loading || success}
className="w-full px-3 py-2 border border-slate-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-500 disabled:bg-slate-100"
placeholder="Jean"
/>
</div>
{isSuperStaff && (
<div className="flex items-center gap-2">
<input
type="checkbox"
id="isSuperStaff"
name="isSuperStaff"
disabled={loading || success}
className="w-4 h-4 text-purple-600 border-slate-300 rounded focus:ring-purple-500"
/>
<label htmlFor="isSuperStaff" className="text-sm font-medium text-slate-700">
Super Staff (accès étendu)
</label>
</div>
)}
<div className="bg-slate-50 p-4 rounded-lg text-sm text-slate-600">
<p className="font-medium mb-2">Informations importantes :</p>
<ul className="list-disc list-inside space-y-1">
<li>L&apos;utilisateur recevra un email avec un lien d&apos;activation</li>
<li>Le lien est valable pendant 7 jours</li>
<li>L&apos;utilisateur aura un accès complet en tant que staff</li>
<li>Il pourra gérer tous les clients et toutes les données</li>
{isSuperStaff && <li>Le statut Super Staff donne des privilèges étendus (création d&apos;autres Super Staff, non-révocable)</li>}
</ul>
</div>
<div className="flex items-center gap-3">
<button
type="submit"
disabled={loading || success}
className="px-4 py-2 rounded-lg bg-indigo-600 text-white text-sm font-medium hover:bg-indigo-700 disabled:opacity-50 disabled:cursor-not-allowed"
>
{loading ? "Création en cours..." : "Créer l'utilisateur staff"}
</button>
<button
type="button"
onClick={() => router.back()}
disabled={loading}
className="px-4 py-2 rounded-lg border border-slate-300 text-slate-700 text-sm font-medium hover:bg-slate-50 disabled:opacity-50"
>
Annuler
</button>
</div>
</form>
</div>
);
}