From 4a0e5641cb56025fd393fc40c5ac43f063abf0ec Mon Sep 17 00:00:00 2001 From: kyy Date: Wed, 13 May 2026 15:17:37 +0900 Subject: [PATCH] =?UTF-8?q?dev/admin=20=ED=85=8C=EC=9D=B4=EB=B8=94=20?= =?UTF-8?q?=EC=A0=95=EB=A0=AC=20=ED=97=A4=EB=8D=94=20UI=20=EA=B3=B5?= =?UTF-8?q?=ED=86=B5=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../tenants/routes/TenantListPage.tsx | 30 ++-- .../src/features/users/UserListPage.tsx | 142 +++++++----------- .../components/sort/SortableTableHead.tsx | 24 ++- devfront/src/features/clients/ClientsPage.tsx | 12 +- 4 files changed, 102 insertions(+), 106 deletions(-) diff --git a/adminfront/src/features/tenants/routes/TenantListPage.tsx b/adminfront/src/features/tenants/routes/TenantListPage.tsx index 5a3d4080..363fe5a7 100644 --- a/adminfront/src/features/tenants/routes/TenantListPage.tsx +++ b/adminfront/src/features/tenants/routes/TenantListPage.tsx @@ -19,7 +19,11 @@ import { } from "lucide-react"; import * as React from "react"; import { Link, useNavigate } from "react-router-dom"; -import { SortableTableHead } from "../../../../../common/core/components/sort"; +import { + SortableTableHead, + sortableTableHeadBaseClassName, + sortableTableHeaderClassName, +} from "../../../../../common/core/components/sort"; import { type SortConfig, type SortResolverMap, @@ -954,9 +958,11 @@ function TenantListPage() { onScroll={handleTenantTableScroll} > - + - + 0 && @@ -969,55 +975,57 @@ function TenantListPage() { /> - + {t("ui.common.actions", "액션")} diff --git a/adminfront/src/features/users/UserListPage.tsx b/adminfront/src/features/users/UserListPage.tsx index 45a4a1cc..f987838c 100644 --- a/adminfront/src/features/users/UserListPage.tsx +++ b/adminfront/src/features/users/UserListPage.tsx @@ -1,9 +1,6 @@ import { useMutation, useQuery } from "@tanstack/react-query"; import type { AxiosError } from "axios"; import { - ArrowDown, - ArrowUp, - ArrowUpDown, ChevronLeft, ChevronRight, FileDown, @@ -22,6 +19,11 @@ import { sortItems, toggleSort, } from "../../../../common/core/utils"; +import { + SortableTableHead, + sortableTableHeadBaseClassName, + sortableTableHeaderClassName, +} from "../../../../common/core/components/sort"; import { Button } from "../../components/ui/button"; import { Card, @@ -285,17 +287,6 @@ function UserListPage() { setSortConfig((current) => toggleSort(current, key)); }; - const getSortIcon = (key: UserSortKey) => { - if (!sortConfig || sortConfig.key !== key) { - return ; - } - return sortConfig.direction === "asc" ? ( - - ) : ( - - ); - }; - const total = query.data?.total ?? 0; const totalPages = Math.ceil(total / limit); const canPromoteSuperAdmin = isSuperAdminRole(profile?.role); @@ -567,9 +558,11 @@ function UserListPage() {
- + - + - requestSort("id")} - > -
- {t("ui.admin.users.list.table.id", "ID")} - {getSortIcon("id")} -
-
- requestSort("name_email")} - > -
- {t( - "ui.admin.users.list.table.name_email", - "이름 / 이메일 / 전화번호", - )} - {getSortIcon("name_email")} -
-
- requestSort("status")} - > -
- {t("ui.admin.users.list.table.status", "STATUS")} - {getSortIcon("status")} -
-
- requestSort("role")} - > -
- {t("ui.admin.users.list.table.role", "ROLE")} - {getSortIcon("role")} -
-
- requestSort("tenant_dept")} - > -
- {t( - "ui.admin.users.list.table.tenant_dept", - "TENANT / DEPT", - )} - {getSortIcon("tenant_dept")} -
-
+ + + + {/* Dynamic Columns from Schema */} {userSchema.map( (field) => visibleColumns[field.key] !== false && ( - requestSort(field.key)} - > -
- {field.label} - {getSortIcon(field.key)} -
-
+ className="whitespace-nowrap" + label={field.label} + onSort={requestSort} + sortConfig={sortConfig} + sortKey={field.key} + /> ), )} - requestSort("createdAt")} - > -
- {t("ui.admin.users.list.table.created", "CREATED")} - {getSortIcon("createdAt")} -
-
+
diff --git a/common/core/components/sort/SortableTableHead.tsx b/common/core/components/sort/SortableTableHead.tsx index b6774a85..5a32e990 100644 --- a/common/core/components/sort/SortableTableHead.tsx +++ b/common/core/components/sort/SortableTableHead.tsx @@ -1,12 +1,18 @@ import type { ReactNode, ThHTMLAttributes } from "react"; import type { SortConfig } from "../../utils"; +export const sortableTableHeadBaseClassName = + "h-12 px-6 text-left text-xs font-sans font-bold uppercase tracking-[0.08em] text-foreground align-middle"; + +export const sortableTableHeaderClassName = + "sticky top-0 z-10 bg-secondary shadow-sm"; + function SortAscendingIcon() { return ( {label} {direction === "asc" ? ( - + + + ) : direction === "desc" ? ( - + + + ) : ( )} diff --git a/devfront/src/features/clients/ClientsPage.tsx b/devfront/src/features/clients/ClientsPage.tsx index 7f6f92e7..73b03603 100644 --- a/devfront/src/features/clients/ClientsPage.tsx +++ b/devfront/src/features/clients/ClientsPage.tsx @@ -10,7 +10,11 @@ import { import { useEffect, useMemo, useState } from "react"; import { useAuth } from "react-oidc-context"; import { Link, useNavigate } from "react-router-dom"; -import { SortableTableHead } from "../../../../common/core/components/sort"; +import { + SortableTableHead, + sortableTableHeadBaseClassName, + sortableTableHeaderClassName, +} from "../../../../common/core/components/sort"; import { type SortConfig, type SortResolverMap, @@ -440,7 +444,7 @@ function ClientsPage() {
- + - + {t("ui.dev.clients.table.actions", "액션")}