diff options
| author | dujinkim <dujin.kim@dtsolution.co.kr> | 2025-09-26 09:57:24 +0000 |
|---|---|---|
| committer | dujinkim <dujin.kim@dtsolution.co.kr> | 2025-09-26 09:57:24 +0000 |
| commit | 8b23b471638a155fd1bfa3a8c853b26d9315b272 (patch) | |
| tree | 47353e9dd342011cb2f1dcd24b09661707a8421b /components/permissions/role-permission-manager.tsx | |
| parent | d62368d2b68d73da895977e60a18f9b1286b0545 (diff) | |
(대표님) 권한관리, 문서업로드, rfq첨부, SWP문서룰 등
(최겸) 입찰
Diffstat (limited to 'components/permissions/role-permission-manager.tsx')
| -rw-r--r-- | components/permissions/role-permission-manager.tsx | 178 |
1 files changed, 178 insertions, 0 deletions
diff --git a/components/permissions/role-permission-manager.tsx b/components/permissions/role-permission-manager.tsx new file mode 100644 index 00000000..b229ec57 --- /dev/null +++ b/components/permissions/role-permission-manager.tsx @@ -0,0 +1,178 @@ +// components/permissions/role-permission-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 { Checkbox } from "@/components/ui/checkbox"; +import { Badge } from "@/components/ui/badge"; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "@/components/ui/select"; +import { + Table, + TableBody, + TableCell, + TableHead, + TableHeader, + TableRow, +} from "@/components/ui/table"; +import { toast } from "sonner"; +import { assignPermissionsToRole, getRolePermissions } from "@/lib/permissions/service"; + +export function RolePermissionManager() { + const [selectedRole, setSelectedRole] = useState<string>(""); + const [permissions, setPermissions] = useState<any[]>([]); + const [selectedPermissions, setSelectedPermissions] = useState<Set<number>>(new Set()); + const [loading, setLoading] = useState(false); + + useEffect(() => { + if (selectedRole) { + loadRolePermissions(selectedRole); + } + }, [selectedRole]); + + const loadRolePermissions = async (roleId: string) => { + try { + const data = await getRolePermissions(parseInt(roleId)); + setPermissions(data.permissions); + setSelectedPermissions(new Set(data.assignedPermissionIds)); + } catch (error) { + toast.error("권한 목록을 불러오는데 실패했습니다."); + } + }; + + const handleSave = async () => { + if (!selectedRole) { + toast.error("역할을 선택해주세요."); + return; + } + + try { + setLoading(true); + await assignPermissionsToRole( + parseInt(selectedRole), + Array.from(selectedPermissions) + ); + toast.success("권한이 성공적으로 저장되었습니다."); + } catch (error) { + toast.error("권한 저장에 실패했습니다."); + } finally { + setLoading(false); + } + }; + + const togglePermission = (permissionId: number) => { + const newSet = new Set(selectedPermissions); + if (newSet.has(permissionId)) { + newSet.delete(permissionId); + } else { + newSet.add(permissionId); + } + setSelectedPermissions(newSet); + }; + + // 권한 그룹별로 정리 + const groupedPermissions = permissions.reduce((acc, perm) => { + const group = perm.menuPath || "기타"; + if (!acc[group]) acc[group] = []; + acc[group].push(perm); + return acc; + }, {} as Record<string, any[]>); + + return ( + <Card> + <CardHeader> + <CardTitle>역할별 권한 설정</CardTitle> + <CardDescription> + 역할을 선택하고 해당 역할에 부여할 권한을 선택하세요. + </CardDescription> + </CardHeader> + <CardContent> + <div className="space-y-6"> + {/* 역할 선택 */} + <div className="flex items-center gap-4"> + <Select value={selectedRole} onValueChange={setSelectedRole}> + <SelectTrigger className="w-[300px]"> + <SelectValue placeholder="역할 선택..." /> + </SelectTrigger> + <SelectContent> + <SelectItem value="1">EVCP Admin</SelectItem> + <SelectItem value="2">EVCP Manager</SelectItem> + <SelectItem value="3">EVCP User</SelectItem> + <SelectItem value="4">Partner Admin</SelectItem> + <SelectItem value="5">Partner User</SelectItem> + </SelectContent> + </Select> + + <Button + onClick={handleSave} + disabled={!selectedRole || loading} + > + 권한 저장 + </Button> + </div> + + {/* 권한 목록 */} + {selectedRole && ( + <div className="border rounded-lg"> + <Table> + <TableHeader> + <TableRow> + <TableHead className="w-[50px]">선택</TableHead> + <TableHead>메뉴/그룹</TableHead> + <TableHead>권한명</TableHead> + <TableHead>타입</TableHead> + <TableHead>범위</TableHead> + <TableHead>설명</TableHead> + </TableRow> + </TableHeader> + <TableBody> + {Object.entries(groupedPermissions).map(([group, perms]) => ( + <> + <TableRow key={group} className="bg-muted/50"> + <TableCell colSpan={6} className="font-medium"> + {group} + </TableCell> + </TableRow> + {perms.map((permission) => ( + <TableRow key={permission.id}> + <TableCell> + <Checkbox + checked={selectedPermissions.has(permission.id)} + onCheckedChange={() => togglePermission(permission.id)} + /> + </TableCell> + <TableCell> + <Badge variant="outline">{permission.resource}</Badge> + </TableCell> + <TableCell className="font-medium"> + {permission.name} + </TableCell> + <TableCell> + <Badge>{permission.permissionType}</Badge> + </TableCell> + <TableCell> + <Badge variant="secondary">{permission.scope}</Badge> + </TableCell> + <TableCell className="text-sm text-muted-foreground"> + {permission.description} + </TableCell> + </TableRow> + ))} + </> + ))} + </TableBody> + </Table> + </div> + )} + </div> + </CardContent> + </Card> + ); +}
\ No newline at end of file |
