Checkpoint: Ajout de la fonctionnalité de création d'utilisateurs : ajout de la fonction createUser dans db.ts, création de la procédure tRPC users.create, ajout du bouton "Ajouter un utilisateur" dans la page AdminUsers avec icône Plus, création du dialogue de création avec formulaire complet (OpenID, nom, email, rôle) et gestion des états de création avec validation et messages de succès/erreur

This commit is contained in:
Manus Sandbox
2025-11-17 16:10:16 -05:00
parent 8cf6a9f6c3
commit c9f6f8f068
4 changed files with 154 additions and 6 deletions

View File

@@ -28,15 +28,22 @@ import {
} from "@/components/ui/select";
import { Badge } from "@/components/ui/badge";
import { toast } from "sonner";
import { Pencil, Trash2, UserCheck, UserX, Search } from "lucide-react";
import { Pencil, Trash2, UserCheck, UserX, Search, Plus } from "lucide-react";
export default function AdminUsers() {
const [searchTerm, setSearchTerm] = useState("");
const [filterRole, setFilterRole] = useState<string>("all");
const [filterStatus, setFilterStatus] = useState<string>("all");
const [createDialogOpen, setCreateDialogOpen] = useState(false);
const [editDialogOpen, setEditDialogOpen] = useState(false);
const [deleteDialogOpen, setDeleteDialogOpen] = useState(false);
const [selectedUser, setSelectedUser] = useState<any>(null);
const [createForm, setCreateForm] = useState({
openId: "",
name: "",
email: "",
role: "user" as "user" | "admin",
});
const [editForm, setEditForm] = useState({
name: "",
email: "",
@@ -44,6 +51,24 @@ export default function AdminUsers() {
});
const { data: users = [], refetch } = trpc.users.list.useQuery();
const createMutation = trpc.users.create.useMutation({
onSuccess: () => {
toast.success("Utilisateur créé avec succès");
refetch();
setCreateDialogOpen(false);
setCreateForm({
openId: "",
name: "",
email: "",
role: "user",
});
},
onError: (error) => {
toast.error(`Erreur : ${error.message}`);
},
});
const updateMutation = trpc.users.update.useMutation({
onSuccess: () => {
toast.success("Utilisateur modifié avec succès");
@@ -76,6 +101,25 @@ export default function AdminUsers() {
},
});
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,
role: createForm.role,
isActive: true,
});
};
const handleEdit = (user: any) => {
setSelectedUser(user);
setEditForm({
@@ -142,11 +186,17 @@ export default function AdminUsers() {
return (
<div className="container mx-auto py-8">
<div className="mb-6">
<h1 className="text-3xl font-bold mb-2">Gestion des Utilisateurs</h1>
<p className="text-muted-foreground">
Gérez les comptes utilisateurs de l'application
</p>
<div className="mb-6 flex justify-between items-start">
<div>
<h1 className="text-3xl font-bold mb-2">Gestion des Utilisateurs</h1>
<p className="text-muted-foreground">
Gérez les comptes utilisateurs de l'application
</p>
</div>
<Button onClick={handleCreate}>
<Plus className="h-4 w-4 mr-2" />
Ajouter un utilisateur
</Button>
</div>
{/* Filtres */}
@@ -280,6 +330,78 @@ export default function AdminUsers() {
</Table>
</div>
{/* Dialog de création */}
<Dialog open={createDialogOpen} onOpenChange={setCreateDialogOpen}>
<DialogContent>
<DialogHeader>
<DialogTitle>Créer un nouvel utilisateur</DialogTitle>
<DialogDescription>
Ajoutez un nouvel utilisateur à l'application
</DialogDescription>
</DialogHeader>
<div className="space-y-4">
<div>
<Label htmlFor="createOpenId">Identifiant OpenID *</Label>
<Input
id="createOpenId"
value={createForm.openId}
onChange={(e) => setCreateForm({ ...createForm, openId: e.target.value })}
placeholder="Identifiant unique de l'utilisateur"
/>
</div>
<div>
<Label htmlFor="createName">Nom</Label>
<Input
id="createName"
value={createForm.name}
onChange={(e) => setCreateForm({ ...createForm, name: e.target.value })}
placeholder="Nom de l'utilisateur"
/>
</div>
<div>
<Label htmlFor="createEmail">Email</Label>
<Input
id="createEmail"
type="email"
value={createForm.email}
onChange={(e) => setCreateForm({ ...createForm, email: e.target.value })}
placeholder="email@exemple.com"
/>
</div>
<div>
<Label htmlFor="createRole">Rôle</Label>
<Select
value={createForm.role}
onValueChange={(value: "user" | "admin") =>
setCreateForm({ ...createForm, role: value })
}
>
<SelectTrigger id="createRole">
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value="user">Utilisateur</SelectItem>
<SelectItem value="admin">Administrateur</SelectItem>
</SelectContent>
</Select>
</div>
</div>
<DialogFooter>
<Button variant="outline" onClick={() => setCreateDialogOpen(false)}>
Annuler
</Button>
<Button onClick={handleSaveCreate} disabled={createMutation.isPending}>
{createMutation.isPending ? "Création..." : "Créer"}
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
{/* Dialog de modification */}
<Dialog open={editDialogOpen} onOpenChange={setEditDialogOpen}>
<DialogContent>