Files
frontend/apps/cs/src/pages/admin/ui/admin-page.tsx
T

263 lines
7.3 KiB
TypeScript

"use client";
import { useState } from "react";
import { useConfirm } from "@frontend-opensource/use-react-hooks";
import { useQuery, useQueryClient } from "@tanstack/react-query";
import {
getCoreRowModel,
type PaginationState,
type RowSelectionState,
type Table,
type Row,
} from "@tanstack/react-table";
import {
Button,
Input,
Label,
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
Checkbox,
} from "@common/components";
import { GroupApi } from "@/entities/group";
import {
UserApi,
type UserSearchParams,
type AdminUserListResponse,
} from "@/entities/user";
import { GroupUsersApi } from "@/entities/group-user";
import { ENDPOINT } from "@/shared/config";
import { useDataTable, useAlertStore } from "@/shared/lib";
import { columns } from "../model/table-columns";
import { AddAdminDialog } from "./add-admin-dialog";
function AdminPage() {
const queryClient = useQueryClient();
const alert = useAlertStore((state) => state.setMessage);
const { confirm } = useConfirm();
const [keywordType, setKeywordType] = useState("userId");
const [keyword, setKeyword] = useState("");
const [grpId, setGrpId] = useState("");
const [searchParams, setSearchParams] = useState<UserSearchParams>({
keywordType: "",
keyword: "",
grpId: "",
sort: "regDt,desc",
});
const [pagination, setPagination] = useState<PaginationState>({
pageIndex: 0,
pageSize: 10,
});
const [rowSelection, setRowSelection] = useState<RowSelectionState>({});
const { data: groupOptions } = useQuery({
queryKey: [ENDPOINT.CMS_SERVICE.GROUPS],
queryFn: () =>
GroupApi.findPageGroup({
delYn: "N",
mngrYn: "Y",
page: 0,
size: 99,
}),
select: (data) =>
data.content.map((item) => ({
groupId: item.groupId,
groupNm: item.groupNm,
})),
});
const query = useQuery({
queryKey: [ENDPOINT.USER_SERVICE.USERS, searchParams, pagination],
queryFn: () =>
UserApi.findPageAdminUser({
...searchParams,
page: pagination.pageIndex,
size: pagination.pageSize,
}),
});
const adminColumns = [
{
id: "select",
header: ({ table }: { table: Table<AdminUserListResponse> }) => (
<Checkbox
checked={
table.getIsAllPageRowsSelected() ||
(table.getIsSomePageRowsSelected() && "indeterminate")
}
onCheckedChange={(value) => table.toggleAllPageRowsSelected(!!value)}
aria-label="전체 선택"
/>
),
cell: ({ row }: { row: Row<AdminUserListResponse> }) => (
<Checkbox
checked={row.getIsSelected()}
onCheckedChange={(value) => row.toggleSelected(!!value)}
aria-label="행 선택"
/>
),
enableSorting: false,
enableHiding: false,
},
...columns,
];
const { tableComponent, tableInstance: table } = useDataTable({
query,
tableOptions: {
columns: adminColumns,
state: {
pagination,
rowSelection,
},
manualPagination: true,
enableRowSelection: true,
enableMultiRowSelection: true,
getCoreRowModel: getCoreRowModel(),
onPaginationChange: setPagination,
onRowSelectionChange: setRowSelection,
},
dataTableOptions: {
viewPagination: true,
},
});
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
setPagination({
...pagination,
pageIndex: 0,
});
setSearchParams({
...searchParams,
keywordType,
keyword,
grpId,
});
};
const handleReset = () => {
setKeywordType("");
setKeyword("");
setGrpId("");
setSearchParams({
...searchParams,
keywordType: "",
keyword: "",
grpId: "",
});
};
const handleDeleteAdmins = async () => {
const selectedRows = table.getSelectedRowModel().rows.map((row) => ({
groupId: row.original.groupId,
userUnqId: row.original.userUnqId,
}));
if (!(await confirm("관리자를 삭제하시겠습니까?"))) {
return;
}
try {
const usersToDelete = selectedRows.map((row) => ({
mode: "D",
groupId: row.groupId,
userUnqId: row.userUnqId,
}));
await GroupUsersApi.saveGroupUser(usersToDelete);
queryClient.invalidateQueries({
queryKey: [ENDPOINT.USER_SERVICE.USERS],
});
alert("관리자 삭제를 완료했습니다.");
setRowSelection({});
} catch (error) {
console.error(error);
}
};
return (
<div className="card card-border !mt-6">
<div className="card card-border">
<form onSubmit={handleSubmit} className="flex items-center gap-6 p-2">
<div className="flex items-center gap-2">
<Label className="mr-2 text-label">관리자구분</Label>
<Select value={grpId} onValueChange={(value) => setGrpId(value)}>
<SelectTrigger className="h-[3.2rem] w-[16rem] !text-[1.3rem]">
<SelectValue placeholder="그룹 선택" />
</SelectTrigger>
<SelectContent>
{groupOptions?.map((item) => (
<SelectItem key={item.groupId} value={item.groupId}>
{item.groupNm}
</SelectItem>
))}
</SelectContent>
</Select>
</div>
<div className="flex items-center gap-2">
<Label htmlFor="" className="mr-2 text-label">
관리자
</Label>
<Select
value={keywordType}
onValueChange={(value) => setKeywordType(value)}
>
<SelectTrigger className="h-[3.2rem] w-[10rem] !text-[1.3rem]">
<SelectValue placeholder="선택" />
</SelectTrigger>
<SelectContent>
<SelectItem value="userId">아이디</SelectItem>
<SelectItem value="userName">이름</SelectItem>
</SelectContent>
</Select>
<Input
className="h-[3.2rem] w-[24rem] rounded-sm !text-[1.3rem]"
value={keyword}
onChange={(e) => setKeyword(e.target.value)}
placeholder="검색어 입력"
/>
</div>
<Button className="h-[3.2rem]" type="submit">
조회
</Button>
<Button
type="button"
color="white"
className="h-[3.2rem]"
onClick={handleReset}
>
초기화
</Button>
</form>
</div>
<div className="card card-border">
<div className="card-header">
<div className="flex w-full items-center justify-between">
<h3 className="text-2xl font-medium text-label">
관리자 목록(총 {query.data?.totalElements}명)
</h3>
<div className="flex gap-2">
<AddAdminDialog />
<Button
color="red"
onClick={handleDeleteAdmins}
disabled={Object.keys(rowSelection).length === 0}
>
선택삭제
</Button>
</div>
</div>
</div>
<div className="card !m-[1.2rem] !p-0">{tableComponent}</div>
</div>
</div>
);
}
export { AdminPage };