263 lines
7.3 KiB
TypeScript
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 };
|