import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import type { AxiosError } from "axios"; import { Plus, Search, ShieldCheck, Trash2, UserPlus, Users, } from "lucide-react"; import { useState } from "react"; import { useParams } from "react-router-dom"; import { toast } from "sonner"; 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, DialogHeader, DialogTitle, DialogTrigger, } from "../../../components/ui/dialog"; import { Input } from "../../../components/ui/input"; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from "../../../components/ui/table"; import { addTenantAdmin, fetchTenantAdmins, fetchUsers, removeTenantAdmin, } from "../../../lib/adminApi"; import { t } from "../../../lib/i18n"; export function TenantAdminsTab() { const { tenantId } = useParams<{ tenantId: string }>(); const queryClient = useQueryClient(); const [searchTerm, setSearchTerm] = useState(""); const [isDialogOpen, setIsAddDialogOpen] = useState(false); if (!tenantId) return null; // 현재 관리자 목록 조회 const adminsQuery = useQuery({ queryKey: ["tenant-admins", tenantId], queryFn: () => fetchTenantAdmins(tenantId), enabled: !!tenantId, }); // 사용자 검색 조회 (2자 이상 입력 시) const usersQuery = useQuery({ queryKey: ["admin-users-search", searchTerm], queryFn: () => fetchUsers(20, 0, searchTerm), enabled: isDialogOpen && searchTerm.length >= 2, }); const addMutation = useMutation({ mutationFn: (userId: string) => addTenantAdmin(tenantId, userId), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ["tenant-admins", tenantId] }); toast.success( t("msg.admin.tenants.admins.add_success", "관리자가 추가되었습니다."), ); setSearchTerm(""); }, onError: (err: AxiosError<{ error?: string }>) => { toast.error( err.response?.data?.error || t("msg.common.error", "오류가 발생했습니다."), ); }, }); const removeMutation = useMutation({ mutationFn: (userId: string) => removeTenantAdmin(tenantId, userId), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ["tenant-admins", tenantId] }); toast.success( t("msg.admin.tenants.admins.remove_success", "권한이 회수되었습니다."), ); }, onError: (err: AxiosError<{ error?: string }>) => { toast.error( err.response?.data?.error || t("msg.common.error", "오류가 발생했습니다."), ); }, }); const handleAddAdmin = (userId: string) => { addMutation.mutate(userId); }; const handleRemoveAdmin = (userId: string, userName: string) => { if ( window.confirm( t( "msg.admin.tenants.admins.remove_confirm", "관리자를 삭제하시겠습니까?", { name: userName }, ), ) ) { removeMutation.mutate(userId); } }; const currentAdmins = adminsQuery.data || []; const searchResults = usersQuery.data?.items || []; return (
{t("ui.admin.tenants.admins.title", "테넌트 관리자")} {t( "msg.admin.tenants.admins.subtitle", "이 테넌트의 자원을 관리할 수 있는 사용자 목록입니다.", )}
{ setIsAddDialogOpen(open); if (!open) setSearchTerm(""); }} > {t("ui.admin.tenants.admins.dialog_title", "새 관리자 추가")} {t( "ui.admin.tenants.admins.dialog_description", "이름 또는 이메일로 사용자를 검색하세요.", )}
setSearchTerm(e.target.value)} />
{searchTerm.length < 2 ? (

{t( "ui.admin.tenants.admins.dialog_search_hint", "검색어를 입력해 주세요.", )}

) : usersQuery.isLoading ? (
) : searchResults.length === 0 ? (
{t( "ui.admin.tenants.admins.dialog_no_results", "검색 결과가 없습니다.", )}
) : (
{searchResults.map((user) => { const isAlreadyAdmin = currentAdmins.some( (a) => a.id === user.id, ); return (
{user.name.charAt(0)}
{user.name} {user.email}
); })}
)}
{t("ui.admin.tenants.admins.table_name", "이름")} {t("ui.admin.tenants.admins.table_email", "이메일")} {t("ui.admin.tenants.admins.table_actions", "액션")} {adminsQuery.isLoading ? (
) : currentAdmins.length === 0 ? (

{t( "msg.admin.tenants.admins.empty", "등록된 관리자가 없습니다.", )}

) : ( currentAdmins.map((admin) => (
{admin.name.charAt(0)}
{admin.name}
{admin.email}
)) )}
); } export default TenantAdminsTab;