update api users and groups and users 6
This commit is contained in:
parent
cfafcb312e
commit
9d0b462a67
@ -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>
|
||||
<div className="flex flex-wrap gap-2">
|
||||
{roles.map((role) => (
|
||||
<SelectItem key={role.id} value={role.name}>
|
||||
{role.name}
|
||||
</SelectItem>
|
||||
<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>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</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>
|
||||
<div className="flex flex-wrap gap-2">
|
||||
{roles.map((role) => (
|
||||
<SelectItem key={role.id} value={role.name}>
|
||||
{role.name}
|
||||
</SelectItem>
|
||||
<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>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</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>
|
||||
);
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user