1
0
forked from baron/baron-sso

common 정렬 헬퍼 공통화 및 devfront 목록 정렬 추가

This commit is contained in:
2026-05-12 09:43:11 +09:00
parent a0713df85a
commit a2a6938246
6 changed files with 347 additions and 110 deletions

View File

@@ -50,6 +50,12 @@ import {
TableRow,
} from "../../components/ui/table";
import { toast } from "../../components/ui/use-toast";
import {
sortItems,
toggleSort,
type SortConfig,
type SortResolverMap,
} from "../../../../common/core/utils";
import {
type UserSummary,
bulkDeleteUsers,
@@ -71,10 +77,7 @@ type UserSchemaField = {
type: string;
};
type SortConfig = {
key: string;
direction: "asc" | "desc";
};
type UserSortKey = string;
function UserListPage() {
const navigate = useNavigate();
@@ -86,7 +89,9 @@ function UserListPage() {
Record<string, boolean>
>({});
const [selectedUserIds, setSelectedUserIds] = React.useState<string[]>([]);
const [sortConfig, setSortConfig] = React.useState<SortConfig | null>(null);
const [sortConfig, setSortConfig] = React.useState<SortConfig<UserSortKey> | null>(
null,
);
const limit = 1000;
const offset = (page - 1) * limit;
@@ -219,60 +224,38 @@ function UserListPage() {
: null;
const rawItems = query.data?.items ?? [];
const userSortResolvers = React.useMemo<SortResolverMap<UserSummary, UserSortKey>>(
() =>
userSchema.reduce<SortResolverMap<UserSummary, UserSortKey>>(
(accumulator, field) => ({
...accumulator,
[field.key]: (user) => {
const value = user.metadata?.[field.key];
return typeof value === "string" ||
typeof value === "number" ||
typeof value === "boolean"
? value
: null;
},
}),
{
name_email: (user) =>
`${user.name ?? ""} ${user.email ?? ""} ${user.phone ?? ""}`,
tenant_dept: (user) =>
`${user.tenant?.name ?? user.tenantSlug ?? ""} ${user.department ?? ""}`,
},
),
[userSchema],
);
const items = React.useMemo(() => {
const sorted = [...rawItems];
if (sortConfig) {
sorted.sort((a, b) => {
let aValue: string | number | boolean | null | undefined;
let bValue: string | number | boolean | null | undefined;
return sortItems(rawItems, sortConfig, userSortResolvers);
}, [rawItems, sortConfig, userSortResolvers]);
if (sortConfig.key === "name_email") {
aValue = a.name?.toLowerCase() || "";
bValue = b.name?.toLowerCase() || "";
} else if (sortConfig.key === "tenant_dept") {
aValue =
(a.tenant?.name || a.tenantSlug || "").toLowerCase() +
(a.department || "").toLowerCase();
bValue =
(b.tenant?.name || b.tenantSlug || "").toLowerCase() +
(b.department || "").toLowerCase();
} else {
aValue = (a as Record<string, unknown>)[sortConfig.key] as
| string
| number
| boolean;
bValue = (b as Record<string, unknown>)[sortConfig.key] as
| string
| number
| boolean;
}
if (aValue === bValue) return 0;
if (aValue === null || aValue === undefined) return 1;
if (bValue === null || bValue === undefined) return -1;
if (sortConfig.direction === "asc") {
return aValue < bValue ? -1 : 1;
}
return aValue > bValue ? -1 : 1;
});
}
return sorted;
}, [rawItems, sortConfig]);
const requestSort = (key: SortConfig["key"]) => {
let direction: "asc" | "desc" = "asc";
if (
sortConfig &&
sortConfig.key === key &&
sortConfig.direction === "asc"
) {
direction = "desc";
}
setSortConfig({ key, direction });
const requestSort = (key: UserSortKey) => {
setSortConfig((current) => toggleSort(current, key));
};
const getSortIcon = (key: SortConfig["key"]) => {
const getSortIcon = (key: UserSortKey) => {
if (!sortConfig || sortConfig.key !== key) {
return <ArrowUpDown size={14} className="ml-1 opacity-50" />;
}