// components/permissions/role-selector.tsx "use client" import * as React from "react" import { Check, ChevronsUpDown, Shield, Users } from "lucide-react" import { Button } from "@/components/ui/button" import { Popover, PopoverTrigger, PopoverContent } from "@/components/ui/popover" import { Command, CommandInput, CommandList, CommandEmpty, CommandGroup, CommandItem } from "@/components/ui/command" import { Badge } from "@/components/ui/badge" import { cn } from "@/lib/utils" import { getRoles } from "@/lib/permissions/service" export interface Role { id: number; name: string; domain: string; description?: string; userCount?: number; } interface RoleSelectorProps { selectedRoleId?: number | null; onRoleSelect: (role: Role) => void; placeholder?: string; domain?: string; // 특정 도메인의 역할만 필터링 className?: string; } export function RoleSelector({ selectedRoleId, onRoleSelect, placeholder = "역할 선택...", domain, className }: RoleSelectorProps) { const [open, setOpen] = React.useState(false) const [searchTerm, setSearchTerm] = React.useState("") const [roles, setRoles] = React.useState([]) const [isLoading, setIsLoading] = React.useState(false) const [selectedRole, setSelectedRole] = React.useState(null) // 역할 데이터 로드 React.useEffect(() => { async function loadRoles() { setIsLoading(true); try { const allRoles = await getRoles(); // domain이 지정된 경우 해당 도메인만 필터링 const filteredByDomain = domain ? allRoles.filter((r: Role) => r.domain === domain) : allRoles; console.log(`Loaded ${filteredByDomain.length} roles${domain ? ` for domain: ${domain}` : ''}`); setRoles(filteredByDomain); // 초기 선택된 역할이 있으면 설정 if (selectedRoleId) { const selected = filteredByDomain.find((r: Role) => r.id === selectedRoleId); if (selected) { setSelectedRole(selected); } } } catch (error) { console.error("역할 목록 로드 오류:", error); setRoles([]); } finally { setIsLoading(false); } } loadRoles(); }, [selectedRoleId, domain]); // 클라이언트 측에서 검색어로 필터링 const filteredRoles = React.useMemo(() => { if (!searchTerm.trim()) return roles; const lowerSearch = searchTerm.toLowerCase(); return roles.filter( role => role.name.toLowerCase().includes(lowerSearch) || role.domain.toLowerCase().includes(lowerSearch) || (role.description && role.description.toLowerCase().includes(lowerSearch)) ); }, [roles, searchTerm]); // 역할 선택 처리 const handleSelectRole = (role: Role) => { setSelectedRole(role); onRoleSelect(role); setOpen(false); }; // 도메인별 색상 결정 const getDomainColor = (domain: string) => { switch(domain?.toLowerCase()) { case 'evcp': return 'default'; case 'partners': return 'secondary'; case 'admin': return 'destructive'; default: return 'outline'; } }; // 도메인별 그룹화 const groupedRoles = React.useMemo(() => { return filteredRoles.reduce((acc, role) => { const key = role.domain || 'other'; if (!acc[key]) acc[key] = []; acc[key].push(role); return acc; }, {} as Record); }, [filteredRoles]); return ( { e.stopPropagation(); const target = e.currentTarget; target.scrollTop += e.deltaY; }} > {isLoading ? (
역할 목록 로딩 중...
) : Object.keys(groupedRoles).length === 0 ? ( {searchTerm ? "검색 결과가 없습니다" : domain ? `${domain} 도메인에 역할이 없습니다` : "역할이 없습니다"} ) : ( Object.entries(groupedRoles).map(([groupDomain, groupRoles]) => ( {groupRoles.map((role) => ( handleSelectRole(role)} className="cursor-pointer" >
{role.name}
{role.description && (
{role.description}
)}
{role.userCount !== undefined && ( {role.userCount} )}
))}
)) )}
); }