Fixed creation of users + better frontend handling of permissions

This commit is contained in:
cdricms
2025-03-06 17:34:52 +01:00
parent 3c6038bce1
commit 7cb633b4c6
46 changed files with 1511 additions and 909 deletions

View File

@@ -10,21 +10,19 @@ import {
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 { Loader2, MoreHorizontal, UserRoundPlus } from "lucide-react";
import IUser from "@/interfaces/IUser";
import hasPermissions from "@/lib/hasPermissions";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "./ui/dropdown-menu";
export default function MembersTable({ user }: { user: IUser }) {
const {
@@ -34,23 +32,12 @@ export default function MembersTable({ user }: { user: IUser }) {
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 { users } = hasPermissions(user.roles, {
users: ["delete", "update", "insert"],
} as const);
const handleOpenDialog = (member: Member | null) => {
setCurrentMember(member);
@@ -59,10 +46,12 @@ export default function MembersTable({ user }: { user: IUser }) {
const handleSaveMember = async (savedMember: Member) => {
if (savedMember.userId) {
const dif = DiffUtils.getDifferences(currentMember!, savedMember);
if (DiffUtils.isEmpty(dif)) return;
const res = await request<unknown>(
`/users/${savedMember.userId}/update`,
{
body: savedMember,
body: dif,
requiresAuth: true,
method: "PATCH",
},
@@ -96,105 +85,83 @@ export default function MembersTable({ user }: { user: IUser }) {
return (
<div className="space-y-4">
<div className="flex justify-between">
<Button onClick={toggleSelectMode}>
{selectMode ? <CircleX /> : "Selectionner"}
</Button>
{hasPermissions(user.roles, { users: ["insert"] }) && (
{users.insert && (
<Button onClick={() => handleOpenDialog(null)}>
<UserRoundPlus />
</Button>
)}
</div>
<div className="relative">
{isLoading && <Loader2 className="animate-spin" />}
<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>Rôles</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>
)}
members.map((_member) => (
<TableRow key={_member.userId}>
<TableCell>
<Link
href={`/dashboard/members/${member.userId}`}
>
<span className="underline">
{member.firstname}
</span>
</Link>
{_member.firstname}
</TableCell>
<TableCell>
<Link
href={`/dashboard/members/${member.userId}`}
>
<span className="underline">
{member.lastname}
</span>
</Link>
{_member.lastname}
</TableCell>
<TableCell>{_member.email}</TableCell>
<TableCell>{_member.phone}</TableCell>
<TableCell>
{_member.roles
?.map((r) => r.name)
.join(", ")}
</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>
)}
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button
variant="ghost"
className="h-8 w-8 p-0"
>
<span className="sr-only">
Ouvrir le menu
</span>
<MoreHorizontal className="h-4 w-4" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
{users.update && (
<DropdownMenuItem
onClick={() =>
handleOpenDialog(
_member,
)
}
>
Mettre à jour
</DropdownMenuItem>
)}
{users.delete && (
<DropdownMenuItem
onClick={() =>
handleDelete(
_member.userId!,
)
}
>
Supprimer
</DropdownMenuItem>
)}
</DropdownMenuContent>
</DropdownMenu>
</TableCell>
</TableRow>
))}