214 lines
5.4 KiB
TypeScript
214 lines
5.4 KiB
TypeScript
"use client";
|
|
|
|
import { useState } from "react";
|
|
import {
|
|
Table,
|
|
TableBody,
|
|
TableCell,
|
|
TableHead,
|
|
TableHeader,
|
|
TableRow,
|
|
} from "@/components/ui/table";
|
|
import { Button } from "@/components/ui/button";
|
|
import { Checkbox } from "@/components/ui/checkbox";
|
|
import { ScrollArea } from "@/components/ui/scroll-area";
|
|
import MemberDialog, { Member } from "./member-dialog";
|
|
import { useApi } from "@/hooks/use-api";
|
|
import request from "@/lib/request";
|
|
import {
|
|
CircleX,
|
|
Loader2,
|
|
Trash2,
|
|
UserRoundPen,
|
|
UserRoundPlus,
|
|
} from "lucide-react";
|
|
import Link from "next/link";
|
|
import IUser from "@/interfaces/IUser";
|
|
import hasPermissions from "@/lib/hasPermissions";
|
|
|
|
export default function MembersTable({ user }: { user: IUser }) {
|
|
const {
|
|
data: members,
|
|
error,
|
|
mutate,
|
|
success,
|
|
isLoading,
|
|
} = useApi<Member[]>("/users", undefined, true, false);
|
|
const [selectMode, setSelectMode] = useState(false);
|
|
const [selectedMembers, setSelectedMembers] = useState<string[]>([]);
|
|
const [dialogOpen, setDialogOpen] = useState(false);
|
|
const [currentMember, setCurrentMember] = useState<Member | null>(null);
|
|
|
|
const toggleSelectMode = () => {
|
|
setSelectMode(!selectMode);
|
|
setSelectedMembers([]);
|
|
};
|
|
|
|
const toggleMemberSelection = (userId: string) => {
|
|
setSelectedMembers((prev) =>
|
|
prev.includes(userId)
|
|
? prev.filter((id) => id !== userId)
|
|
: [...prev, userId],
|
|
);
|
|
};
|
|
|
|
const handleOpenDialog = (member: Member | null) => {
|
|
setCurrentMember(member);
|
|
setDialogOpen(true);
|
|
};
|
|
|
|
const handleSaveMember = async (savedMember: Member) => {
|
|
if (savedMember.userId) {
|
|
const res = await request<unknown>(
|
|
`/users/${savedMember.userId}/update`,
|
|
{
|
|
body: savedMember,
|
|
requiresAuth: true,
|
|
method: "PATCH",
|
|
},
|
|
);
|
|
if (res.status === "Success") mutate();
|
|
// Update existing member
|
|
// setMembers((prev) =>
|
|
// prev.map((m) =>
|
|
// m.user_id === savedMember.user_id ? savedMember : m,
|
|
// ),
|
|
// );
|
|
} else {
|
|
delete savedMember.userId;
|
|
const res = await request<unknown>("/users/new", {
|
|
body: savedMember,
|
|
method: "POST",
|
|
requiresAuth: true,
|
|
});
|
|
if (res.status === "Success") mutate();
|
|
}
|
|
};
|
|
|
|
const handleDelete = async (userId: string) => {
|
|
const res = await request<unknown>(`/users/${userId}/delete`, {
|
|
method: "DELETE",
|
|
requiresAuth: true,
|
|
});
|
|
if (res.status === "Success") mutate();
|
|
};
|
|
|
|
return (
|
|
<div className="space-y-4">
|
|
<div className="flex justify-between">
|
|
<Button onClick={toggleSelectMode}>
|
|
{selectMode ? <CircleX /> : "Selectionner"}
|
|
</Button>
|
|
{hasPermissions(user.roles, { users: ["insert"] }) && (
|
|
<Button onClick={() => handleOpenDialog(null)}>
|
|
<UserRoundPlus />
|
|
</Button>
|
|
)}
|
|
</div>
|
|
<div className="relative">
|
|
<ScrollArea className="h-full rounded-md border">
|
|
<Table>
|
|
<TableHeader className="sticky top-0 bg-background z-10 shadow-sm">
|
|
<TableRow>
|
|
{selectMode && (
|
|
<TableHead className="w-[50px]">
|
|
Sélectionner
|
|
</TableHead>
|
|
)}
|
|
<TableHead>Prénom</TableHead>
|
|
<TableHead>Nom</TableHead>
|
|
<TableHead>Email</TableHead>
|
|
<TableHead>Téléphone</TableHead>
|
|
<TableHead>Rôle</TableHead>
|
|
<TableHead className="text-right">
|
|
Actions
|
|
</TableHead>
|
|
</TableRow>
|
|
</TableHeader>
|
|
<TableBody>
|
|
{isLoading && <Loader2 className="animate-spin" />}
|
|
{members &&
|
|
members.map((member) => (
|
|
<TableRow key={member.userId}>
|
|
{selectMode && (
|
|
<TableCell>
|
|
<Checkbox
|
|
checked={selectedMembers.includes(
|
|
member.userId!,
|
|
)}
|
|
onCheckedChange={() =>
|
|
toggleMemberSelection(
|
|
member.userId!,
|
|
)
|
|
}
|
|
/>
|
|
</TableCell>
|
|
)}
|
|
<TableCell>
|
|
<Link
|
|
href={`/dashboard/members/${member.userId}`}
|
|
>
|
|
<span className="underline">
|
|
{member.firstname}
|
|
</span>
|
|
</Link>
|
|
</TableCell>
|
|
<TableCell>
|
|
<Link
|
|
href={`/dashboard/members/${member.userId}`}
|
|
>
|
|
<span className="underline">
|
|
{member.lastname}
|
|
</span>
|
|
</Link>
|
|
</TableCell>
|
|
<TableCell>{member.email}</TableCell>
|
|
<TableCell>{member.phone}</TableCell>
|
|
<TableCell>{member.role}</TableCell>
|
|
<TableCell className="text-right">
|
|
{hasPermissions(user.roles, {
|
|
users: ["update"],
|
|
}) && (
|
|
<Button
|
|
variant="outline"
|
|
size="sm"
|
|
className="mr-2"
|
|
onClick={() =>
|
|
handleOpenDialog(member)
|
|
}
|
|
>
|
|
<UserRoundPen />
|
|
</Button>
|
|
)}
|
|
{hasPermissions(user.roles, {
|
|
users: ["delete"],
|
|
}) && (
|
|
<Button
|
|
variant="destructive"
|
|
size="sm"
|
|
onClick={() =>
|
|
handleDelete(
|
|
member.userId!,
|
|
)
|
|
}
|
|
>
|
|
<Trash2 />
|
|
</Button>
|
|
)}
|
|
</TableCell>
|
|
</TableRow>
|
|
))}
|
|
</TableBody>
|
|
</Table>
|
|
</ScrollArea>
|
|
</div>
|
|
<MemberDialog
|
|
isOpen={dialogOpen}
|
|
onClose={() => setDialogOpen(false)}
|
|
member={currentMember}
|
|
onSave={handleSaveMember}
|
|
/>
|
|
</div>
|
|
);
|
|
}
|