admin/src/pages/roles/role-permissions/RolePermissionsPage.tsx

247 lines
13 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { useState } from "react";
import { useNavigate, useParams } from "react-router-dom";
import { useRole, useRolePermissions, usePermissions, useAssignPermission, useRemovePermission } from "../core/_hooks";
import { Button } from "@/components/ui/Button";
import { Permission } from "@/types/auth";
import { ArrowRight, Plus, Trash2, Check, Shield } from "lucide-react";
import { Modal } from "@/components/ui/Modal";
import { PageContainer } from "@/components/ui/Typography";
const RolePermissionsPage = () => {
const navigate = useNavigate();
const { id = "" } = useParams();
const [showAssignModal, setShowAssignModal] = useState(false);
const [removePermissionId, setRemovePermissionId] = useState<string | null>(null);
const { data: role, isLoading: roleLoading } = useRole(id);
const { data: rolePermissions, isLoading: permissionsLoading } = useRolePermissions(id);
const { data: allPermissions, isLoading: allPermissionsLoading } = usePermissions();
const assignedPermissionIds = (rolePermissions || []).map(p => p.id);
// Access the permissions array from the object structure
const safeAllPermissions = Array.isArray((allPermissions as any)?.permissions) ? (allPermissions as any).permissions : [];
const availablePermissions = safeAllPermissions.filter((p: any) => !assignedPermissionIds.includes(p.id));
const { mutate: assignPermission, isPending: assigning } = useAssignPermission();
const { mutate: removePermission, isPending: removing } = useRemovePermission();
const handleAssignPermission = (permissionId: number) => {
assignPermission({
roleId: id,
permissionId: permissionId.toString(),
});
};
const handleRemovePermission = (permissionId: number) => {
setRemovePermissionId(permissionId.toString());
};
const confirmRemovePermission = () => {
if (removePermissionId) {
removePermission({
roleId: id,
permissionId: removePermissionId,
}, {
onSuccess: () => {
setRemovePermissionId(null);
}
});
}
};
const cancelRemovePermission = () => {
setRemovePermissionId(null);
};
const isLoading = roleLoading || permissionsLoading;
if (isLoading) {
return (
<PageContainer>
<div className="space-y-6 animate-pulse">
<div className="h-8 bg-gray-200 dark:bg-gray-700 rounded w-64"></div>
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
{[...Array(2)].map((_, i) => (
<div key={i} className="card">
<div className="p-6 border-b border-gray-200 dark:border-gray-700">
<div className="h-6 bg-gray-200 dark:bg-gray-700 rounded w-48"></div>
</div>
<div className="p-6 space-y-3">
{[...Array(5)].map((_, j) => (
<div key={j} className="h-12 bg-gray-200 dark:bg-gray-700 rounded"></div>
))}
</div>
</div>
))}
</div>
</div>
</PageContainer>
);
}
if (!role) return <div className="text-red-600">نقش یافت نشد</div>;
return (
<PageContainer>
<div className="space-y-6">
{/* Header */}
<div className="flex items-center gap-4">
<Button
variant="secondary"
onClick={() => navigate('/roles')}
className="flex items-center gap-2"
>
<ArrowRight className="h-4 w-4" />
بازگشت
</Button>
<div>
<h1 className="text-2xl font-bold text-gray-900 dark:text-gray-100">
مدیریت دسترسیهای نقش: {role?.title}
</h1>
<p className="text-gray-600 dark:text-gray-400 mt-1">
تخصیص و حذف دسترسیها برای این نقش
</p>
</div>
</div>
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
{/* دسترسی‌های تخصیص یافته */}
<div className="bg-white dark:bg-gray-800 rounded-lg shadow-md">
<div className="p-6 border-b border-gray-200 dark:border-gray-700">
<h2 className="text-lg font-semibold text-gray-900 dark:text-gray-100">
دسترسیهای تخصیص یافته ({(rolePermissions || []).length})
</h2>
</div>
<div className="p-6">
{permissionsLoading ? (
<div className="space-y-3 animate-pulse">
{[...Array(5)].map((_, i) => (
<div key={i} className="h-12 bg-gray-200 dark:bg-gray-700 rounded"></div>
))}
</div>
) : (
<div className="space-y-3">
{(rolePermissions || []).length > 0 ? (
(rolePermissions || []).map((permission: Permission) => (
<div
key={permission.id}
className="flex items-center justify-between p-3 bg-green-50 dark:bg-green-900/20 border border-green-200 dark:border-green-800 rounded-lg"
>
<div className="flex-1">
<h4 className="font-medium text-green-900 dark:text-green-100">
{permission.title}
</h4>
<p className="text-sm text-green-700 dark:text-green-300">
{permission.description}
</p>
</div>
<Button
size="sm"
variant="danger"
onClick={() => handleRemovePermission(permission.id)}
className="flex items-center gap-1 ml-3"
>
<Trash2 className="h-3 w-3" />
حذف
</Button>
</div>
))
) : (
<p className="text-center text-gray-500 dark:text-gray-400 py-8">
هیچ دسترسی تخصیص داده نشده است
</p>
)}
</div>
)}
</div>
</div>
{/* دسترسی‌های در دسترس */}
<div className="bg-white dark:bg-gray-800 rounded-lg shadow-md">
<div className="p-6 border-b border-gray-200 dark:border-gray-700">
<h2 className="text-lg font-semibold text-gray-900 dark:text-gray-100">
دسترسیهای قابل تخصیص ({availablePermissions.length})
</h2>
</div>
<div className="p-6">
{allPermissionsLoading ? (
<div className="space-y-3 animate-pulse">
{[...Array(5)].map((_, i) => (
<div key={i} className="h-12 bg-gray-200 dark:bg-gray-700 rounded"></div>
))}
</div>
) : (
<div className="space-y-3">
{availablePermissions.length > 0 ? (
availablePermissions.map((permission: Permission) => (
<div
key={permission.id}
className="flex items-center justify-between p-3 bg-gray-50 dark:bg-gray-700 border border-gray-200 dark:border-gray-600 rounded-lg"
>
<div className="flex-1">
<h4 className="font-medium text-gray-900 dark:text-gray-100">
{permission.title}
</h4>
<p className="text-sm text-gray-600 dark:text-gray-400">
{permission.description}
</p>
</div>
<Button
size="sm"
variant="primary"
onClick={() => handleAssignPermission(permission.id)}
className="flex items-center gap-1 ml-3"
loading={assigning}
>
<Plus className="h-3 w-3" />
اختصاص
</Button>
</div>
))
) : (
<p className="text-center text-gray-500 dark:text-gray-400 py-8">
تمام دسترسیها به این نقش تخصیص داده شده است
</p>
)}
</div>
)}
</div>
</div>
</div>
{/* Modal تأیید حذف دسترسی */}
<Modal
isOpen={!!removePermissionId}
onClose={() => setRemovePermissionId(null)}
title="حذف دسترسی"
>
<div className="space-y-4">
<p className="text-gray-600 dark:text-gray-400">
آیا از حذف این دسترسی از نقش اطمینان دارید؟
</p>
<div className="flex justify-end space-x-2 space-x-reverse">
<Button
variant="secondary"
onClick={() => setRemovePermissionId(null)}
disabled={removing}
>
انصراف
</Button>
<Button
variant="danger"
onClick={confirmRemovePermission}
loading={removing}
>
حذف
</Button>
</div>
</div>
</Modal>
</div>
</PageContainer>
);
};
export default RolePermissionsPage;