TTMT.ManageWebGUI/src/routes/_auth/user/role/$roleId/index.tsx

146 lines
5.5 KiB
TypeScript
Raw Normal View History

2026-03-06 17:54:09 +07:00
import { createFileRoute, useNavigate } from "@tanstack/react-router";
import { useGetRoleById, useGetRolePermissions } from "@/hooks/queries";
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from "@/components/ui/card";
import { Button } from "@/components/ui/button";
import { Badge } from "@/components/ui/badge";
import { Shield, ArrowLeft, Check, X } from "lucide-react";
import type { PermissionOnRole } from "@/types/permission";
export const Route = createFileRoute("/_auth/user/role/$roleId/")({
2026-03-19 18:38:21 +07:00
head: () => ({
meta: [{ title: "Quyền của người dùng | AccessControl" }]
}),
2026-03-06 17:54:09 +07:00
component: ViewRolePermissionsComponent,
loader: async ({ context, params }) => {
context.breadcrumbs = [
2026-03-19 18:38:21 +07:00
{
title: "Quản lý tài khoản",
path: "#"
},
{
title: "Danh sách người dùng",
path: "/user"
},
{
title: "Quyền của người dùng",
path: `/user/role/${params.roleId}`
}
2026-03-06 17:54:09 +07:00
];
},
});
function ViewRolePermissionsComponent() {
const { roleId } = Route.useParams();
const navigate = useNavigate();
const roleIdNum = parseInt(roleId, 10);
const { data: role, isLoading: roleLoading } = useGetRoleById(roleIdNum);
const { data: permissions = [], isLoading: permissionsLoading } = useGetRolePermissions(roleIdNum);
const isLoading = roleLoading || permissionsLoading;
// Group permissions by parent
const groupedPermissions = (permissions as PermissionOnRole[]).reduce((acc, permission) => {
if (permission.parentId === null) {
if (!acc[permission.permisionId]) {
acc[permission.permisionId] = { parent: permission, children: [] };
} else {
acc[permission.permisionId].parent = permission;
}
} else {
if (!acc[permission.parentId]) {
acc[permission.parentId] = { parent: null as any, children: [] };
}
acc[permission.parentId].children.push(permission);
}
return acc;
}, {} as Record<number, { parent: PermissionOnRole; children: PermissionOnRole[] }>);
if (isLoading) {
return (
<div className="flex items-center justify-center h-64">
<div className="animate-spin rounded-full h-8 w-8 border-b-2 border-primary"></div>
</div>
);
}
return (
<div className="w-full px-6 space-y-4">
<div className="flex items-center gap-4">
2026-03-19 18:38:21 +07:00
<Button variant="ghost" size="sm" onClick={() => navigate({ to: "/user" })}>
2026-03-06 17:54:09 +07:00
<ArrowLeft className="h-4 w-4 mr-2" />
Quay lại
</Button>
</div>
<Card>
<CardHeader>
<CardTitle className="flex items-center gap-2">
<Shield className="h-5 w-5" />
Quyền hạn của Role: {role?.roleName || `#${roleId}`}
</CardTitle>
<CardDescription>
Danh sách các quyền đưc gán cho role này
{role?.priority !== undefined && (
<span className="ml-2">(Đ ưu tiên: <Badge variant="outline">{role.priority}</Badge>)</span>
)}
</CardDescription>
</CardHeader>
<CardContent>
{permissions.length === 0 ? (
<div className="text-center text-muted-foreground py-8">Không quyền nào đưc gán cho role này</div>
) : (
<div className="space-y-6">
{Object.values(groupedPermissions).map(({ parent, children }) => (
<div key={parent?.permisionId} className="border rounded-lg p-4">
<div className="flex items-center justify-between mb-3">
<div className="flex items-center gap-2">
2026-03-19 18:38:21 +07:00
<span className="font-semibold text-lg">{parent?.permissionName || "Allow all"}</span>
2026-03-06 17:54:09 +07:00
<Badge variant="secondary" className="text-xs">{parent?.permissionCode}</Badge>
</div>
<div className="flex items-center gap-1">
2026-03-19 18:38:21 +07:00
{(parent?.isChecked === 1 || parent === null) ? (
2026-03-06 17:54:09 +07:00
<Badge variant="default" className="bg-green-600">
<Check className="h-3 w-3 mr-1" />Đã bật
</Badge>
) : (
<Badge variant="secondary">
<X className="h-3 w-3 mr-1" />Đã tắt
</Badge>
)}
</div>
</div>
{children.length > 0 && (
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-2 mt-3 pl-4 border-l-2 border-muted">
{children.map((child) => (
<div key={child.permisionId} className="flex items-center justify-between p-2 rounded bg-muted/50">
<div className="flex flex-col">
<span className="text-sm font-medium">{child.permissionName}</span>
<span className="text-xs text-muted-foreground">{child.permissionCode}</span>
</div>
{child.isChecked === 1 ? (
<Check className="h-4 w-4 text-green-600" />
) : (
<X className="h-4 w-4 text-muted-foreground" />
)}
</div>
))}
</div>
)}
</div>
))}
</div>
)}
</CardContent>
</Card>
</div>
);
}