From 45dc68427a0ff6ccb66a6479fdf103acfe23db3f Mon Sep 17 00:00:00 2001 From: kyy Date: Tue, 24 Feb 2026 16:00:37 +0900 Subject: [PATCH] =?UTF-8?q?=EC=97=B0=EB=8F=99=20=EC=95=B1=20=EB=AA=A9?= =?UTF-8?q?=EB=A1=9D=20=EB=B0=8F=20=ED=8E=B8=EC=A7=91=20=ED=8E=98=EC=9D=B4?= =?UTF-8?q?=EC=A7=80=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../features/clients/ClientGeneralPage.tsx | 176 ++++++++++++------ devfront/src/features/clients/ClientsPage.tsx | 115 ++---------- 2 files changed, 140 insertions(+), 151 deletions(-) diff --git a/devfront/src/features/clients/ClientGeneralPage.tsx b/devfront/src/features/clients/ClientGeneralPage.tsx index 7bb0e8c0..cf00077a 100644 --- a/devfront/src/features/clients/ClientGeneralPage.tsx +++ b/devfront/src/features/clients/ClientGeneralPage.tsx @@ -16,7 +16,12 @@ import { Input } from "../../components/ui/input"; import { Label } from "../../components/ui/label"; import { Switch } from "../../components/ui/switch"; import { Textarea } from "../../components/ui/textarea"; -import { createClient, fetchClient, updateClient } from "../../lib/devApi"; +import { + createClient, + deleteClient, + fetchClient, + updateClient, +} from "../../lib/devApi"; import type { ClientStatus, ClientType, @@ -174,6 +179,39 @@ function ClientGeneralPage() { }, }); + const deleteMutation = useMutation({ + mutationFn: (id: string) => deleteClient(id), + onSuccess: () => { + queryClient.invalidateQueries({ queryKey: ["clients"] }); + alert(t("msg.dev.clients.deleted", "앱이 삭제되었습니다.")); + navigate("/clients"); + }, + onError: (err) => { + const errorMessage = + (err as AxiosError<{ error?: string }>).response?.data?.error ?? + (err as Error)?.message; + alert( + t("msg.dev.clients.delete_error", "삭제 실패: {{error}}", { + error: errorMessage, + }), + ); + }, + }); + + const handleDelete = () => { + if ( + clientId && + window.confirm( + t( + "msg.dev.clients.delete_confirm", + "정말로 이 앱을 삭제하시겠습니까? 이 작업은 되돌릴 수 없습니다.", + ), + ) + ) { + deleteMutation.mutate(clientId); + } + }; + if (!isCreate && isLoading) { return (
@@ -220,14 +258,16 @@ function ClientGeneralPage() { : t("ui.dev.clients.general.title_edit", "Client Settings")}
- - {status === "active" - ? t("ui.common.status.active", "Active") - : t("ui.common.status.inactive", "Inactive")} - + {!isCreate && ( + + {status === "active" + ? t("ui.common.status.active", "Active") + : t("ui.common.status.inactive", "Inactive")} + + )}
{!isCreate && ( @@ -254,15 +294,49 @@ function ClientGeneralPage() { {/* 1. Application Identity */}
- - {t("ui.dev.clients.general.identity.title", "Application Identity")} - - - {t( - "msg.dev.clients.general.identity.subtitle", - "앱 이름과 설명, 로고를 설정합니다.", +
+
+ + {t( + "ui.dev.clients.general.identity.title", + "Application Identity", + )} + + + {t( + "msg.dev.clients.general.identity.subtitle", + "앱 이름과 설명, 로고를 설정합니다.", + )} + +
+ {!isCreate && ( +
+ +
+ + setStatus(checked ? "active" : "inactive") + } + /> + + {status === "active" + ? t("ui.common.status.active", "활성") + : t("ui.common.status.inactive", "비활성")} + +
+
)} - +
@@ -568,43 +642,41 @@ function ClientGeneralPage() { -
- - +
+
+ {!isCreate && ( + + )} +
+
+ + +
- {!isCreate && ( -
-
- - {t("ui.dev.clients.general.footer.client_id", "Client ID")} - - {data?.client?.id} -
-
- - {t("ui.dev.clients.general.footer.created_on", "Created On")} - - - {data?.client?.createdAt - ? new Date(data.client.createdAt).toLocaleString() - : "-"} - -
-
- )} +
); } diff --git a/devfront/src/features/clients/ClientsPage.tsx b/devfront/src/features/clients/ClientsPage.tsx index cb43ae6b..9d9def58 100644 --- a/devfront/src/features/clients/ClientsPage.tsx +++ b/devfront/src/features/clients/ClientsPage.tsx @@ -1,4 +1,4 @@ -import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; +import { useQuery } from "@tanstack/react-query"; import type { AxiosError } from "axios"; import { BookOpenText, @@ -22,10 +22,8 @@ import { CardHeader, CardTitle, } from "../../components/ui/card"; -import { CopyButton } from "../../components/ui/copy-button"; import { Input } from "../../components/ui/input"; import { Separator } from "../../components/ui/separator"; -import { Switch } from "../../components/ui/switch"; import { Table, TableBody, @@ -34,56 +32,16 @@ import { TableHeader, TableRow, } from "../../components/ui/table"; -import { toast } from "../../components/ui/use-toast"; -import { - deleteClient, - fetchClients, - updateClientStatus, -} from "../../lib/devApi"; +import { fetchClients } from "../../lib/devApi"; import { t } from "../../lib/i18n"; import { cn } from "../../lib/utils"; function ClientsPage() { const navigate = useNavigate(); - const queryClient = useQueryClient(); const { data, isLoading, error } = useQuery({ queryKey: ["clients"], queryFn: fetchClients, }); - const updateStatusMutation = useMutation({ - mutationFn: (payload: { id: string; status: "active" | "inactive" }) => - updateClientStatus(payload.id, payload.status), - onSuccess: (_, variables) => { - const statusText = - variables.status === "active" - ? t("ui.common.status.active", "활성화") - : t("ui.common.status.inactive", "비활성화"); - toast( - t( - "msg.dev.clients.status_updated", - "클라이언트가 {{status}}되었습니다.", - { - status: statusText, - }, - ), - ); - queryClient.invalidateQueries({ queryKey: ["clients"] }); - }, - onError: (error: AxiosError<{ error?: string }>) => { - const errMsg = - error.response?.data?.error ?? - error.message ?? - t( - "msg.dev.clients.status_update_error", - "Failed to update client status", - ); - toast(errMsg, "error"); - }, - }); - const deleteMutation = useMutation({ - mutationFn: (clientId: string) => deleteClient(clientId), - onSuccess: () => queryClient.invalidateQueries({ queryKey: ["clients"] }), - }); const clients = data?.items || []; const totalClients = clients.length; @@ -267,7 +225,10 @@ function ClientsPage() { {clients.map((client) => ( -
+
{client.type === "private" ? ( @@ -284,30 +245,13 @@ function ClientsPage() { {t("ui.dev.clients.tenant_scoped", "Tenant-scoped")}

-
+
{client.id} - - toast( - t( - "msg.dev.clients.copy_client_id", - "클라이언트 ID가 복사되었습니다.", - ), - ) - } - />
@@ -320,33 +264,14 @@ function ClientsPage() { -
- - updateStatusMutation.mutate({ - id: client.id, - status: checked ? "active" : "inactive", - }) - } - /> - - {client.status === "active" - ? t("ui.common.status.active", "활성") - : t("ui.common.status.inactive", "비활성")} - -
+ + {client.status === "active" + ? t("ui.common.status.active", "Active") + : t("ui.common.status.inactive", "Inactive")} +
{client.createdAt @@ -357,17 +282,9 @@ function ClientsPage() {
-