// components/permissions/permission-group-assignment-manager.tsx "use client"; import { useState, useEffect } from "react"; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; import { Button } from "@/components/ui/button"; import { Badge } from "@/components/ui/badge"; import { Input } from "@/components/ui/input"; import { Checkbox } from "@/components/ui/checkbox"; import { ScrollArea } from "@/components/ui/scroll-area"; import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, } from "@/components/ui/dialog"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select"; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from "@/components/ui/table"; import { Users, User, Plus, X, Search, Package, Shield, Loader2, UserPlus, ChevronRight } from "lucide-react"; import { toast } from "sonner"; import { cn } from "@/lib/utils"; import { getPermissionGroupAssignments, assignGroupToRoles, assignGroupToUsers, removeGroupFromRole, removeGroupFromUser, searchRoles, searchUsers, } from "@/lib/permissions/permission-group-assignment-actions"; interface PermissionGroup { id: number; groupKey: string; name: string; description?: string; domain?: string; permissionCount: number; isActive: boolean; } interface AssignedRole { id: number; name: string; domain: string; userCount: number; assignedAt: Date; assignedBy?: string; } interface AssignedUser { id: number; name: string; email: string; imageUrl?: string; domain: string; companyName?: string; assignedAt: Date; assignedBy?: string; } export function PermissionGroupAssignmentManager() { const [groups, setGroups] = useState([]); const [selectedGroup, setSelectedGroup] = useState(null); const [assignedRoles, setAssignedRoles] = useState([]); const [assignedUsers, setAssignedUsers] = useState([]); const [searchQuery, setSearchQuery] = useState(""); const [loading, setLoading] = useState(false); const [addRoleDialogOpen, setAddRoleDialogOpen] = useState(false); const [addUserDialogOpen, setAddUserDialogOpen] = useState(false); useEffect(() => { loadGroups(); }, []); useEffect(() => { if (selectedGroup) { loadAssignments(selectedGroup.id); } }, [selectedGroup]); const loadGroups = async () => { setLoading(true); try { const data = await getPermissionGroupAssignments(); setGroups(data.groups); } catch (error) { toast.error("권한 그룹을 불러오는데 실패했습니다."); } finally { setLoading(false); } }; const loadAssignments = async (groupId: number) => { try { const data = await getPermissionGroupAssignments(groupId); setAssignedRoles(data.roles); setAssignedUsers(data.users); } catch (error) { toast.error("할당 정보를 불러오는데 실패했습니다."); } }; const handleRemoveRole = async (roleId: number) => { if (!selectedGroup) return; try { await removeGroupFromRole(selectedGroup.id, roleId); toast.success("역할에서 권한 그룹이 제거되었습니다."); loadAssignments(selectedGroup.id); } catch (error) { toast.error("권한 그룹 제거에 실패했습니다."); } }; const handleRemoveUser = async (userId: number) => { if (!selectedGroup) return; try { await removeGroupFromUser(selectedGroup.id, userId); toast.success("사용자에서 권한 그룹이 제거되었습니다."); loadAssignments(selectedGroup.id); } catch (error) { toast.error("권한 그룹 제거에 실패했습니다."); } }; // 그룹 필터링 const filteredGroups = groups.filter(g => g.name.toLowerCase().includes(searchQuery.toLowerCase()) || g.groupKey.toLowerCase().includes(searchQuery.toLowerCase()) || g.description?.toLowerCase().includes(searchQuery.toLowerCase()) ); return (
{/* 권한 그룹 목록 */} 권한 그룹 할당을 관리할 권한 그룹을 선택하세요.
{/* 검색 */}
setSearchQuery(e.target.value)} className="pl-8" />
{/* 그룹 목록 */} {loading ? (
) : (
{filteredGroups.map(group => ( ))}
)}
{/* 할당 관리 */} {selectedGroup ? (
{selectedGroup.name}
{selectedGroup.groupKey} {selectedGroup.domain && ( {selectedGroup.domain} )} {selectedGroup.permissionCount}개 권한
역할 ({assignedRoles.length}) 사용자 ({assignedUsers.length})
{assignedRoles.map((role) => (
{role.name}
{role.domain} • {role.userCount}명 사용자
{new Date(role.assignedAt).toLocaleDateString()} 할당 {role.assignedBy && ` • ${role.assignedBy}`}
))} {assignedRoles.length === 0 && (

할당된 역할이 없습니다.

)}
{assignedUsers.map((user) => (
{user.name[0]}
{user.name}
{user.email}
{user.domain} {user.companyName && ( {user.companyName} )}
))} {assignedUsers.length === 0 && (

할당된 사용자가 없습니다.

)}
) : (

권한 그룹을 선택하면 할당 정보가 표시됩니다.

)} {/* 역할 추가 다이얼로그 */} {selectedGroup && ( { setAddRoleDialogOpen(false); loadAssignments(selectedGroup.id); }} /> )} {/* 사용자 추가 다이얼로그 */} {selectedGroup && ( { setAddUserDialogOpen(false); loadAssignments(selectedGroup.id); }} /> )}
); } // 역할 추가 다이얼로그 function AddRoleDialog({ open, onOpenChange, group, onSuccess, }: { open: boolean; onOpenChange: (open: boolean) => void; group: PermissionGroup; onSuccess: () => void; }) { const [availableRoles, setAvailableRoles] = useState([]); const [selectedRoles, setSelectedRoles] = useState([]); const [loading, setLoading] = useState(false); const [saving, setSaving] = useState(false); useEffect(() => { if (open) { loadAvailableRoles(); } }, [open]); const loadAvailableRoles = async () => { setLoading(true); try { const data = await searchRoles(group.id); setAvailableRoles(data); } catch (error) { toast.error("역할 목록을 불러오는데 실패했습니다."); } finally { setLoading(false); } }; const handleSubmit = async () => { if (selectedRoles.length === 0) { toast.error("역할을 선택해주세요."); return; } setSaving(true); try { await assignGroupToRoles(group.id, selectedRoles); toast.success("역할에 권한 그룹이 추가되었습니다."); onSuccess(); } catch (error) { toast.error("권한 그룹 추가에 실패했습니다."); } finally { setSaving(false); } }; return ( 역할 추가 "{group.name}" 그룹을 할당할 역할을 선택하세요. {loading ? (
) : (
{availableRoles.map((role) => ( ))}
{selectedRoles.length}개 역할 선택됨
)}
); } // 사용자 추가 다이얼로그 function AddUserDialog({ open, onOpenChange, group, onSuccess, }: { open: boolean; onOpenChange: (open: boolean) => void; group: PermissionGroup; onSuccess: () => void; }) { const [searchQuery, setSearchQuery] = useState(""); const [availableUsers, setAvailableUsers] = useState([]); const [selectedUsers, setSelectedUsers] = useState([]); const [loading, setLoading] = useState(false); const [saving, setSaving] = useState(false); useEffect(() => { const timer = setTimeout(() => { if (searchQuery && open) { searchUsersData(searchQuery); } }, 300); return () => clearTimeout(timer); }, [searchQuery, open]); const searchUsersData = async (query: string) => { setLoading(true); try { const data = await searchUsers(query, group.id); setAvailableUsers(data); } catch (error) { toast.error("사용자 검색에 실패했습니다."); } finally { setLoading(false); } }; const handleSubmit = async () => { if (selectedUsers.length === 0) { toast.error("사용자를 선택해주세요."); return; } setSaving(true); try { await assignGroupToUsers(group.id, selectedUsers); toast.success("사용자에게 권한 그룹이 추가되었습니다."); onSuccess(); } catch (error) { toast.error("권한 그룹 추가에 실패했습니다."); } finally { setSaving(false); } }; return ( 사용자 추가 "{group.name}" 그룹을 할당할 사용자를 검색하고 선택하세요.
{/* 검색 */}
setSearchQuery(e.target.value)} className="pl-8" />
{/* 사용자 목록 */} {loading ? (
) : ( <>
{availableUsers.map((user) => ( ))}
{availableUsers.length > 0 && (
{selectedUsers.length}명 선택됨
)} )}
); }