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

275 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 { LoadingSpinner } from "@/components/ui/LoadingSpinner";
import { Permission } from "@/types/auth";
import { ArrowRight, Plus, Trash2, Check } from "lucide-react";
import { Modal } from "@/components/ui/Modal";
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 { 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 <LoadingSpinner />;
if (!role) return <div className="text-red-600">نقش یافت نشد</div>;
const assignedPermissionIds = rolePermissions?.map(p => p.id) || [];
const availablePermissions = allPermissions?.filter(p => !assignedPermissionIds.includes(p.id)) || [];
return (
<div className="p-6">
<div className="mb-6">
<div className="flex items-center justify-between mb-4">
<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">
مدیریت دسترسیهای نقش
</h1>
<p className="text-gray-600 dark:text-gray-400">
{role.title}
</p>
</div>
</div>
<Button
variant="primary"
onClick={() => setShowAssignModal(true)}
className="flex items-center gap-2"
disabled={availablePermissions.length === 0}
>
<Plus className="h-4 w-4" />
اختصاص دسترسی جدید
</Button>
</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">
دسترسیهای تخصیص یافته ({assignedPermissionIds.length})
</h2>
</div>
<div className="p-6">
{permissionsLoading ? (
<div className="flex justify-center">
<LoadingSpinner />
</div>
) : (
<div className="space-y-3">
{rolePermissions && 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="flex justify-center">
<LoadingSpinner />
</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>
{/* Assign Permission Modal */}
<Modal
isOpen={showAssignModal}
onClose={() => setShowAssignModal(false)}
title="اختصاص دسترسی جدید"
size="lg"
>
<div className="space-y-4">
<p className="text-gray-600 dark:text-gray-300">
دسترسی مورد نظر را برای تخصیص به نقش "{role.title}" انتخاب کنید:
</p>
<div className="max-h-96 overflow-y-auto space-y-3">
{availablePermissions.map((permission: Permission) => (
<div
key={permission.id}
className="flex items-center justify-between p-3 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);
setShowAssignModal(false);
}}
className="flex items-center gap-1"
>
<Check className="h-3 w-3" />
انتخاب
</Button>
</div>
))}
</div>
<div className="flex justify-end gap-3 pt-4">
<Button variant="secondary" onClick={() => setShowAssignModal(false)}>
انصراف
</Button>
</div>
</div>
</Modal>
{/* Remove Permission Confirmation Modal */}
<Modal
isOpen={!!removePermissionId}
onClose={cancelRemovePermission}
title="تأیید حذف دسترسی"
size="sm"
>
<div className="space-y-4">
<p className="text-gray-600 dark:text-gray-300">
آیا از حذف این دسترسی از نقش اطمینان دارید؟
</p>
<div className="flex justify-end gap-3">
<Button variant="secondary" onClick={cancelRemovePermission}>
انصراف
</Button>
<Button
variant="danger"
onClick={confirmRemovePermission}
loading={removing}
>
حذف دسترسی
</Button>
</div>
</div>
</Modal>
</div>
);
};
export default RolePermissionsPage;