Fixed creation of users + better frontend handling of permissions
This commit is contained in:
@@ -1,238 +0,0 @@
|
||||
"use client";
|
||||
|
||||
import { UserIcon, Building, X } from "lucide-react";
|
||||
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Card, CardContent } from "@/components/ui/card";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/components/ui/select";
|
||||
import { Role, User } from "@/types/types";
|
||||
import { useParams } from "next/navigation";
|
||||
import { useApi } from "@/hooks/use-api";
|
||||
import { useState } from "react";
|
||||
import request from "@/lib/request";
|
||||
import IUser from "@/interfaces/IUser";
|
||||
import hasPermissions from "@/lib/hasPermissions";
|
||||
|
||||
export default function UserDetailsPage({ user }: { user: IUser }) {
|
||||
const { uuid } = useParams<{ uuid: string }>();
|
||||
const _user = useApi<User>(`/users/${uuid}`, {}, true);
|
||||
|
||||
const availableRoles = useApi<Role[]>("/roles", {}, true);
|
||||
availableRoles.data ??= [];
|
||||
const [selectedRole, setSelectedRole] = useState<Role | null>(null);
|
||||
// const [selectedOrg, setSelectedOrg] = useState("");
|
||||
|
||||
const addRole = async (role: Role) => {
|
||||
const res = await request(
|
||||
`/users/${_user.data?.userId}/roles/${role.id}/add`,
|
||||
{ method: "PATCH", requiresAuth: true },
|
||||
);
|
||||
if (res.status === "Success") {
|
||||
setSelectedRole(null);
|
||||
_user.mutate();
|
||||
}
|
||||
};
|
||||
|
||||
const removeRole = async (role: Role) => {
|
||||
const res = await request(
|
||||
`/users/${_user.data?.userId}/roles/${role.id}/remove`,
|
||||
{ method: "PATCH", requiresAuth: true },
|
||||
);
|
||||
if (res.status === "Success") _user.mutate();
|
||||
};
|
||||
|
||||
const addOrganization = () => {
|
||||
// if (selectedOrg && !user.organizations.includes(selectedOrg)) {
|
||||
// setUser((prevUser) => ({
|
||||
// ...prevUser,
|
||||
// organizations: [...prevUser.organizations, selectedOrg],
|
||||
// }));
|
||||
// setSelectedOrg("");
|
||||
// }
|
||||
};
|
||||
|
||||
const removeOrganization = (orgToRemove: string) => {
|
||||
// setUser((prevUser) => ({
|
||||
// ...prevUser,
|
||||
// organizations: prevUser.organizations.filter(
|
||||
// (org) => org !== orgToRemove,
|
||||
// ),
|
||||
// }));
|
||||
};
|
||||
|
||||
if (!_user.data || !_user.success) return <p>Error</p>;
|
||||
|
||||
return (
|
||||
<div className="container mx-auto py-10">
|
||||
<Card>
|
||||
<CardContent className="pt-6">
|
||||
<div className="grid gap-6">
|
||||
<div className="flex items-center space-x-4">
|
||||
<UserIcon className="h-12 w-12 text-gray-400" />
|
||||
<div>
|
||||
<h2 className="text-xl font-semibold">
|
||||
{_user.data.firstname} {_user.data.lastname}
|
||||
</h2>
|
||||
<p className="text-sm text-gray-500">
|
||||
{_user.data.email}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="grid gap-6 md:grid-cols-2">
|
||||
<div>
|
||||
<h3 className="text-lg font-semibold mb-2">
|
||||
Rôles
|
||||
</h3>
|
||||
<div className="flex flex-wrap gap-2">
|
||||
{_user.data.roles?.map((role) => (
|
||||
<Badge
|
||||
key={role.id}
|
||||
variant="secondary"
|
||||
className="text-sm py-1 px-2"
|
||||
>
|
||||
{role.name}
|
||||
{hasPermissions(user.roles, {
|
||||
users: ["update"],
|
||||
}) && (
|
||||
<button
|
||||
onClick={() =>
|
||||
removeRole(role)
|
||||
}
|
||||
className="ml-2 text-gray-500 hover:text-gray-700"
|
||||
>
|
||||
<X className="h-3 w-3" />
|
||||
</button>
|
||||
)}
|
||||
</Badge>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{hasPermissions(user.roles, {
|
||||
users: ["update"],
|
||||
}) && (
|
||||
<div className="mt-2 flex space-x-2">
|
||||
<Select
|
||||
value={
|
||||
selectedRole
|
||||
? selectedRole.name
|
||||
: ""
|
||||
}
|
||||
onValueChange={(s) => {
|
||||
const r =
|
||||
availableRoles.data?.find(
|
||||
(r) => r.name === s,
|
||||
);
|
||||
console.log(r);
|
||||
if (r) setSelectedRole(r);
|
||||
}}
|
||||
>
|
||||
<SelectTrigger className="w-[180px]">
|
||||
<SelectValue placeholder="Sélectionner un rôle" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{availableRoles.data
|
||||
.filter(
|
||||
(org) =>
|
||||
!_user.data?.roles?.includes(
|
||||
org,
|
||||
),
|
||||
)
|
||||
.map((role) => (
|
||||
<SelectItem
|
||||
key={role.id}
|
||||
value={role.name}
|
||||
>
|
||||
{role.name}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<Button
|
||||
disabled={
|
||||
!_user.data || !selectedRole
|
||||
}
|
||||
onClick={() =>
|
||||
addRole(selectedRole!)
|
||||
}
|
||||
className="flex items-center"
|
||||
>
|
||||
<Building className="mr-2 h-4 w-4" />
|
||||
Ajouter le rôle
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/*<div>
|
||||
<h3 className="text-lg font-semibold mb-2">
|
||||
Organizations
|
||||
</h3>
|
||||
<div className="flex flex-wrap gap-2">
|
||||
{user.data.organizations.map((org) => (
|
||||
<Badge
|
||||
key={org}
|
||||
variant="outline"
|
||||
className="text-sm py-1 px-2"
|
||||
>
|
||||
{org}
|
||||
<button
|
||||
onClick={() =>
|
||||
removeOrganization(org)
|
||||
}
|
||||
className="ml-2 text-gray-500 hover:text-gray-700"
|
||||
>
|
||||
<X className="h-3 w-3" />
|
||||
</button>
|
||||
</Badge>
|
||||
))}
|
||||
</div>
|
||||
<div className="mt-2 flex space-x-2">
|
||||
<Select
|
||||
value={selectedOrg}
|
||||
onValueChange={setSelectedOrg}
|
||||
>
|
||||
<SelectTrigger className="w-[180px]">
|
||||
<SelectValue placeholder="Select an organization" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{availableOrganizations
|
||||
.filter(
|
||||
(org) =>
|
||||
!user.organizations.includes(
|
||||
org,
|
||||
),
|
||||
)
|
||||
.map((org) => (
|
||||
<SelectItem
|
||||
key={org}
|
||||
value={org}
|
||||
>
|
||||
{org}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<Button
|
||||
onClick={addOrganization}
|
||||
className="flex items-center"
|
||||
>
|
||||
<Building className="mr-2 h-4 w-4" />
|
||||
Add Org
|
||||
</Button>
|
||||
</div>
|
||||
</div> */}
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
import getMe from "@/lib/getMe";
|
||||
import hasPermissions from "@/lib/hasPermissions";
|
||||
import { redirect } from "next/navigation";
|
||||
import UserDetailsPage from "./_user";
|
||||
|
||||
export default async function Page() {
|
||||
const me = await getMe();
|
||||
if (
|
||||
!me ||
|
||||
me.status === "Error" ||
|
||||
!me.data ||
|
||||
!hasPermissions(me.data.roles, {
|
||||
users: ["get"],
|
||||
})
|
||||
) {
|
||||
redirect("/dashboard");
|
||||
}
|
||||
|
||||
return <UserDetailsPage user={me.data} />;
|
||||
}
|
||||
@@ -12,7 +12,7 @@ export default async function Page({}) {
|
||||
!me.data ||
|
||||
!hasPermissions(me.data.roles, {
|
||||
users: ["get"],
|
||||
})
|
||||
} as const).all
|
||||
) {
|
||||
redirect("/dashboard");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user