import { useMutation, useQuery } from "@tanstack/react-query"; import type { AxiosError } from "axios"; import { CornerDownRight, Pencil, Plus, RefreshCw, Trash2 } from "lucide-react"; import * as React from "react"; import { Link, useNavigate } from "react-router-dom"; import { RoleGuard } from "../../../components/auth/RoleGuard"; import { Badge } from "../../../components/ui/badge"; import { Button } from "../../../components/ui/button"; import { Card, CardContent, CardDescription, CardHeader, CardTitle, } from "../../../components/ui/card"; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from "../../../components/ui/table"; import { type TenantSummary, deleteTenant, fetchMe, fetchTenants, } from "../../../lib/adminApi"; import { t } from "../../../lib/i18n"; function TenantListPage() { const navigate = useNavigate(); const { data: profile } = useQuery({ queryKey: ["me"], queryFn: fetchMe, }); // Redirect tenant_admin ONLY if they have one or fewer manageable tenants in the list React.useEffect(() => { if (profile?.role === "tenant_admin") { const manageableCount = profile.manageableTenants?.length ?? 0; // If only 1 in array, OR array is empty but we have a primary tenantId if ( (manageableCount === 1 || manageableCount === 0) && profile.tenantId ) { navigate(`/tenants/${profile.tenantId}`, { replace: true }); } } }, [profile, navigate]); const query = useQuery({ queryKey: ["tenants", { limit: 1000, offset: 0 }], queryFn: () => fetchTenants(1000, 0), enabled: profile?.role === "super_admin" || (profile?.role === "tenant_admin" && (profile.manageableTenants?.length ?? 0) > 1), }); const deleteMutation = useMutation({ mutationFn: (tenantId: string) => deleteTenant(tenantId), onSuccess: () => { query.refetch(); }, }); if ( profile && profile.role !== "super_admin" && profile.role !== "tenant_admin" ) { return (

{t("msg.admin.common.forbidden", "접근 권한이 없습니다.")}

); } // While redirecting (only if exactly one manageable tenant) if ( profile?.role === "tenant_admin" && (profile.manageableTenants?.length ?? 0) <= 1 ) { return null; } const errorMsg = (query.error as AxiosError<{ error?: string }>)?.response ?.data?.error; const fallbackError = !errorMsg && query.isError ? t("msg.admin.tenants.fetch_error", "테넌트 목록 조회에 실패했습니다.") : null; const tenants = query.data?.items ?? []; const handleDelete = (tenantId: string, tenantName: string) => { if ( !window.confirm( t( "msg.admin.tenants.delete_confirm", '테넌트 "{{name}}"를 삭제할까요?', { name: tenantName }, ), ) ) { return; } deleteMutation.mutate(tenantId); }; return (
{t("ui.admin.tenants.breadcrumb.section", "Tenants")} / {t("ui.admin.tenants.breadcrumb.list", "List")}

{t("ui.admin.tenants.title", "테넌트 목록")}

{t( "msg.admin.tenants.subtitle", "시스템에 등록된 모든 테넌트를 평면 목록으로 확인하고 관리합니다.", )}

{t("ui.admin.tenants.registry.title", "Tenant Registry")} {t("msg.admin.tenants.registry.count", "총 {{count}}개 테넌트", { count: query.data?.total ?? 0, })}
{t("ui.common.badge.admin_only", "Admin only")}
{(errorMsg || fallbackError) && (
{errorMsg ?? fallbackError}
)} {t("ui.admin.tenants.table.name", "NAME")} {t("ui.admin.tenants.table.type", "TYPE")} {t("ui.admin.tenants.table.slug", "SLUG")} {t("ui.admin.tenants.table.status", "STATUS")} {t("ui.admin.tenants.table.members", "MEMBERS")} {t("ui.admin.tenants.table.updated", "UPDATED")} {t("ui.admin.tenants.table.actions", "ACTIONS")} {query.isLoading && ( {t("msg.common.loading", "로딩 중...")} )} {!query.isLoading && tenants.length === 0 && ( {t( "msg.admin.tenants.empty", "아직 등록된 테넌트가 없습니다.", )} )} {tenants.map((tenant) => ( {tenant.name} {t( `domain.tenant_type.${tenant.type?.toLowerCase()}`, tenant.type, )} {tenant.slug} {t(`ui.common.status.${tenant.status}`, tenant.status)} {tenant.memberCount} {tenant.updatedAt ? new Date(tenant.updatedAt).toLocaleString("ko-KR") : "-"}
))}
); } export default TenantListPage;