import { useState } from "react"; import { trpc } from "@/lib/trpc"; import DashboardLayout from "@/components/DashboardLayout"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from "@/components/ui/table"; import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, } from "@/components/ui/dialog"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select"; import { Badge } from "@/components/ui/badge"; import { toast } from "sonner"; import { Pencil, Trash2, UserCheck, UserX, Search, Plus, KeyRound } from "lucide-react"; export default function AdminUsers() { const [searchTerm, setSearchTerm] = useState(""); const [filterRole, setFilterRole] = useState("all"); const [filterStatus, setFilterStatus] = useState("all"); const [createDialogOpen, setCreateDialogOpen] = useState(false); const [editDialogOpen, setEditDialogOpen] = useState(false); const [deleteDialogOpen, setDeleteDialogOpen] = useState(false); const [resetPasswordDialogOpen, setResetPasswordDialogOpen] = useState(false); const [selectedUser, setSelectedUser] = useState(null); const [createForm, setCreateForm] = useState({ openId: "", name: "", email: "", username: "", password: "", role: "user" as "user" | "admin" | "formateur" | "super_formateur", formateurId: undefined as number | undefined, }); const [editForm, setEditForm] = useState({ name: "", email: "", username: "", password: "", role: "user" as "user" | "admin" | "formateur" | "super_formateur", formateurId: undefined as number | undefined, }); const { data: usersData, refetch } = trpc.users.listWithFormateurs.useQuery(); const users = usersData?.users || []; const formateurs = usersData?.formateurs || []; const createMutation = trpc.users.create.useMutation({ onSuccess: () => { toast.success("Utilisateur créé avec succès"); refetch(); setCreateDialogOpen(false); setCreateForm({ openId: "", name: "", email: "", username: "", password: "", role: "user", formateurId: undefined, }); }, onError: (error) => { toast.error(`Erreur : ${error.message}`); }, }); const updateMutation = trpc.users.update.useMutation({ onSuccess: () => { toast.success("Utilisateur modifié avec succès"); refetch(); setEditDialogOpen(false); }, onError: (error) => { toast.error(`Erreur : ${error.message}`); }, }); const toggleStatusMutation = trpc.users.toggleStatus.useMutation({ onSuccess: () => { toast.success("Statut modifié avec succès"); refetch(); }, onError: (error) => { toast.error(`Erreur : ${error.message}`); }, }); const deleteMutation = trpc.users.delete.useMutation({ onSuccess: () => { toast.success("Utilisateur supprimé avec succès"); refetch(); setDeleteDialogOpen(false); }, onError: (error) => { toast.error(`Erreur : ${error.message}`); }, }); const resetPasswordMutation = trpc.users.requestPasswordReset.useMutation({ onSuccess: () => { toast.success("Email de réinitialisation envoyé avec succès"); setResetPasswordDialogOpen(false); }, onError: (error) => { toast.error(`Erreur : ${error.message}`); }, }); const handleCreate = () => { setCreateDialogOpen(true); }; const handleSaveCreate = () => { if (!createForm.openId) { toast.error("L'identifiant OpenID est obligatoire"); return; } createMutation.mutate({ openId: createForm.openId, name: createForm.name || undefined, email: createForm.email || undefined, username: createForm.username || undefined, password: createForm.password || undefined, role: createForm.role, isActive: true, formateurId: createForm.formateurId, }); }; const handleEdit = (user: any) => { setSelectedUser(user); setEditForm({ name: user.name || "", email: user.email || "", username: user.username || "", password: "", // Toujours vide pour la sécurité role: user.role, formateurId: user.formateurId, }); setEditDialogOpen(true); }; const handleSaveEdit = () => { if (!selectedUser) return; // Ne pas envoyer username et password s'ils sont vides const updateData: any = { id: selectedUser.id, name: editForm.name || undefined, email: editForm.email || undefined, role: editForm.role, formateurId: editForm.formateurId, }; if (editForm.username) { updateData.username = editForm.username; } if (editForm.password) { updateData.password = editForm.password; } updateMutation.mutate(updateData); }; const handleToggleStatus = (user: any) => { toggleStatusMutation.mutate({ id: user.id, isActive: !user.isActive, }); }; const handleDelete = (user: any) => { setSelectedUser(user); setDeleteDialogOpen(true); }; const confirmDelete = () => { if (!selectedUser) return; deleteMutation.mutate({ id: selectedUser.id }); }; const handleResetPassword = (user: any) => { setSelectedUser(user); setResetPasswordDialogOpen(true); }; const confirmResetPassword = () => { if (!selectedUser) return; resetPasswordMutation.mutate({ id: selectedUser.id }); }; // Filtrage des utilisateurs const filteredUsers = users.filter((user) => { const matchesSearch = searchTerm === "" || user.name?.toLowerCase().includes(searchTerm.toLowerCase()) || user.email?.toLowerCase().includes(searchTerm.toLowerCase()); const matchesRole = filterRole === "all" || user.role === filterRole; const matchesStatus = filterStatus === "all" || (filterStatus === "active" && user.isActive) || (filterStatus === "inactive" && !user.isActive); return matchesSearch && matchesRole && matchesStatus; }); const formatDate = (date: Date | string | null) => { if (!date) return "N/A"; const d = new Date(date); return d.toLocaleDateString("fr-FR", { day: "2-digit", month: "2-digit", year: "numeric", }); }; return (

Gestion des Utilisateurs

Gérez les comptes utilisateurs de l'application

{/* Filtres */}
setSearchTerm(e.target.value)} className="pl-8" />
{/* Formateurs sans compte */} {formateurs.filter(f => !f.hasAccount).length > 0 && (

Formateurs sans compte utilisateur ({formateurs.filter(f => !f.hasAccount).length})

Ces formateurs existent dans le système mais n'ont pas de compte utilisateur. Créez un compte pour leur permettre de se connecter.

{formateurs.filter(f => !f.hasAccount).map((formateur) => (

{formateur.nom}

{formateur.email || "Pas d'email"}

))}
)} {/* Compteur de résultats */}

{filteredUsers.length} utilisateur(s) trouvé(s)

{/* Tableau des utilisateurs */}
ID Nom Email Identifiant Rôle Statut Dernière connexion Créé le Actions {filteredUsers.length === 0 ? ( Aucun utilisateur trouvé ) : ( filteredUsers.map((user, index) => ( {user.id} {user.name || "N/A"} {user.email || "N/A"} {user.username || "N/A"} {user.role === "admin" ? "Administrateur" : user.role === "formateur" ? "Formateur" : user.role === "super_formateur" ? "Super Formateur" : "Utilisateur"} {user.isActive ? "Actif" : "Inactif"} {formatDate(user.lastSignedIn)} {formatDate(user.createdAt)}
)) )}
{/* Dialog de création */} Créer un nouvel utilisateur Ajoutez un nouvel utilisateur à l'application
setCreateForm({ ...createForm, openId: e.target.value })} placeholder="Identifiant unique de l'utilisateur" />
setCreateForm({ ...createForm, name: e.target.value })} placeholder="Nom de l'utilisateur" />
setCreateForm({ ...createForm, email: e.target.value })} placeholder="email@exemple.com" />
setCreateForm({ ...createForm, username: e.target.value })} placeholder="Identifiant unique pour la connexion" />
setCreateForm({ ...createForm, password: e.target.value })} placeholder="Minimum 6 caractères" />
{(createForm.role === "formateur" || createForm.role === "super_formateur") && (
)}
{/* Dialog de modification */} Modifier l'utilisateur {selectedUser?.username === "adminServFormation" ? "Seuls l'email et le mot de passe peuvent être modifiés pour cet utilisateur" : "Modifiez les informations de l'utilisateur"}
setEditForm({ ...editForm, name: e.target.value })} placeholder="Nom de l'utilisateur" disabled={selectedUser?.username === "adminServFormation"} className={selectedUser?.username === "adminServFormation" ? "bg-gray-100 cursor-not-allowed" : ""} />
setEditForm({ ...editForm, email: e.target.value })} placeholder="email@exemple.com" />
setEditForm({ ...editForm, username: e.target.value })} placeholder="Identifiant unique pour la connexion" disabled={selectedUser?.username === "adminServFormation"} className={selectedUser?.username === "adminServFormation" ? "bg-gray-100 cursor-not-allowed" : ""} /> {selectedUser?.username !== "adminServFormation" && (

Laissez vide pour ne pas modifier

)}
setEditForm({ ...editForm, password: e.target.value })} placeholder="Laissez vide pour ne pas modifier" />

Minimum 6 caractères si modifié

{(editForm.role === "formateur" || editForm.role === "super_formateur") && (
)}
{/* Dialog de réinitialisation de mot de passe */} Réinitialiser le mot de passe Êtes-vous sûr de vouloir envoyer un email de réinitialisation de mot de passe à{" "} {selectedUser?.name || selectedUser?.email} ?

ℹ️ Information :

  • Un email sera envoyé à : {selectedUser?.email}
  • Le lien de réinitialisation sera valide pendant 24 heures
  • Il ne pourra être utilisé qu'une seule fois
{/* Dialog de suppression */} Confirmer la suppression Êtes-vous sûr de vouloir supprimer l'utilisateur{" "} {selectedUser?.name || selectedUser?.email} ? Cette action est irréversible.
); }