152 lines
6.0 KiB
JavaScript
Executable File
152 lines
6.0 KiB
JavaScript
Executable File
// File: frontend/app/(protected)/admin/_components/role-form-dialog.jsx
|
|
'use client';
|
|
|
|
import { useState, useEffect } from 'react';
|
|
import { api } from '@/lib/api';
|
|
import { Button } from '@/components/ui/button';
|
|
import {
|
|
Dialog,
|
|
DialogContent,
|
|
DialogHeader,
|
|
DialogTitle,
|
|
DialogDescription,
|
|
DialogFooter,
|
|
} from '@/components/ui/dialog';
|
|
import { Input } from '@/components/ui/input';
|
|
import { Label } from '@/components/ui/label';
|
|
import { Checkbox } from '@/components/ui/checkbox';
|
|
import { ScrollArea } from '@/components/ui/scroll-area';
|
|
|
|
export function RoleFormDialog({ role, allPermissions, isOpen, setIsOpen, onSuccess }) {
|
|
const [formData, setFormData] = useState({ name: '', description: '' });
|
|
const [selectedPermissions, setSelectedPermissions] = useState(new Set());
|
|
const [isLoading, setIsLoading] = useState(false);
|
|
const [error, setError] = useState('');
|
|
|
|
const isEditMode = !!role;
|
|
|
|
useEffect(() => {
|
|
// Reset state ทุกครั้งที่ dialog เปิดขึ้นมาใหม่
|
|
if (isOpen) {
|
|
if (isEditMode) {
|
|
// โหมดแก้ไข: ตั้งค่าฟอร์มด้วยข้อมูล Role ที่มีอยู่
|
|
setFormData({ name: role.name, description: role.description || '' });
|
|
setSelectedPermissions(new Set(role.Permissions?.map(p => p.id) || []));
|
|
} else {
|
|
// โหมดสร้างใหม่: เคลียร์ฟอร์ม
|
|
setFormData({ name: '', description: '' });
|
|
setSelectedPermissions(new Set());
|
|
}
|
|
setError('');
|
|
}
|
|
}, [role, isOpen]); // ให้ re-run effect นี้เมื่อ role หรือ isOpen เปลี่ยน
|
|
|
|
const handleInputChange = (e) => {
|
|
const { id, value } = e.target;
|
|
setFormData((prev) => ({ ...prev, [id]: value }));
|
|
};
|
|
|
|
const handlePermissionChange = (permissionId) => {
|
|
setSelectedPermissions(prev => {
|
|
const newSet = new Set(prev);
|
|
if (newSet.has(permissionId)) {
|
|
newSet.delete(permissionId);
|
|
} else {
|
|
newSet.add(permissionId);
|
|
}
|
|
return newSet;
|
|
});
|
|
};
|
|
|
|
const handleSubmit = async (e) => {
|
|
e.preventDefault();
|
|
setIsLoading(true);
|
|
setError('');
|
|
|
|
try {
|
|
if (isEditMode) {
|
|
// โหมดแก้ไข: อัปเดต Permissions ของ Role ที่มีอยู่
|
|
await api.put(`/rbac/roles/${role.id}/permissions`, {
|
|
permissionIds: Array.from(selectedPermissions)
|
|
});
|
|
} else {
|
|
// โหมดสร้างใหม่: สร้าง Role ใหม่ก่อน
|
|
const newRoleRes = await api.post('/rbac/roles', formData);
|
|
|
|
// ถ้าสร้าง Role สำเร็จ และมีการเลือก Permission ไว้ ให้ทำการผูกสิทธิ์ทันที
|
|
if (newRoleRes.data && selectedPermissions.size > 0) {
|
|
await api.put(`/rbac/roles/${newRoleRes.data.id}/permissions`, {
|
|
permissionIds: Array.from(selectedPermissions)
|
|
});
|
|
}
|
|
}
|
|
onSuccess(); // บอกให้หน้าแม่ (roles/page.jsx) โหลดข้อมูลใหม่
|
|
setIsOpen(false); // ปิด Dialog
|
|
} catch (err) {
|
|
setError(err.response?.data?.message || 'An unexpected error occurred.');
|
|
} finally {
|
|
setIsLoading(false);
|
|
}
|
|
};
|
|
|
|
return (
|
|
<Dialog open={isOpen} onOpenChange={setIsOpen}>
|
|
<DialogContent className="sm:max-w-md">
|
|
<form onSubmit={handleSubmit}>
|
|
<DialogHeader>
|
|
<DialogTitle>{isEditMode ? `Edit Permissions for: ${role.name}` : 'Create New Role'}</DialogTitle>
|
|
<DialogDescription>
|
|
{isEditMode ? 'Select the permissions for this role.' : 'Define a new role and its initial permissions.'}
|
|
</DialogDescription>
|
|
</DialogHeader>
|
|
|
|
<div className="py-4 space-y-4">
|
|
{/* แสดงฟอร์มสำหรับชื่อและคำอธิบายเฉพาะตอนสร้างใหม่ */}
|
|
{!isEditMode && (
|
|
<>
|
|
<div className="space-y-1">
|
|
<Label htmlFor="name">Role Name</Label>
|
|
<Input id="name" value={formData.name} onChange={handleInputChange} required />
|
|
</div>
|
|
<div className="space-y-1">
|
|
<Label htmlFor="description">Description</Label>
|
|
<Input id="description" value={formData.description} onChange={handleInputChange} />
|
|
</div>
|
|
</>
|
|
)}
|
|
|
|
<div>
|
|
<Label>Permissions</Label>
|
|
<ScrollArea className="h-60 w-full rounded-md border p-4 mt-1">
|
|
<div className="space-y-2">
|
|
{allPermissions.map(perm => (
|
|
<div key={perm.id} className="flex items-center space-x-2">
|
|
<Checkbox
|
|
id={`perm-${perm.id}`}
|
|
checked={selectedPermissions.has(perm.id)}
|
|
onCheckedChange={() => handlePermissionChange(perm.id)}
|
|
/>
|
|
<label htmlFor={`perm-${perm.id}`} className="text-sm font-medium leading-none cursor-pointer">
|
|
{perm.name}
|
|
</label>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</ScrollArea>
|
|
</div>
|
|
</div>
|
|
|
|
{error && <p className="text-sm text-red-500 text-center pb-2">{error}</p>}
|
|
<DialogFooter>
|
|
<Button type="button" variant="outline" onClick={() => setIsOpen(false)} disabled={isLoading}>
|
|
Cancel
|
|
</Button>
|
|
<Button type="submit" disabled={isLoading}>
|
|
{isLoading ? 'Saving...' : 'Save Changes'}
|
|
</Button>
|
|
</DialogFooter>
|
|
</form>
|
|
</DialogContent>
|
|
</Dialog>
|
|
);
|
|
} |