146 lines
		
	
	
		
			5.3 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			146 lines
		
	
	
		
			5.3 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| // 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(() => {
 | |
|     if (isOpen) {
 | |
|       if (isEditMode) {
 | |
|         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]);
 | |
| 
 | |
|   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) {
 | |
|         // ในโหมดแก้ไข เราจะอัปเดตสิทธิ์เสมอ
 | |
|         await api.put(`/rbac/roles/${role.id}/permissions`, { 
 | |
|           permissionIds: Array.from(selectedPermissions) 
 | |
|         });
 | |
|         // (Optional) อาจจะเพิ่มการแก้ไขชื่อ/description ของ role ที่นี่ด้วยก็ได้
 | |
|         // await api.put(`/rbac/roles/${role.id}`, { name: formData.name, description: formData.description });
 | |
|       } else {
 | |
|         // ในโหมดสร้างใหม่
 | |
|         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();
 | |
|       setIsOpen(false);
 | |
|     } 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>
 | |
|               Select the permissions for this role.
 | |
|             </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">
 | |
|                         {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="submit" disabled={isLoading}>
 | |
|               {isLoading ? 'Saving...' : 'Save Changes'}
 | |
|             </Button>
 | |
|           </DialogFooter>
 | |
|         </form>
 | |
|       </DialogContent>
 | |
|     </Dialog>
 | |
|   );
 | |
| } | 
