update api users and groups and users 6

This commit is contained in:
Alma 2025-04-09 21:00:50 +02:00
parent cfafcb312e
commit 9d0b462a67

View File

@ -12,7 +12,7 @@ import {
import { Button } from "@/components/ui/button";
import { useSession } from "next-auth/react";
import { Input } from "@/components/ui/input";
import { MoreHorizontal, Trash, Edit, UserPlus } from "lucide-react";
import { MoreHorizontal, Trash, Edit, UserPlus, Key, Lock, Unlock } from "lucide-react";
import {
DropdownMenu,
DropdownMenuContent,
@ -46,6 +46,7 @@ interface User {
email: string;
createdTimestamp: number;
roles: string[];
enabled: boolean;
}
interface Role {
@ -72,14 +73,16 @@ export function UsersTable({ userRole = [] }: UsersTableProps) {
const [searchTerm, setSearchTerm] = useState("");
const [newUserDialog, setNewUserDialog] = useState(false);
const [editUserDialog, setEditUserDialog] = useState(false);
const [manageRolesDialog, setManageRolesDialog] = useState(false);
const [selectedUser, setSelectedUser] = useState<User | null>(null);
const [formData, setFormData] = useState({
username: "",
firstName: "",
lastName: "",
firstName: "",
email: "",
password: "",
roles: [] as string[],
enabled: true,
});
useEffect(() => {
@ -149,6 +152,7 @@ export function UsersTable({ userRole = [] }: UsersTableProps) {
email: "",
password: "",
roles: [],
enabled: true,
});
toast({
@ -176,10 +180,56 @@ export function UsersTable({ userRole = [] }: UsersTableProps) {
email: user.email || "",
password: "",
roles: user.roles || [],
enabled: user.enabled,
});
setEditUserDialog(true);
};
const handleManageRoles = async (userId: string) => {
const user = users.find(u => u.id === userId);
if (!user) return;
setSelectedUser(user);
setFormData(prev => ({ ...prev, roles: user.roles || [] }));
setManageRolesDialog(true);
};
const handleUpdateRoles = async () => {
if (!selectedUser) return;
try {
const response = await fetch(`/api/users/${selectedUser.id}/roles`, {
method: "PUT",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
roles: formData.roles,
}),
});
if (!response.ok) {
throw new Error("Erreur lors de la mise à jour des rôles");
}
await fetchUsers();
setManageRolesDialog(false);
setSelectedUser(null);
toast({
title: "Succès",
description: "Les rôles ont été mis à jour avec succès",
});
} catch (error) {
toast({
title: "Erreur",
description: error instanceof Error ? error.message : "Une erreur est survenue",
variant: "destructive",
});
}
};
const handleUpdateUser = async (e: React.FormEvent) => {
e.preventDefault();
if (!selectedUser) return;
@ -197,15 +247,11 @@ export function UsersTable({ userRole = [] }: UsersTableProps) {
}),
});
const data = await response.json();
if (!response.ok) {
throw new Error(data.error || "Erreur lors de la modification de l'utilisateur");
throw new Error("Erreur lors de la modification de l'utilisateur");
}
setUsers(prevUsers => prevUsers.map(u =>
u.id === selectedUser.id ? { ...u, ...data } : u
));
await fetchUsers();
setEditUserDialog(false);
setSelectedUser(null);
@ -223,55 +269,6 @@ export function UsersTable({ userRole = [] }: UsersTableProps) {
}
};
const handleManageRoles = async (userId: string) => {
const user = users.find(u => u.id === userId);
if (!user) return;
setSelectedUser(user);
setFormData(prev => ({ ...prev, roles: user.roles || [] }));
setEditUserDialog(true);
};
const handleUpdateRoles = async () => {
if (!selectedUser) return;
try {
const response = await fetch(`/api/users/${selectedUser.id}/roles`, {
method: "PUT",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
roles: formData.roles,
}),
});
const data = await response.json();
if (!response.ok) {
throw new Error(data.error || "Erreur lors de la mise à jour des rôles");
}
setUsers(prevUsers => prevUsers.map(u =>
u.id === selectedUser.id ? { ...u, roles: formData.roles } : u
));
setEditUserDialog(false);
setSelectedUser(null);
toast({
title: "Succès",
description: "Les rôles ont été mis à jour avec succès",
});
} catch (error) {
toast({
title: "Erreur",
description: error instanceof Error ? error.message : "Une erreur est survenue",
variant: "destructive",
});
}
};
const handleDelete = async (userId: string) => {
try {
const response = await fetch(`/api/users/${userId}`, {
@ -299,6 +296,67 @@ export function UsersTable({ userRole = [] }: UsersTableProps) {
}
};
const handleChangePassword = async (userId: string) => {
const newPassword = prompt("Entrez le nouveau mot de passe:");
if (!newPassword) return;
try {
const response = await fetch(`/api/users/${userId}/password`, {
method: "PUT",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ password: newPassword }),
});
if (!response.ok) {
throw new Error("Erreur lors du changement de mot de passe");
}
toast({
title: "Succès",
description: "Le mot de passe a été modifié avec succès",
});
} catch (error) {
toast({
title: "Erreur",
description: error instanceof Error ? error.message : "Une erreur est survenue",
variant: "destructive",
});
}
};
const handleToggleUserStatus = async (userId: string, currentStatus: boolean) => {
try {
const response = await fetch(`/api/users/${userId}`, {
method: "PUT",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ enabled: !currentStatus }),
});
if (!response.ok) {
throw new Error("Erreur lors de la modification du statut de l'utilisateur");
}
setUsers(prevUsers => prevUsers.map(u =>
u.id === userId ? { ...u, enabled: !currentStatus } : u
));
toast({
title: "Succès",
description: `L'utilisateur a été ${!currentStatus ? "activé" : "désactivé"} avec succès`,
});
} catch (error) {
toast({
title: "Erreur",
description: error instanceof Error ? error.message : "Une erreur est survenue",
variant: "destructive",
});
}
};
const filteredUsers = useMemo(() => {
let filtered = users;
@ -351,14 +409,6 @@ export function UsersTable({ userRole = [] }: UsersTableProps) {
required
/>
</div>
<div className="space-y-2">
<Label htmlFor="firstName">Prénom</Label>
<Input
id="firstName"
value={formData.firstName}
onChange={(e) => setFormData(prev => ({ ...prev, firstName: e.target.value }))}
/>
</div>
<div className="space-y-2">
<Label htmlFor="lastName">Nom</Label>
<Input
@ -367,6 +417,14 @@ export function UsersTable({ userRole = [] }: UsersTableProps) {
onChange={(e) => setFormData(prev => ({ ...prev, lastName: e.target.value }))}
/>
</div>
<div className="space-y-2">
<Label htmlFor="firstName">Prénom</Label>
<Input
id="firstName"
value={formData.firstName}
onChange={(e) => setFormData(prev => ({ ...prev, firstName: e.target.value }))}
/>
</div>
<div className="space-y-2">
<Label htmlFor="email">Email</Label>
<Input
@ -389,21 +447,43 @@ export function UsersTable({ userRole = [] }: UsersTableProps) {
</div>
<div className="space-y-2">
<Label htmlFor="roles">Rôles</Label>
<Select
value={formData.roles[0] || ""}
onValueChange={(value) => setFormData(prev => ({ ...prev, roles: [value] }))}
>
<SelectTrigger>
<SelectValue placeholder="Sélectionner un rôle" />
</SelectTrigger>
<SelectContent>
{roles.map((role) => (
<SelectItem key={role.id} value={role.name}>
{role.name}
</SelectItem>
))}
</SelectContent>
</Select>
<div className="flex flex-wrap gap-2">
{roles.map((role) => (
<div key={role.id} className="flex items-center space-x-2">
<input
type="checkbox"
id={`role-${role.id}`}
checked={formData.roles.includes(role.name)}
onChange={(e) => {
setFormData(prev => ({
...prev,
roles: e.target.checked
? [...prev.roles, role.name]
: prev.roles.filter(r => r !== role.name)
}));
}}
/>
<label htmlFor={`role-${role.id}`}>{role.name}</label>
</div>
))}
</div>
<div className="flex flex-wrap gap-2 mt-2">
{formData.roles.map(role => (
<span key={role} className="px-2 py-1 bg-gray-100 rounded-md text-sm">
{role}
<button
type="button"
onClick={() => setFormData(prev => ({
...prev,
roles: prev.roles.filter(r => r !== role)
}))}
className="ml-2 text-gray-500 hover:text-gray-700"
>
×
</button>
</span>
))}
</div>
</div>
<Button type="submit" className="w-full">
Créer l'utilisateur
@ -454,6 +534,23 @@ export function UsersTable({ userRole = [] }: UsersTableProps) {
<UserPlus className="mr-2 h-4 w-4" />
Gérer les rôles
</DropdownMenuItem>
<DropdownMenuItem onClick={() => handleChangePassword(user.id)}>
<Key className="mr-2 h-4 w-4" />
Changer le mot de passe
</DropdownMenuItem>
<DropdownMenuItem onClick={() => handleToggleUserStatus(user.id, user.enabled)}>
{user.enabled ? (
<>
<Lock className="mr-2 h-4 w-4" />
Désactiver
</>
) : (
<>
<Unlock className="mr-2 h-4 w-4" />
Activer
</>
)}
</DropdownMenuItem>
<DropdownMenuSeparator />
<DropdownMenuItem
className="text-red-600"
@ -476,14 +573,6 @@ export function UsersTable({ userRole = [] }: UsersTableProps) {
<DialogTitle>Modifier l'utilisateur</DialogTitle>
</DialogHeader>
<form onSubmit={handleUpdateUser} className="space-y-4">
<div className="space-y-2">
<Label htmlFor="edit-firstName">Prénom</Label>
<Input
id="edit-firstName"
value={formData.firstName}
onChange={(e) => setFormData(prev => ({ ...prev, firstName: e.target.value }))}
/>
</div>
<div className="space-y-2">
<Label htmlFor="edit-lastName">Nom</Label>
<Input
@ -492,6 +581,14 @@ export function UsersTable({ userRole = [] }: UsersTableProps) {
onChange={(e) => setFormData(prev => ({ ...prev, lastName: e.target.value }))}
/>
</div>
<div className="space-y-2">
<Label htmlFor="edit-firstName">Prénom</Label>
<Input
id="edit-firstName"
value={formData.firstName}
onChange={(e) => setFormData(prev => ({ ...prev, firstName: e.target.value }))}
/>
</div>
<div className="space-y-2">
<Label htmlFor="edit-email">Email</Label>
<Input
@ -503,21 +600,43 @@ export function UsersTable({ userRole = [] }: UsersTableProps) {
</div>
<div className="space-y-2">
<Label htmlFor="edit-roles">Rôles</Label>
<Select
value={formData.roles[0] || ""}
onValueChange={(value) => setFormData(prev => ({ ...prev, roles: [value] }))}
>
<SelectTrigger>
<SelectValue placeholder="Sélectionner un rôle" />
</SelectTrigger>
<SelectContent>
{roles.map((role) => (
<SelectItem key={role.id} value={role.name}>
{role.name}
</SelectItem>
))}
</SelectContent>
</Select>
<div className="flex flex-wrap gap-2">
{roles.map((role) => (
<div key={role.id} className="flex items-center space-x-2">
<input
type="checkbox"
id={`edit-role-${role.id}`}
checked={formData.roles.includes(role.name)}
onChange={(e) => {
setFormData(prev => ({
...prev,
roles: e.target.checked
? [...prev.roles, role.name]
: prev.roles.filter(r => r !== role.name)
}));
}}
/>
<label htmlFor={`edit-role-${role.id}`}>{role.name}</label>
</div>
))}
</div>
<div className="flex flex-wrap gap-2 mt-2">
{formData.roles.map(role => (
<span key={role} className="px-2 py-1 bg-gray-100 rounded-md text-sm">
{role}
<button
type="button"
onClick={() => setFormData(prev => ({
...prev,
roles: prev.roles.filter(r => r !== role)
}))}
className="ml-2 text-gray-500 hover:text-gray-700"
>
×
</button>
</span>
))}
</div>
</div>
<div className="flex space-x-2">
<Button type="submit" className="flex-1">
@ -535,6 +654,59 @@ export function UsersTable({ userRole = [] }: UsersTableProps) {
</form>
</DialogContent>
</Dialog>
<Dialog open={manageRolesDialog} onOpenChange={setManageRolesDialog}>
<DialogContent>
<DialogHeader>
<DialogTitle>Gérer les rôles de {selectedUser?.username}</DialogTitle>
</DialogHeader>
<div className="space-y-4">
<div className="space-y-2">
<Label>Rôles</Label>
<div className="flex flex-wrap gap-2">
{roles.map((role) => (
<div key={role.id} className="flex items-center space-x-2">
<input
type="checkbox"
id={`manage-role-${role.id}`}
checked={formData.roles.includes(role.name)}
onChange={(e) => {
setFormData(prev => ({
...prev,
roles: e.target.checked
? [...prev.roles, role.name]
: prev.roles.filter(r => r !== role.name)
}));
}}
/>
<label htmlFor={`manage-role-${role.id}`}>{role.name}</label>
</div>
))}
</div>
<div className="flex flex-wrap gap-2 mt-2">
{formData.roles.map(role => (
<span key={role} className="px-2 py-1 bg-gray-100 rounded-md text-sm">
{role}
<button
type="button"
onClick={() => setFormData(prev => ({
...prev,
roles: prev.roles.filter(r => r !== role)
}))}
className="ml-2 text-gray-500 hover:text-gray-700"
>
×
</button>
</span>
))}
</div>
</div>
<Button onClick={handleUpdateRoles} className="w-full">
Mettre à jour les rôles
</Button>
</div>
</DialogContent>
</Dialog>
</div>
);
}