From 1a2241c40e10193c5ff7008a7b7b36cc1d855d96 Mon Sep 17 00:00:00 2001 From: joonhoekim <26rote@gmail.com> Date: Tue, 25 Mar 2025 15:55:45 +0900 Subject: initial commit --- components/system/permissionDialog.tsx | 301 +++++++++++++++++++++++++++++++++ 1 file changed, 301 insertions(+) create mode 100644 components/system/permissionDialog.tsx (limited to 'components/system/permissionDialog.tsx') diff --git a/components/system/permissionDialog.tsx b/components/system/permissionDialog.tsx new file mode 100644 index 00000000..f7247672 --- /dev/null +++ b/components/system/permissionDialog.tsx @@ -0,0 +1,301 @@ +"use client" + +import * as React from "react" +import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter } from "@/components/ui/dialog" +import { Checkbox } from "@/components/ui/checkbox" +import { Button } from "@/components/ui/button" +import { Tooltip, TooltipTrigger, TooltipContent } from "@/components/ui/tooltip" +import { RoleView } from "@/db/schema/users" +import { + getAllRoleView, + getMenuPermissions, + upsertPermissions +} from "@/lib/roles/services" +import { useToast } from "@/hooks/use-toast" +import { Loader } from "lucide-react" +import { permissionLabelMap } from "@/config/permissionsConfig" + +interface PermissionDialogProps { + open: boolean + onOpenChange: (val: boolean) => void + itemKey?: string + itemTitle?: string +} + +export function PermissionDialog({ + open, + onOpenChange, + itemKey, + itemTitle, +}: PermissionDialogProps) { + // **(A)**: 체크박스에 의해 새로 추가할 권한(perms) + const [permissions, setPermissions] = React.useState([]) + + // **(B)**: 체크된 Roles(새로 부여할 대상) + const [selectedRoles, setSelectedRoles] = React.useState([]) + + // **(C)**: 전체 Role 목록 + const [roles, setRoles] = React.useState([]) + + // **(D)**: Role별 이미 존재하는 권한들 → UI 표시용 + const [rolePermsMap, setRolePermsMap] = React.useState>({}) + + const { toast } = useToast() + const [isPending, startTransition] = React.useTransition() + + // 1) Role 목록 로드 + React.useEffect(() => { + getAllRoleView("evcp").then((res) => { + setRoles(res) + }) + }, []) + + // 2) Dialog 열릴 때 → DB에서 “이미 부여된 권한” 로드 + React.useEffect(() => { + if (open && itemKey) { + // 기존에 어떤 Role들이 itemKey 퍼미션을 가지고 있는지 + getMenuPermissions(itemKey).then((rows) => { + // rows: { roleId, permKey: "itemKey.xxx" } + // rolePermsMap[r.roleId] = ["create","viewAll",...] + const rMap: Record = {} + for (const row of rows) { + const splitted = row.permKey.split(".") + const shortPerm = splitted[1] + if (!rMap[row.roleId]) { + rMap[row.roleId] = [] + } + rMap[row.roleId].push(shortPerm) + } + setRolePermsMap(rMap) + + // 권한 체크박스(permissions)와 selectedRoles는 + // "항상 비어있는 상태"로 시작 (새로 추가할 용도) + setPermissions([]) + setSelectedRoles([]) + }) + } else if (!open) { + // Dialog가 닫힐 때 리셋 + setPermissions([]) + setSelectedRoles([]) + setRolePermsMap({}) + } + }, [open, itemKey]) + + // Checkbox toggle: 권한 + function togglePermission(perm: string) { + setPermissions((prev) => + prev.includes(perm) ? prev.filter((p) => p !== perm) : [...prev, perm] + ) + } + + // Checkbox toggle: Role + function toggleRole(roleId: number) { + setSelectedRoles((prev) => + prev.includes(roleId) ? prev.filter((p) => p !== roleId) : [...prev, roleId] + ) + } + + async function handleSave() { + if (!itemKey) { + toast({ + variant: "destructive", + title: "오류", + description: "선택한 메뉴가 없어 권한을 생성할 수 없습니다.", + }) + onOpenChange(false) + return + } + + // permission_key = itemKey.perm + const permissionKeys = permissions.map((perm) => `${itemKey}.${perm}`) + + startTransition(async () => { + try { + await upsertPermissions({ + roleIds: selectedRoles, + permissionKeys, + itemTitle, + }) + + toast({ + variant: "default", + title: "권한 설정 완료", + description: "새 권한이 정상적으로 설정되었습니다.", + }) + setPermissions([]) + setSelectedRoles([]) + setRolePermsMap({}) + onOpenChange(false) + } catch (err) { + toast({ + variant: "destructive", + title: "오류", + description: "권한 설정에 실패했습니다. 다시 시도해주세요.", + }) + } + }) + } + + function handleCancel() { + setPermissions([]) + setSelectedRoles([]) + setRolePermsMap({}) + onOpenChange(false) + } + + const isDisabled = isPending + + return ( + + + + + 권한 설정 - {itemTitle} + + + +
+ {/* 1) Role 표시: 이미 가진 권한은 slash 구분 */} +
+

Role & 이미 부여된 권한

+
+ {roles.map((r) => { + const existPerms = rolePermsMap[r.id] || [] + const permsText = existPerms + .map((perm) => permissionLabelMap[perm] ?? perm) + // ↑ 매핑에 없는 키일 경우 대비해 ?? perm 로 처리 + .join(" / ") + + return ( +
+ toggleRole(r.id)} + disabled={isDisabled} + /> + + + + {r.name} + + + + {r.description ?? "No description"} + + + {/* 이미 가진 권한 텍스트 */} + {permsText && ( + + {permsText} + + )} +
+ ) + })} +
+
+ + {/* 2) 새 권한 체크박스 */} +
+

새로 부여할 권한

+
+ {/* 왼쪽 */} +
+ {/* 생성 */} +
+

생성

+
+ togglePermission("create")} + disabled={isDisabled} + /> + {permissionLabelMap["create"]} +
+
+ + {/* 보기 */} +
+

보기

+
+ togglePermission("viewAll")} + disabled={isDisabled} + /> + {permissionLabelMap["viewAll"]} +
+
+ togglePermission("viewOwn")} + disabled={isDisabled} + /> + {permissionLabelMap["viewOwn"]} +
+
+
+ + {/* 오른쪽 */} +
+ {/* 편집 */} +
+

편집

+
+ togglePermission("editAll")} + disabled={isDisabled} + /> + {permissionLabelMap["editAll"]} +
+
+ togglePermission("editOwn")} + disabled={isDisabled} + /> + {permissionLabelMap["editOwn"]} +
+
+ + {/* 삭제 */} +
+

삭제

+
+ togglePermission("deleteAll")} + disabled={isDisabled} + /> + {permissionLabelMap["deleteAll"]} +
+
+ togglePermission("deleteOwn")} + disabled={isDisabled} + /> + {permissionLabelMap["deleteOwn"]} +
+
+
+
+
+
+ + + + + +
+
+ ) +} \ No newline at end of file -- cgit v1.2.3