import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import type { AxiosError } from "axios"; import { ArrowLeft, Shield, Trash2, UserPlus, Users } from "lucide-react"; import { useState } from "react"; import { Link, useParams } from "react-router-dom"; import { toast } from "../../../components/ui/use-toast"; import { Badge } from "../../../components/ui/badge"; import { Button } from "../../../components/ui/button"; import { Card, CardContent, CardDescription, CardHeader, CardTitle, } from "../../../components/ui/card"; import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger, } from "../../../components/ui/dialog"; import { Input } from "../../../components/ui/input"; import { Label } from "../../../components/ui/label"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "../../../components/ui/select"; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from "../../../components/ui/table"; import { addGroupMember, assignGroupRole, fetchGroup, fetchGroupRoles, fetchTenants, fetchUsers, removeGroupMember, removeGroupRole, } from "../../../lib/adminApi"; import { t } from "../../../lib/i18n"; export function UserGroupDetailPage() { const { tenantId, id } = useParams<{ tenantId: string; id: string }>(); const queryClient = useQueryClient(); const [isAddMemberOpen, setIsAddMemberOpen] = useState(false); const [selectedUserId, setSelectedUserId] = useState(""); const [searchUser, setSearchUser] = useState(""); const [isAddRoleOpen, setIsAddRoleOpen] = useState(false); const [selectedTargetTenantId, setSelectedTargetTenantId] = useState(""); const [selectedRelation, setSelectedRelation] = useState("view"); const { data: currentGroup, isLoading: isGroupLoading, error, } = useQuery({ queryKey: ["user-group-detail", id], queryFn: () => fetchGroup(tenantId ?? "", id ?? ""), enabled: !!id && !!tenantId, retry: false, }); // Fetch assigned roles const { data: groupRoles, isLoading: isRolesLoading } = useQuery({ queryKey: ["user-group-roles", id], queryFn: () => fetchGroupRoles(tenantId ?? "", id ?? ""), enabled: !!id && !!tenantId, }); // Fetch all users for selection const { data: userList } = useQuery({ queryKey: ["admin-users", searchUser], queryFn: () => fetchUsers(20, 0, searchUser), enabled: isAddMemberOpen, }); // Fetch all tenants for role assignment const { data: tenantList } = useQuery({ queryKey: ["admin-tenants"], queryFn: () => fetchTenants(100, 0), enabled: isAddRoleOpen, }); const addMemberMutation = useMutation({ mutationFn: (userId: string) => addGroupMember(tenantId ?? "", id ?? "", userId), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ["user-group-detail", id] }); setIsAddMemberOpen(false); setSelectedUserId(""); toast.success( t("msg.admin.groups.members.add_success", "구성원이 추가되었습니다."), ); }, onError: (error: AxiosError<{ error?: string }>) => { toast.error( error.response?.data?.error || error.message || t("err.common.unknown", "오류가 발생했습니다."), ); }, }); const removeMemberMutation = useMutation({ mutationFn: (userId: string) => removeGroupMember(tenantId ?? "", id ?? "", userId), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ["user-group-detail", id] }); toast.success( t( "msg.admin.groups.members.remove_success", "구성원이 제외되었습니다.", ), ); }, }); const assignRoleMutation = useMutation({ mutationFn: () => assignGroupRole( tenantId ?? "", id ?? "", selectedTargetTenantId, selectedRelation, ), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ["user-group-roles", id] }); setIsAddRoleOpen(false); toast.success( t("msg.admin.groups.roles.assign_success", "역할이 할당되었습니다."), ); }, onError: (error: AxiosError<{ error?: string }>) => { toast.error( error.response?.data?.error || error.message || t("err.common.unknown", "오류가 발생했습니다."), ); }, }); const removeRoleMutation = useMutation({ mutationFn: (role: { targetTenantId: string; relation: string }) => removeGroupRole( tenantId ?? "", id ?? "", role.targetTenantId, role.relation, ), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ["user-group-roles", id] }); toast.success( t("msg.admin.groups.roles.remove_success", "역할이 회수되었습니다."), ); }, }); if (isGroupLoading) return (
{t("msg.common.loading", "로딩 중...")}
); if (error || !currentGroup) return (

조직 단위를 불러올 수 없습니다

Error:{" "} {(error as AxiosError<{ error?: string }>)?.response?.data?.error || (error as any)?.message || "Not found"}

{t( "ui.admin.groups.detail.breadcrumb_org", "조직 관리 목록으로 돌아가기", )}
); return (
{t("ui.admin.groups.detail.breadcrumb_tenant", "테넌트 상세")} / {t("ui.admin.groups.detail.breadcrumb_org", "조직 관리")} / {t("ui.admin.groups.detail.breadcrumb_unit", "조직 단위")}

{currentGroup.name}

{currentGroup.unitType && ( {currentGroup.unitType} )}

{currentGroup.description || t("msg.common.no_description", "설명이 없습니다.")}

{t("ui.admin.groups.detail.breadcrumb_unit", "조직 단위")} ID: {id?.split("-")[0]}...
{/* Members Management */}
{t("ui.admin.groups.detail.members_title", "구성원 관리")} {t( "ui.admin.groups.detail.members_subtitle", "이 조직에 소속된 사용자를 관리합니다.", )}
{t("ui.admin.groups.detail.members_title", "구성원 추가")} {t( "ui.admin.groups.detail.members_subtitle", "사용자를 검색하여 조직 구성원으로 추가합니다.", )}
setSearchUser(e.target.value)} />
{t("ui.admin.users.list.table.name_email", "사용자")} {t("ui.admin.groups.table.actions", "액션")} {!currentGroup.members || currentGroup.members.length === 0 ? ( {t( "msg.admin.groups.members.empty", "구성원이 없습니다.", )} ) : ( currentGroup.members.map((member) => (
{member.name.charAt(0)}

{member.name}

{member.email}

)) )}
{/* Roles/Permissions Management (Keto Based) */}
{t("ui.admin.groups.detail.permissions_title", "권한 관리")} {t( "ui.admin.groups.detail.permissions_subtitle", "이 조직이 다른 테넌트에 가지는 역할을 정의합니다.", )}
{t( "ui.admin.groups.detail.permissions_title", "테넌트 역할 할당", )} {t( "msg.admin.groups.roles.description", "이 조직의 구성원들이 대상 테넌트에서 상속받을 역할을 선택하세요.", )}
{t("ui.admin.users.detail.form.tenant", "대상 테넌트")} {t("ui.admin.users.detail.form.role", "역할")} {t("ui.admin.groups.table.actions", "액션")} {isRolesLoading ? (
) : !groupRoles || groupRoles.length === 0 ? ( {t( "msg.admin.groups.roles.empty", "할당된 역할이 없습니다.", )} ) : ( groupRoles.map((role, idx) => (
{role.tenantName || role.tenantId}
{role.relation}
)) )}
); }