forked from baron/baron-sso
dev/admin 테이블 정렬 헤더 UI 공통화
This commit is contained in:
@@ -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}
|
||||
>
|
||||
<Table className="min-w-[1180px]">
|
||||
<TableHeader className="sticky top-0 z-10 bg-secondary shadow-sm">
|
||||
<TableHeader className={sortableTableHeaderClassName}>
|
||||
<TableRow>
|
||||
<TableHead className="w-[48px] whitespace-nowrap">
|
||||
<TableHead
|
||||
className={`${sortableTableHeadBaseClassName} w-[48px] whitespace-nowrap`}
|
||||
>
|
||||
<Checkbox
|
||||
checked={
|
||||
tenants.length > 0 &&
|
||||
@@ -969,55 +975,57 @@ function TenantListPage() {
|
||||
/>
|
||||
</TableHead>
|
||||
<SortableTableHead
|
||||
className="min-w-[220px] whitespace-nowrap sticky top-0 bg-inherit"
|
||||
className="min-w-[220px] whitespace-nowrap"
|
||||
label={t("ui.admin.tenants.table.id", "ID")}
|
||||
onSort={requestSort}
|
||||
sortConfig={sortConfig}
|
||||
sortKey="id"
|
||||
/>
|
||||
<SortableTableHead
|
||||
className="whitespace-nowrap sticky top-0 bg-inherit"
|
||||
className="whitespace-nowrap"
|
||||
label={t("ui.admin.tenants.table.name", "NAME")}
|
||||
onSort={requestSort}
|
||||
sortConfig={sortConfig}
|
||||
sortKey="name"
|
||||
/>
|
||||
<SortableTableHead
|
||||
className="whitespace-nowrap sticky top-0 bg-inherit"
|
||||
className="whitespace-nowrap"
|
||||
label={t("ui.admin.tenants.table.type", "TYPE")}
|
||||
onSort={requestSort}
|
||||
sortConfig={sortConfig}
|
||||
sortKey="type"
|
||||
/>
|
||||
<SortableTableHead
|
||||
className="whitespace-nowrap sticky top-0 bg-inherit"
|
||||
className="whitespace-nowrap"
|
||||
label={t("ui.admin.tenants.table.slug", "SLUG")}
|
||||
onSort={requestSort}
|
||||
sortConfig={sortConfig}
|
||||
sortKey="slug"
|
||||
/>
|
||||
<SortableTableHead
|
||||
className="whitespace-nowrap sticky top-0 bg-inherit"
|
||||
className="whitespace-nowrap"
|
||||
label={t("ui.admin.tenants.table.status", "STATUS")}
|
||||
onSort={requestSort}
|
||||
sortConfig={sortConfig}
|
||||
sortKey="status"
|
||||
/>
|
||||
<SortableTableHead
|
||||
className="whitespace-nowrap sticky top-0 bg-inherit"
|
||||
className="whitespace-nowrap"
|
||||
label={t("ui.admin.tenants.table.members", "MEMBERS")}
|
||||
onSort={requestSort}
|
||||
sortConfig={sortConfig}
|
||||
sortKey="recursiveMemberCount"
|
||||
/>
|
||||
<SortableTableHead
|
||||
className="whitespace-nowrap sticky top-0 bg-inherit"
|
||||
className="whitespace-nowrap"
|
||||
label={t("ui.admin.tenants.table.created", "CREATED")}
|
||||
onSort={requestSort}
|
||||
sortConfig={sortConfig}
|
||||
sortKey="createdAt"
|
||||
/>
|
||||
<TableHead className="whitespace-nowrap">
|
||||
<TableHead
|
||||
className={`${sortableTableHeadBaseClassName} whitespace-nowrap`}
|
||||
>
|
||||
{t("ui.common.actions", "액션")}
|
||||
</TableHead>
|
||||
</TableRow>
|
||||
|
||||
@@ -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 <ArrowUpDown size={14} className="ml-1 opacity-50" />;
|
||||
}
|
||||
return sortConfig.direction === "asc" ? (
|
||||
<ArrowUp size={14} className="ml-1" />
|
||||
) : (
|
||||
<ArrowDown size={14} className="ml-1" />
|
||||
);
|
||||
};
|
||||
|
||||
const total = query.data?.total ?? 0;
|
||||
const totalPages = Math.ceil(total / limit);
|
||||
const canPromoteSuperAdmin = isSuperAdminRole(profile?.role);
|
||||
@@ -567,9 +558,11 @@ function UserListPage() {
|
||||
<div className="flex-1 rounded-md border overflow-hidden flex flex-col">
|
||||
<div className="flex-1 overflow-auto relative custom-scrollbar">
|
||||
<Table>
|
||||
<TableHeader className="sticky top-0 z-10 bg-secondary shadow-sm">
|
||||
<TableHeader className={sortableTableHeaderClassName}>
|
||||
<TableRow>
|
||||
<TableHead className="w-12">
|
||||
<TableHead
|
||||
className={`${sortableTableHeadBaseClassName} w-12`}
|
||||
>
|
||||
<input
|
||||
type="checkbox"
|
||||
className="w-4 h-4 rounded border-gray-300 text-primary focus:ring-primary cursor-pointer"
|
||||
@@ -580,82 +573,61 @@ function UserListPage() {
|
||||
onChange={toggleSelectAll}
|
||||
/>
|
||||
</TableHead>
|
||||
<TableHead
|
||||
className="min-w-[220px] whitespace-nowrap cursor-pointer hover:bg-muted/50 transition-colors"
|
||||
onClick={() => requestSort("id")}
|
||||
>
|
||||
<div className="flex items-center">
|
||||
{t("ui.admin.users.list.table.id", "ID")}
|
||||
{getSortIcon("id")}
|
||||
</div>
|
||||
</TableHead>
|
||||
<TableHead
|
||||
className="min-w-[200px] whitespace-nowrap cursor-pointer hover:bg-muted/50 transition-colors"
|
||||
onClick={() => requestSort("name_email")}
|
||||
>
|
||||
<div className="flex items-center">
|
||||
{t(
|
||||
"ui.admin.users.list.table.name_email",
|
||||
"이름 / 이메일 / 전화번호",
|
||||
)}
|
||||
{getSortIcon("name_email")}
|
||||
</div>
|
||||
</TableHead>
|
||||
<TableHead
|
||||
className="whitespace-nowrap cursor-pointer hover:bg-muted/50 transition-colors"
|
||||
onClick={() => requestSort("status")}
|
||||
>
|
||||
<div className="flex items-center">
|
||||
{t("ui.admin.users.list.table.status", "STATUS")}
|
||||
{getSortIcon("status")}
|
||||
</div>
|
||||
</TableHead>
|
||||
<TableHead
|
||||
className="whitespace-nowrap cursor-pointer hover:bg-muted/50 transition-colors"
|
||||
onClick={() => requestSort("role")}
|
||||
>
|
||||
<div className="flex items-center">
|
||||
{t("ui.admin.users.list.table.role", "ROLE")}
|
||||
{getSortIcon("role")}
|
||||
</div>
|
||||
</TableHead>
|
||||
<TableHead
|
||||
className="whitespace-nowrap cursor-pointer hover:bg-muted/50 transition-colors"
|
||||
onClick={() => requestSort("tenant_dept")}
|
||||
>
|
||||
<div className="flex items-center">
|
||||
{t(
|
||||
"ui.admin.users.list.table.tenant_dept",
|
||||
"TENANT / DEPT",
|
||||
)}
|
||||
{getSortIcon("tenant_dept")}
|
||||
</div>
|
||||
</TableHead>
|
||||
<SortableTableHead
|
||||
className="min-w-[220px] whitespace-nowrap"
|
||||
label={t("ui.admin.users.list.table.id", "ID")}
|
||||
onSort={requestSort}
|
||||
sortConfig={sortConfig}
|
||||
sortKey="id"
|
||||
/>
|
||||
<SortableTableHead
|
||||
className="min-w-[200px] whitespace-nowrap"
|
||||
label={t(
|
||||
"ui.admin.users.list.table.name_email",
|
||||
"이름 / 이메일 / 전화번호",
|
||||
)}
|
||||
onSort={requestSort}
|
||||
sortConfig={sortConfig}
|
||||
sortKey="name_email"
|
||||
/>
|
||||
<SortableTableHead
|
||||
className="whitespace-nowrap"
|
||||
label={t("ui.admin.users.list.table.status", "STATUS")}
|
||||
onSort={requestSort}
|
||||
sortConfig={sortConfig}
|
||||
sortKey="status"
|
||||
/>
|
||||
<SortableTableHead
|
||||
className="whitespace-nowrap"
|
||||
label={t(
|
||||
"ui.admin.users.list.table.tenant_dept",
|
||||
"TENANT / DEPT",
|
||||
)}
|
||||
onSort={requestSort}
|
||||
sortConfig={sortConfig}
|
||||
sortKey="tenant_dept"
|
||||
/>
|
||||
{/* Dynamic Columns from Schema */}
|
||||
{userSchema.map(
|
||||
(field) =>
|
||||
visibleColumns[field.key] !== false && (
|
||||
<TableHead
|
||||
<SortableTableHead
|
||||
key={field.key}
|
||||
className="whitespace-nowrap uppercase cursor-pointer hover:bg-muted/50 transition-colors"
|
||||
onClick={() => requestSort(field.key)}
|
||||
>
|
||||
<div className="flex items-center">
|
||||
{field.label}
|
||||
{getSortIcon(field.key)}
|
||||
</div>
|
||||
</TableHead>
|
||||
className="whitespace-nowrap"
|
||||
label={field.label}
|
||||
onSort={requestSort}
|
||||
sortConfig={sortConfig}
|
||||
sortKey={field.key}
|
||||
/>
|
||||
),
|
||||
)}
|
||||
<TableHead
|
||||
className="whitespace-nowrap cursor-pointer hover:bg-muted/50 transition-colors"
|
||||
onClick={() => requestSort("createdAt")}
|
||||
>
|
||||
<div className="flex items-center">
|
||||
{t("ui.admin.users.list.table.created", "CREATED")}
|
||||
{getSortIcon("createdAt")}
|
||||
</div>
|
||||
</TableHead>
|
||||
<SortableTableHead
|
||||
className="whitespace-nowrap"
|
||||
label={t("ui.admin.users.list.table.created", "CREATED")}
|
||||
onSort={requestSort}
|
||||
sortConfig={sortConfig}
|
||||
sortKey="createdAt"
|
||||
/>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
|
||||
Reference in New Issue
Block a user