288 lines
8.7 KiB
TypeScript
288 lines
8.7 KiB
TypeScript
"use client";
|
|
|
|
import { useRef, useState } from "react";
|
|
import { usePathname, useRouter } from "next/navigation";
|
|
import { useConfirm } from "@frontend-opensource/use-react-hooks";
|
|
import { useQuery } from "@tanstack/react-query";
|
|
import {
|
|
getCoreRowModel,
|
|
useReactTable,
|
|
type PaginationState,
|
|
type RowSelectionState,
|
|
} from "@tanstack/react-table";
|
|
import {
|
|
Button,
|
|
DataTable,
|
|
Input,
|
|
Label,
|
|
Select,
|
|
SelectContent,
|
|
SelectItem,
|
|
SelectTrigger,
|
|
SelectValue,
|
|
Skeleton,
|
|
} from "@common/components";
|
|
import {
|
|
PostApi,
|
|
PostPageGuard,
|
|
type Post,
|
|
type PostParams,
|
|
} from "@/entities/post";
|
|
import { ENDPOINT } from "@/shared/config";
|
|
import { useMenuStore, useUserStore } from "@/shared/lib";
|
|
import { GridViewDataTable } from "@/shared/ui/grid-view-data-table";
|
|
import { columns as tableColumns } from "../model/post-table-columns";
|
|
import { createColumns as createGridViewColumns } from "../model/grid-view-table-columns";
|
|
import { SortSelect } from "./sort-select";
|
|
|
|
function PostPage({
|
|
bbsId,
|
|
tableCaption,
|
|
}: {
|
|
bbsId: string;
|
|
tableCaption?: string;
|
|
}) {
|
|
const router = useRouter();
|
|
const pathname = usePathname();
|
|
const { confirm } = useConfirm();
|
|
const userInfo = useUserStore((state) => state.userInfo);
|
|
const { bbsInfo, pageMenuAuthority } = useMenuStore((state) => state);
|
|
const thumbRefs = useRef<Map<number, string>>(new Map());
|
|
|
|
const [tableSort, setTableSort] = useState("");
|
|
const [keywordType, setKeywordType] = useState("title");
|
|
const [keyword, setKeyword] = useState("");
|
|
const [searchParams, setSearchParams] = useState<PostParams>({
|
|
keywordType: "title",
|
|
keyword: "",
|
|
});
|
|
const [pagination, setPagination] = useState<PaginationState>({
|
|
pageIndex: 0,
|
|
pageSize: 10,
|
|
});
|
|
const [rowSelection, setRowSelection] = useState<RowSelectionState>({});
|
|
|
|
const { data: upndFixPostList } = useQuery({
|
|
queryKey: [ENDPOINT.BOARD_SERVICE.POSTS_USER, bbsId, bbsInfo],
|
|
queryFn: () =>
|
|
PostApi.getPostList(parseInt(bbsId), {
|
|
...searchParams,
|
|
upndFixYn: bbsInfo?.upndFixUseYn,
|
|
}),
|
|
select: (data) => {
|
|
const newContent = data.content.map((post) => ({
|
|
...post,
|
|
isUpndFixPost: post.upndFixYn === "Y",
|
|
}));
|
|
return {
|
|
...data,
|
|
content: newContent,
|
|
};
|
|
},
|
|
enabled: bbsInfo?.upndFixUseYn === "Y",
|
|
});
|
|
|
|
const {
|
|
data: postList,
|
|
isLoading,
|
|
refetch,
|
|
} = useQuery({
|
|
queryKey: [
|
|
ENDPOINT.BOARD_SERVICE.POSTS_USER,
|
|
bbsId,
|
|
searchParams,
|
|
pagination,
|
|
tableSort,
|
|
],
|
|
queryFn: () =>
|
|
PostApi.getPostList(parseInt(bbsId), {
|
|
...searchParams,
|
|
ansUseYn: bbsInfo?.ansUseYn,
|
|
page: pagination.pageIndex,
|
|
size: pagination.pageSize,
|
|
sort: tableSort,
|
|
}),
|
|
});
|
|
|
|
const isGridViewPage =
|
|
bbsInfo?.bbsTypeCd === "BBSIMAGE" || bbsInfo?.bbsTypeCd === "BBSMOVIE";
|
|
|
|
const table = useReactTable({
|
|
data: isGridViewPage
|
|
? (postList?.content ?? [])
|
|
: [...(upndFixPostList?.content ?? []), ...(postList?.content ?? [])],
|
|
columns: isGridViewPage ? createGridViewColumns(thumbRefs) : tableColumns,
|
|
state: { pagination, rowSelection },
|
|
rowCount: postList?.totalElements ?? 0,
|
|
manualPagination: true,
|
|
enableMultiRowSelection: true,
|
|
getCoreRowModel: getCoreRowModel(),
|
|
onPaginationChange: setPagination,
|
|
onRowSelectionChange: setRowSelection,
|
|
meta: { bbsTypeCd: bbsInfo?.bbsTypeCd },
|
|
});
|
|
|
|
const onPostDelete = async () => {
|
|
const selectedPosts = table
|
|
.getFilteredSelectedRowModel()
|
|
.rows.map((row) => row.original.pstNo);
|
|
|
|
if (await confirm("삭제하시겠습니까?")) {
|
|
setRowSelection({});
|
|
await Promise.all(
|
|
selectedPosts.map((pstNo) =>
|
|
PostApi.deletePost(parseInt(bbsId), pstNo, userInfo?.userUnqId),
|
|
),
|
|
);
|
|
refetch();
|
|
}
|
|
};
|
|
|
|
const handleSubmit = (e: React.SubmitEvent<HTMLFormElement>) => {
|
|
e.preventDefault();
|
|
setPagination({
|
|
...pagination,
|
|
pageIndex: 0,
|
|
});
|
|
setSearchParams({
|
|
...searchParams,
|
|
keywordType,
|
|
keyword,
|
|
});
|
|
};
|
|
|
|
const handleReset = () => {
|
|
setKeywordType("title");
|
|
setKeyword("");
|
|
setPagination({
|
|
...pagination,
|
|
pageIndex: 0,
|
|
});
|
|
setSearchParams({
|
|
...searchParams,
|
|
keywordType: "title",
|
|
keyword: "",
|
|
});
|
|
};
|
|
|
|
const handleRowClick = (row: Post) => {
|
|
router.push(`${pathname}/${row.pstNo}`);
|
|
};
|
|
|
|
return (
|
|
<PostPageGuard bbsId={bbsId}>
|
|
<div className="card card-border !mt-6">
|
|
<div className="card card-border">
|
|
<form onSubmit={handleSubmit} className="flex items-center gap-2 p-2">
|
|
<Label className="mr-2 text-label">검색</Label>
|
|
<Select value={keywordType} onValueChange={setKeywordType}>
|
|
<SelectTrigger className="h-[3.2rem] w-[10rem]">
|
|
<SelectValue placeholder="선택" />
|
|
</SelectTrigger>
|
|
<SelectContent>
|
|
<SelectItem value="title">제목</SelectItem>
|
|
<SelectItem value="all">제목+내용</SelectItem>
|
|
<SelectItem value="writer">작성자</SelectItem>
|
|
</SelectContent>
|
|
</Select>
|
|
<Input
|
|
value={keyword}
|
|
onChange={(e) => setKeyword(e.target.value)}
|
|
className="h-[3.2rem] w-[24rem] rounded-sm !text-[1.3rem]"
|
|
/>
|
|
<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">콘텐츠 목록</h3>
|
|
<div className="flex gap-2">
|
|
{pageMenuAuthority?.regAuthrtYn === "Y" && (
|
|
<Button onClick={() => router.push(`${pathname}/register`)}>
|
|
등록
|
|
</Button>
|
|
)}
|
|
<Select
|
|
value={table.getState().pagination.pageSize.toString()}
|
|
onValueChange={(value) => {
|
|
table.setPageSize(parseInt(value));
|
|
}}
|
|
>
|
|
<SelectTrigger className="h-[3.2rem] w-[12rem]">
|
|
<SelectValue placeholder="페이지 크기" />
|
|
</SelectTrigger>
|
|
<SelectContent>
|
|
{[10, 20, 30, 40, 50].map((pageSize) => (
|
|
<SelectItem key={pageSize} value={pageSize.toString()}>
|
|
{pageSize}개씩 보기
|
|
</SelectItem>
|
|
))}
|
|
</SelectContent>
|
|
</Select>
|
|
{bbsInfo?.ansUseYn === "N" && (
|
|
<SortSelect value={tableSort} onValueChange={setTableSort} />
|
|
)}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div className="card !m-[1.2rem] h-full overflow-auto !p-0">
|
|
{isLoading ? (
|
|
<Skeleton className="h-[36rem] w-full" />
|
|
) : (
|
|
isGridViewPage ? (
|
|
<GridViewDataTable
|
|
table={table}
|
|
onRowClick={handleRowClick}
|
|
viewPagination
|
|
footerContent={
|
|
pageMenuAuthority?.delAuthrtYn === "Y" ? (
|
|
<Button
|
|
color="red"
|
|
onClick={onPostDelete}
|
|
disabled={!table.getFilteredSelectedRowModel().rows.length}
|
|
>
|
|
선택삭제
|
|
</Button>
|
|
) : undefined
|
|
}
|
|
/>
|
|
) : (
|
|
<DataTable
|
|
table={table}
|
|
onRowClick={handleRowClick}
|
|
viewPagination
|
|
caption={tableCaption}
|
|
footerContent={
|
|
pageMenuAuthority?.delAuthrtYn === "Y" ? (
|
|
<Button
|
|
color="red"
|
|
onClick={onPostDelete}
|
|
disabled={!table.getFilteredSelectedRowModel().rows.length}
|
|
>
|
|
선택삭제
|
|
</Button>
|
|
) : undefined
|
|
}
|
|
/>
|
|
)
|
|
)}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</PostPageGuard>
|
|
);
|
|
}
|
|
|
|
export { PostPage };
|