From 7c1db5e0e01d4c973a16bb75632ac7f6a094d70b Mon Sep 17 00:00:00 2001 From: bicochan Date: Wed, 10 Jun 2026 14:45:06 +0900 Subject: [PATCH] =?UTF-8?q?[cs]=20refactor:=20useSearchParamsState=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1=20=EB=B0=8F=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/cs/src/pages/admin/ui/admin-page.tsx | 26 +-- apps/cs/src/pages/banner/ui/banner-page.tsx | 75 ++++---- apps/cs/src/pages/bbs/ui/bbs-page.tsx | 80 ++++---- .../src/pages/contents/ui/contents-page.tsx | 74 +++---- apps/cs/src/pages/file/ui/file-page.tsx | 11 +- apps/cs/src/pages/image/ui/image-page.tsx | 69 +++---- apps/cs/src/pages/module/ui/module-page.tsx | 102 +++++----- apps/cs/src/pages/popup/ui/popup-page.tsx | 69 +++---- apps/cs/src/pages/recent/ui/recent-page.tsx | 180 ++++++++++-------- apps/cs/src/pages/role/ui/role-page.tsx | 93 +++++---- apps/cs/src/pages/site/ui/site-page.tsx | 69 ++++--- apps/cs/src/pages/survey/ui/survey-page.tsx | 85 +++++---- .../src/pages/template/ui/template-page.tsx | 76 ++++---- apps/cs/src/pages/terms/ui/terms-page.tsx | 81 ++++---- apps/cs/src/pages/users/ui/users-page.tsx | 128 +++++++------ apps/cs/src/shared/lib/index.ts | 7 +- .../src/shared/lib/use-search-params-state.ts | 90 +++++++++ apps/cs/src/widgets/post/ui/post-action.tsx | 17 +- 18 files changed, 768 insertions(+), 564 deletions(-) create mode 100644 apps/cs/src/shared/lib/use-search-params-state.ts diff --git a/apps/cs/src/pages/admin/ui/admin-page.tsx b/apps/cs/src/pages/admin/ui/admin-page.tsx index 6a621b865..4874f6525 100644 --- a/apps/cs/src/pages/admin/ui/admin-page.tsx +++ b/apps/cs/src/pages/admin/ui/admin-page.tsx @@ -1,17 +1,29 @@ "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 Row, type RowSelectionState, type Table, - type Row, } from "@tanstack/react-table"; + +import { ENDPOINT } from "@/shared/config"; +import { useAlertStore, useDataTable } from "@/shared/lib"; +import { GroupApi } from "@/entities/group"; +import { GroupUsersApi } from "@/entities/group-user"; +import { + type AdminUserListResponse, + UserApi, + type UserSearchParams, +} from "@/entities/user"; import { Button, + Checkbox, Input, Label, Select, @@ -19,18 +31,10 @@ import { 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() { diff --git a/apps/cs/src/pages/banner/ui/banner-page.tsx b/apps/cs/src/pages/banner/ui/banner-page.tsx index e09f5ab58..4e1e4733c 100644 --- a/apps/cs/src/pages/banner/ui/banner-page.tsx +++ b/apps/cs/src/pages/banner/ui/banner-page.tsx @@ -1,20 +1,25 @@ "use client"; -import { useEffect, useState, useRef } from "react"; +import { useEffect, useRef, useState } from "react"; import { useRouter } from "next/navigation"; -import { useQuery } from "@tanstack/react-query"; + +import { keepPreviousData, useQuery } from "@tanstack/react-query"; import { getCoreRowModel, + type OnChangeFn, type PaginationState, type RowSelectionState, } from "@tanstack/react-table"; -import { Button, Input, Label } from "@common/components"; -import { POSTING_TYPE, PostingDialog } from "@/entities/posting"; + import { ENDPOINT } from "@/shared/config"; -import { useDataTable } from "@/shared/lib"; +import { useDataTable, useSearchParamsState } from "@/shared/lib"; +import { POSTING_TYPE, PostingDialog } from "@/entities/posting"; +import { Button, Input, Label } from "@common/components"; + import { BannerApi } from "../api/banner-service"; +import { type Banner } from "../model/banner-interface"; import { createColumns } from "../model/banner-table-columns"; -import { type Banner, type BannerParams } from "../model/banner-interface"; + import { PreviewBannerDialog } from "./preview-banner-dialog"; type PostingTarget = { @@ -22,50 +27,52 @@ type PostingTarget = { pstgTrgtNo: number; }; +const DEFAULT_PARAMS = { + bnrTtl: "", + sort: "regDt,desc", + page: 0, + size: 10, +}; + function BannerPage() { const router = useRouter(); const imageRefs = useRef>(new Map()); - + const { params, setParams, resetParams } = + useSearchParamsState(DEFAULT_PARAMS); const [rowSelection, setRowSelection] = useState({}); const [postingTargets, setPostingTargets] = useState([]); - const [bnrTtl, setBnrTtl] = useState(""); - const [searchParams, setSearchParams] = useState({ - bnrTtl: "", - sort: "regDt,desc", - }); - const [pagination, setPagination] = useState({ - pageIndex: 0, - pageSize: 10, - }); + const [bnrTtl, setBnrTtl] = useState(params.bnrTtl); const query = useQuery({ - queryKey: [ENDPOINT.CMS_SERVICE.BANNERS, searchParams, pagination], + queryKey: [ENDPOINT.CMS_SERVICE.BANNERS, params], queryFn: () => BannerApi.getBannerList({ - ...searchParams, - page: pagination.pageIndex, - size: pagination.pageSize, + bnrTtl: params.bnrTtl, + sort: params.sort, + page: params.page, + size: params.size, }), + placeholderData: keepPreviousData, }); - const handleSubmit = (e: React.SubmitEvent) => { + const pagination: PaginationState = { + pageIndex: params.page, + pageSize: params.size, + }; + + const handlePaginationChange: OnChangeFn = (updater) => { + const next = typeof updater === "function" ? updater(pagination) : updater; + setParams({ page: next.pageIndex, size: next.pageSize }); + }; + + const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); - setPagination({ - ...pagination, - pageIndex: 0, - }); - setSearchParams({ - ...searchParams, - bnrTtl, - }); + setParams({ bnrTtl, page: 0 }); }; const handleReset = () => { setBnrTtl(""); - setSearchParams({ - ...searchParams, - bnrTtl: "", - }); + resetParams(); }; const handleRowClick = (row: Banner) => { @@ -92,7 +99,7 @@ function BannerPage() { manualPagination: true, enableMultiRowSelection: true, getCoreRowModel: getCoreRowModel(), - onPaginationChange: setPagination, + onPaginationChange: handlePaginationChange, onRowSelectionChange: setRowSelection, }, dataTableOptions: { diff --git a/apps/cs/src/pages/bbs/ui/bbs-page.tsx b/apps/cs/src/pages/bbs/ui/bbs-page.tsx index abb1ec9db..27d0fb879 100644 --- a/apps/cs/src/pages/bbs/ui/bbs-page.tsx +++ b/apps/cs/src/pages/bbs/ui/bbs-page.tsx @@ -2,12 +2,19 @@ import { useState } from "react"; import { useRouter } from "next/navigation"; -import { useQuery } from "@tanstack/react-query"; + +import { keepPreviousData, useQuery } from "@tanstack/react-query"; import { getCoreRowModel, + type OnChangeFn, type PaginationState, type RowSelectionState, } from "@tanstack/react-table"; + +import { ENDPOINT } from "@/shared/config"; +import { useDataTable, useSearchParamsState } from "@/shared/lib"; +import { type Board, BoardApi } from "@/entities/board"; +import { CodeSelect } from "@/entities/code"; import { Button, Input, @@ -18,60 +25,57 @@ import { SelectTrigger, SelectValue, } from "@common/components"; -import { CodeSelect } from "@/entities/code"; -import { BoardApi, type BoardParams } from "@/entities/board"; -import { ENDPOINT } from "@/shared/config"; -import { useDataTable } from "@/shared/lib"; -import { type Board } from "@/entities/board"; + import { columns } from "../model/table-columns"; +const DEFAULT_PARAMS = { + bbsTypeCd: "", + bbsNm: "", + sort: "regDt,desc", + page: 0, + size: 10, +}; + function BbsPage() { const router = useRouter(); - + const { params, setParams, resetParams } = + useSearchParamsState(DEFAULT_PARAMS); const [rowSelection, setRowSelection] = useState({}); - const [bbsTypeCd, setBbsTypeCd] = useState(""); - const [bbsNm, setBbsNm] = useState(""); - const [searchParams, setSearchParams] = useState({ - bbsTypeCd: "", - bbsNm: "", - sort: "regDt,desc", - }); - const [pagination, setPagination] = useState({ - pageIndex: 0, - pageSize: 10, - }); + const [bbsTypeCd, setBbsTypeCd] = useState(params.bbsTypeCd); + const [bbsNm, setBbsNm] = useState(params.bbsNm); const query = useQuery({ - queryKey: [ENDPOINT.BOARD_SERVICE.BBS, searchParams, pagination], + queryKey: [ENDPOINT.BOARD_SERVICE.BBS, params], queryFn: () => BoardApi.getBoardList({ - ...searchParams, - page: pagination.pageIndex, - size: pagination.pageSize, + bbsTypeCd: params.bbsTypeCd, + bbsNm: params.bbsNm, + sort: params.sort, + page: params.page, + size: params.size, }), + placeholderData: keepPreviousData, }); - const handleSubmit = (e: React.SubmitEvent) => { + const pagination: PaginationState = { + pageIndex: params.page, + pageSize: params.size, + }; + + const handlePaginationChange: OnChangeFn = (updater) => { + const next = typeof updater === "function" ? updater(pagination) : updater; + setParams({ page: next.pageIndex, size: next.pageSize }); + }; + + const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); - setPagination({ - ...pagination, - pageIndex: 0, - }); - setSearchParams({ - ...searchParams, - bbsTypeCd, - bbsNm, - }); + setParams({ bbsTypeCd, bbsNm, page: 0 }); }; const handleReset = () => { setBbsTypeCd(""); setBbsNm(""); - setSearchParams({ - ...searchParams, - bbsTypeCd: "", - bbsNm: "", - }); + resetParams(); }; const handleRowClick = (row: Board) => { @@ -89,7 +93,7 @@ function BbsPage() { manualPagination: true, enableMultiRowSelection: true, getCoreRowModel: getCoreRowModel(), - onPaginationChange: setPagination, + onPaginationChange: handlePaginationChange, onRowSelectionChange: setRowSelection, }, dataTableOptions: { diff --git a/apps/cs/src/pages/contents/ui/contents-page.tsx b/apps/cs/src/pages/contents/ui/contents-page.tsx index 105aecdba..bda7c9ed6 100644 --- a/apps/cs/src/pages/contents/ui/contents-page.tsx +++ b/apps/cs/src/pages/contents/ui/contents-page.tsx @@ -2,60 +2,64 @@ import { useState } from "react"; import { useRouter } from "next/navigation"; + import { keepPreviousData, useQuery } from "@tanstack/react-query"; -import { getCoreRowModel, type PaginationState } from "@tanstack/react-table"; -import { Button, Input, Label } from "@common/components"; import { - ContentsApi, - type Contents, - type ContentsParams, -} from "@/entities/content"; + getCoreRowModel, + type OnChangeFn, + type PaginationState, +} from "@tanstack/react-table"; + import { ENDPOINT } from "@/shared/config"; -import { useDataTable } from "@/shared/lib"; +import { useDataTable, useSearchParamsState } from "@/shared/lib"; +import { type Contents, ContentsApi } from "@/entities/content"; +import { Button, Input, Label } from "@common/components"; + import { columns } from "../model/table-columns"; +const DEFAULT_PARAMS = { + contsTtl: "", + sort: "regDt,desc", + page: 0, + size: 10, +}; + function ContentsPage() { const router = useRouter(); - - const [contsTtl, setContsTtl] = useState(""); - const [searchParams, setSearchParams] = useState({ - contsTtl: "", - sort: "regDt,desc", - }); - const [pagination, setPagination] = useState({ - pageIndex: 0, - pageSize: 10, - }); + const { params, setParams, resetParams } = + useSearchParamsState(DEFAULT_PARAMS); + const [contsTtl, setContsTtl] = useState(params.contsTtl); const query = useQuery({ - queryKey: [ENDPOINT.CMS_SERVICE.CONTENTS, searchParams, pagination], + queryKey: [ENDPOINT.CMS_SERVICE.CONTENTS, params], queryFn: () => ContentsApi.getContentsList({ - ...searchParams, - page: pagination.pageIndex, - size: pagination.pageSize, + contsTtl: params.contsTtl, + sort: params.sort, + page: params.page, + size: params.size, }), placeholderData: keepPreviousData, }); - const handleSubmit = (e: React.SubmitEvent) => { + const pagination: PaginationState = { + pageIndex: params.page, + pageSize: params.size, + }; + + const handlePaginationChange: OnChangeFn = (updater) => { + const next = typeof updater === "function" ? updater(pagination) : updater; + setParams({ page: next.pageIndex, size: next.pageSize }); + }; + + const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); - setPagination({ - ...pagination, - pageIndex: 0, - }); - setSearchParams({ - ...searchParams, - contsTtl, - }); + setParams({ contsTtl, page: 0 }); }; const handleReset = () => { setContsTtl(""); - setSearchParams({ - ...searchParams, - contsTtl: "", - }); + resetParams(); }; const handleRowClick = (row: Contents) => { @@ -69,7 +73,7 @@ function ContentsPage() { state: { pagination, }, - onPaginationChange: setPagination, + onPaginationChange: handlePaginationChange, getCoreRowModel: getCoreRowModel(), manualPagination: true, }, diff --git a/apps/cs/src/pages/file/ui/file-page.tsx b/apps/cs/src/pages/file/ui/file-page.tsx index f4ff3f97a..8669d6717 100644 --- a/apps/cs/src/pages/file/ui/file-page.tsx +++ b/apps/cs/src/pages/file/ui/file-page.tsx @@ -1,13 +1,16 @@ "use client"; import { useState } from "react"; + +import { useConfirm } from "@frontend-opensource/use-react-hooks"; import { keepPreviousData, useQuery } from "@tanstack/react-query"; import { getCoreRowModel, type PaginationState } from "@tanstack/react-table"; -import { useConfirm } from "@frontend-opensource/use-react-hooks"; -import { Button, Input, Label } from "@common/components"; -import { AttachmentApi, type AttachmentParams } from "@/entities/attachment"; -import { useAlertStore, useDataTable, useMutationWrapper } from "@/shared/lib"; + import { ENDPOINT } from "@/shared/config"; +import { useAlertStore, useDataTable, useMutationWrapper } from "@/shared/lib"; +import { AttachmentApi, type AttachmentParams } from "@/entities/attachment"; +import { Button, Input, Label } from "@common/components"; + import { createColumns } from "../model/table-columns"; function FilePage() { diff --git a/apps/cs/src/pages/image/ui/image-page.tsx b/apps/cs/src/pages/image/ui/image-page.tsx index 212726c5d..72a0d4fcf 100644 --- a/apps/cs/src/pages/image/ui/image-page.tsx +++ b/apps/cs/src/pages/image/ui/image-page.tsx @@ -2,68 +2,73 @@ import { useEffect, useState } from "react"; import { useRouter } from "next/navigation"; + import { useQuery } from "@tanstack/react-query"; import { getCoreRowModel, + type OnChangeFn, type PaginationState, type RowSelectionState, } from "@tanstack/react-table"; -import { Button, Input, Label } from "@common/components"; -import { POSTING_TYPE, PostingDialog } from "@/entities/posting"; + import { ENDPOINT } from "@/shared/config"; -import { useDataTable } from "@/shared/lib"; +import { useDataTable, useSearchParamsState } from "@/shared/lib"; +import { POSTING_TYPE, PostingDialog } from "@/entities/posting"; +import { Button, Input, Label } from "@common/components"; + import { ImageApi } from "../api/image-service"; +import { type Image } from "../model/image-interface"; import { columns } from "../model/image-table-columns"; -import { type Image, type ImageParams } from "../model/image-interface"; type PostingTarget = { pstgTrgtNm: string; pstgTrgtNo: number; }; +const DEFAULT_PARAMS = { + keyword: "", + sort: "regDt,desc", + page: 0, + size: 10, +}; + function ImagePage() { const router = useRouter(); - - const [keyword, setKeyword] = useState(""); - const [searchParams, setSearchParams] = useState({ - keyword: "", - sort: "regDt,desc", - }); - const [pagination, setPagination] = useState({ - pageIndex: 0, - pageSize: 10, - }); + const { params, setParams, resetParams } = + useSearchParamsState(DEFAULT_PARAMS); + const [keyword, setKeyword] = useState(params.keyword); const [rowSelection, setRowSelection] = useState({}); const [postingTargets, setPostingTargets] = useState([]); const query = useQuery({ - queryKey: [ENDPOINT.CMS_SERVICE.IMAGES, searchParams, pagination], + queryKey: [ENDPOINT.CMS_SERVICE.IMAGES, params], queryFn: () => ImageApi.getImageList({ - ...searchParams, - page: pagination.pageIndex, - size: pagination.pageSize, + keyword: params.keyword, + sort: params.sort, + page: params.page, + size: params.size, }), }); - const handleSubmit = (e: React.SubmitEvent) => { + const pagination: PaginationState = { + pageIndex: params.page, + pageSize: params.size, + }; + + const handlePaginationChange: OnChangeFn = (updater) => { + const next = typeof updater === "function" ? updater(pagination) : updater; + setParams({ page: next.pageIndex, size: next.pageSize }); + }; + + const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); - setPagination({ - ...pagination, - pageIndex: 0, - }); - setSearchParams({ - ...searchParams, - keyword, - }); + setParams({ keyword, page: 0 }); }; const handleReset = () => { setKeyword(""); - setSearchParams({ - ...searchParams, - keyword: "", - }); + resetParams(); }; const handleRowClick = (row: Image) => { @@ -81,7 +86,7 @@ function ImagePage() { manualPagination: true, enableMultiRowSelection: true, getCoreRowModel: getCoreRowModel(), - onPaginationChange: setPagination, + onPaginationChange: handlePaginationChange, onRowSelectionChange: setRowSelection, }, dataTableOptions: { diff --git a/apps/cs/src/pages/module/ui/module-page.tsx b/apps/cs/src/pages/module/ui/module-page.tsx index 1749bdfbd..d97f213fb 100644 --- a/apps/cs/src/pages/module/ui/module-page.tsx +++ b/apps/cs/src/pages/module/ui/module-page.tsx @@ -2,45 +2,76 @@ import { useState } from "react"; import { useRouter } from "next/navigation"; + import { keepPreviousData, useQuery } from "@tanstack/react-query"; -import { getCoreRowModel, type PaginationState } from "@tanstack/react-table"; -import { Button, Input, Label } from "@common/components"; -import { CodeSelect } from "@/entities/code"; -import { ENDPOINT } from "@/shared/config"; -import { useDataTable } from "@/shared/lib"; import { - AuthorizationsApi, + getCoreRowModel, + type OnChangeFn, + type PaginationState, +} from "@tanstack/react-table"; + +import { ENDPOINT } from "@/shared/config"; +import { useDataTable, useSearchParamsState } from "@/shared/lib"; +import { type Authorizations, - type AuthorizationsParams, + AuthorizationsApi, } from "@/entities/authorization"; +import { CodeSelect } from "@/entities/code"; +import { Button, Input, Label } from "@common/components"; + import { columns } from "../model/authorizations-table-columns"; +const DEFAULT_PARAMS = { + authorizationName: "", + httpMethodCode: "", + sort: "regDt,desc", + page: 0, + size: 10, +}; + function ModulePage() { const router = useRouter(); - - const [authorizationName, setAuthorizationName] = useState(""); - const [httpMethodCode, setHttpMethodCode] = useState(""); - const [searchParams, setSearchParams] = useState({ - authorizationName: "", - httpMethodCode: "", - sort: "regDt,desc", - }); - const [pagination, setPagination] = useState({ - pageIndex: 0, - pageSize: 10, - }); + const { params, setParams, resetParams } = + useSearchParamsState(DEFAULT_PARAMS); + const [authorizationName, setAuthorizationName] = useState( + params.authorizationName, + ); + const [httpMethodCode, setHttpMethodCode] = useState(params.httpMethodCode); const query = useQuery({ - queryKey: [ENDPOINT.USER_SERVICE.AUTHORIZATIONS, searchParams, pagination], + queryKey: [ENDPOINT.USER_SERVICE.AUTHORIZATIONS, params], queryFn: () => AuthorizationsApi.getAuthorizationsList({ - ...searchParams, - page: pagination.pageIndex, - size: pagination.pageSize, + authorizationName: params.authorizationName, + httpMethodCode: params.httpMethodCode, + sort: params.sort, + page: params.page, + size: params.size, }), placeholderData: keepPreviousData, }); + const pagination: PaginationState = { + pageIndex: params.page, + pageSize: params.size, + }; + + const handlePaginationChange: OnChangeFn = (updater) => { + const next = typeof updater === "function" ? updater(pagination) : updater; + setParams({ page: next.pageIndex, size: next.pageSize }); + }; + + const handleSubmit = (e: React.FormEvent) => { + e.preventDefault(); + setParams({ authorizationName, httpMethodCode, page: 0 }); + }; + + const handleReset = () => { + setAuthorizationName(""); + setHttpMethodCode(""); + resetParams(); + }; + const handleRowClick = (row: Authorizations) => { router.push(`/module/register/${row.authorizationNo}`); }; @@ -52,7 +83,7 @@ function ModulePage() { state: { pagination, }, - onPaginationChange: setPagination, + onPaginationChange: handlePaginationChange, getCoreRowModel: getCoreRowModel(), manualPagination: true, }, @@ -62,29 +93,6 @@ function ModulePage() { }, }); - const handleSubmit = (e: React.SubmitEvent) => { - e.preventDefault(); - setPagination({ - ...pagination, - pageIndex: 0, - }); - setSearchParams({ - ...searchParams, - authorizationName, - httpMethodCode, - }); - }; - - const handleReset = () => { - setAuthorizationName(""); - setHttpMethodCode(""); - setSearchParams({ - ...searchParams, - authorizationName: "", - httpMethodCode: "", - }); - }; - return (
diff --git a/apps/cs/src/pages/popup/ui/popup-page.tsx b/apps/cs/src/pages/popup/ui/popup-page.tsx index 3ce6d131a..6dd9e1721 100644 --- a/apps/cs/src/pages/popup/ui/popup-page.tsx +++ b/apps/cs/src/pages/popup/ui/popup-page.tsx @@ -2,70 +2,75 @@ import { useEffect, useState } from "react"; import { useRouter } from "next/navigation"; + import { keepPreviousData, useQuery } from "@tanstack/react-query"; import { getCoreRowModel, + type OnChangeFn, type PaginationState, type RowSelectionState, } from "@tanstack/react-table"; -import { Button, Input, Label } from "@common/components"; + +import { ENDPOINT } from "@/shared/config"; +import { useDataTable, useSearchParamsState } from "@/shared/lib"; import { AuthorityButton } from "@/entities/menu-authority"; import { POSTING_TYPE, PostingDialog } from "@/entities/posting"; -import { ENDPOINT } from "@/shared/config"; -import { useDataTable } from "@/shared/lib"; +import { Button, Input, Label } from "@common/components"; + import { PopupApi } from "../api/popup-service"; +import type { Popup } from "../model/popup-interface"; import { columns } from "../model/table-columns"; -import type { Popup, PopupParams } from "../model/popup-interface"; type PostingTarget = { pstgTrgtNm: string; pstgTrgtNo: number; }; +const DEFAULT_PARAMS = { + keyword: "", + sort: "regDt,desc", + page: 0, + size: 10, +}; + function PopupPage() { const router = useRouter(); - - const [keyword, setKeyword] = useState(""); - const [searchParams, setSearchParams] = useState({ - keyword: "", - sort: "regDt,desc", - }); - const [pagination, setPagination] = useState({ - pageIndex: 0, - pageSize: 10, - }); + const { params, setParams, resetParams } = + useSearchParamsState(DEFAULT_PARAMS); + const [keyword, setKeyword] = useState(params.keyword); const [rowSelection, setRowSelection] = useState({}); const [postingTargets, setPostingTargets] = useState([]); const query = useQuery({ - queryKey: [ENDPOINT.CMS_SERVICE.POPUPS, searchParams, pagination], + queryKey: [ENDPOINT.CMS_SERVICE.POPUPS, params], queryFn: () => PopupApi.getPopupList({ - ...searchParams, - page: pagination.pageIndex, - size: pagination.pageSize, + keyword: params.keyword, + sort: params.sort, + page: params.page, + size: params.size, }), placeholderData: keepPreviousData, }); - const handleSubmit = (e: React.SubmitEvent) => { + const pagination: PaginationState = { + pageIndex: params.page, + pageSize: params.size, + }; + + const handlePaginationChange: OnChangeFn = (updater) => { + const next = typeof updater === "function" ? updater(pagination) : updater; + setParams({ page: next.pageIndex, size: next.pageSize }); + }; + + const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); - setPagination({ - ...pagination, - pageIndex: 0, - }); - setSearchParams({ - ...searchParams, - keyword, - }); + setParams({ keyword, page: 0 }); }; const handleReset = () => { setKeyword(""); - setSearchParams({ - ...searchParams, - keyword: "", - }); + resetParams(); }; const handleRowClick = (row: Popup) => { @@ -82,7 +87,7 @@ function PopupPage() { }, manualPagination: true, getCoreRowModel: getCoreRowModel(), - onPaginationChange: setPagination, + onPaginationChange: handlePaginationChange, onRowSelectionChange: setRowSelection, }, dataTableOptions: { diff --git a/apps/cs/src/pages/recent/ui/recent-page.tsx b/apps/cs/src/pages/recent/ui/recent-page.tsx index 803317669..7d74cc714 100644 --- a/apps/cs/src/pages/recent/ui/recent-page.tsx +++ b/apps/cs/src/pages/recent/ui/recent-page.tsx @@ -1,15 +1,35 @@ "use client"; -import dayjs from "dayjs"; import { useState } from "react"; -import { useRouter } from "next/navigation"; +import { usePathname, useRouter, useSearchParams } from "next/navigation"; + import { useConfirm } from "@frontend-opensource/use-react-hooks"; import { keepPreviousData, useQuery } from "@tanstack/react-query"; import { getCoreRowModel, + type OnChangeFn, type PaginationState, type RowSelectionState, } from "@tanstack/react-table"; +import dayjs from "dayjs"; + +import { ENDPOINT } from "@/shared/config"; +import { + useAlertStore, + useDataTable, + useSearchParamsState, + useSelectPrompt, +} from "@/shared/lib"; +import { InputDateRangePicker } from "@/shared/ui/input-date-range-picker"; +import { BoardApi } from "@/entities/board"; +import { AuthorityButton } from "@/entities/menu-authority"; +import { + type DeletePost, + deleteReasonMessages, + PostApi, + type RecentPost, +} from "@/entities/post"; +import { SortSelect } from "@/widgets/post"; import { Button, Input, @@ -20,76 +40,72 @@ import { SelectTrigger, SelectValue, } from "@common/components"; -import { SortSelect } from "@/widgets/post"; -import { - PostApi, - deleteReasonMessages, - type DeletePost, - type RecentPost, - type RecentPostParams, -} from "@/entities/post"; -import { BoardApi } from "@/entities/board"; -import { AuthorityButton } from "@/entities/menu-authority"; -import { ENDPOINT } from "@/shared/config"; -import { InputDateRangePicker } from "@/shared/ui/input-date-range-picker"; -import { useAlertStore, useSelectPrompt, useDataTable } from "@/shared/lib"; + import { columns } from "../model/table-columns"; + import { MovePostDialog } from "./move-post-dialog"; type DateRange = { - from?: Date | undefined; - to?: Date | undefined; + from?: Date | null | undefined; + to?: Date | null | undefined; }; const selectData = Object.entries(deleteReasonMessages).map( ([label, value]) => ({ label, value }), ); +const DEFAULT_PARAMS = { + keywordType: "", + keyword: "", + bbsId: "", + delYn: "N", + frDateYmd: "", + toDateYmd: "", + sort: "regDt,desc", + page: 0, + size: 10, +}; + +function parseDateRange(frDateYmd: string, toDateYmd: string): DateRange { + return { + from: frDateYmd ? dayjs(frDateYmd, "YYYYMMDD").toDate() : undefined, + to: toDateYmd ? dayjs(toDateYmd, "YYYYMMDD").toDate() : undefined, + }; +} + function RecentPage() { const router = useRouter(); + const pathname = usePathname(); + const searchParams = useSearchParams(); const { prompt } = useSelectPrompt(selectData); const { confirm } = useConfirm(); const alert = useAlertStore((state) => state.setMessage); + const { params, setParams, resetParams } = + useSearchParamsState(DEFAULT_PARAMS); - const [tableSort, setTableSort] = useState("regDt,desc"); - const [pagination, setPagination] = useState({ - pageIndex: 0, - pageSize: 10, - }); const [rowSelection, setRowSelection] = useState({}); const [presetDateRange, setPresetDateRange] = useState(""); - const [dateRange, setDateRange] = useState({ - from: undefined, - to: undefined, - }); - const [keywordType, setKeywordType] = useState(""); - const [keyword, setKeyword] = useState(""); - const [bbsId, setBbsId] = useState(null); - const [delYn, setDelYn] = useState("N"); - const [searchParams, setSearchParams] = useState({ - keywordType: "", - keyword: "", - bbsId: null, - delYn: "N", - frDateYmd: "", - toDateYmd: "", - sort: "regDt,desc", - }); - const [isDeletePostData, setIsDeletePostData] = useState(false); + const [dateRange, setDateRange] = useState(() => + parseDateRange(params.frDateYmd, params.toDateYmd), + ); + const [keywordType, setKeywordType] = useState(params.keywordType); + const [keyword, setKeyword] = useState(params.keyword); + const [bbsId, setBbsId] = useState(params.bbsId); + const [delYn, setDelYn] = useState(params.delYn); const query = useQuery({ - queryKey: [ - ENDPOINT.BOARD_SERVICE.POSTS, - searchParams, - pagination, - tableSort, - ], + queryKey: [ENDPOINT.BOARD_SERVICE.POSTS, params], queryFn: () => PostApi.getRecentPostList({ - ...searchParams, - page: pagination.pageIndex, - size: pagination.pageSize, - sort: tableSort, + keywordType: params.keywordType, + keyword: params.keyword, + bbsId: params.bbsId ? parseInt(params.bbsId) : null, + delYn: params.delYn, + frDateYmd: params.frDateYmd, + toDateYmd: params.toDateYmd, + sort: params.sort, + page: params.page, + size: params.size, }), placeholderData: keepPreviousData, }); @@ -99,9 +115,22 @@ function RecentPage() { queryFn: () => BoardApi.getBoardList(), }); + const pagination: PaginationState = { + pageIndex: params.page, + pageSize: params.size, + }; + + const handlePaginationChange: OnChangeFn = (updater) => { + const next = typeof updater === "function" ? updater(pagination) : updater; + setParams({ page: next.pageIndex, size: next.pageSize }); + }; + + const isDeletePostData = params.delYn === "Y"; + const handleRowClick = (row: RecentPost) => { + const from = `${pathname}${searchParams?.toString() ? `?${searchParams.toString()}` : ""}`; router.push( - `/bbs/${row.bbsTypeCd.toLowerCase()}/${row.bbsId}/${row.pstNo}`, + `/bbs/${row.bbsTypeCd.toLowerCase()}/${row.bbsId}/${row.pstNo}?from=${encodeURIComponent(from)}`, ); }; @@ -116,7 +145,7 @@ function RecentPage() { manualPagination: true, enableMultiRowSelection: true, getCoreRowModel: getCoreRowModel(), - onPaginationChange: setPagination, + onPaginationChange: handlePaginationChange, onRowSelectionChange: setRowSelection, }, dataTableOptions: { @@ -127,45 +156,32 @@ function RecentPage() { const isSelectedRow = table.getFilteredSelectedRowModel().rows.length > 0; - const handleSubmit = (e: React.SubmitEvent) => { + const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); - setIsDeletePostData(delYn === "Y"); - setPagination({ - ...pagination, - pageIndex: 0, - }); - setSearchParams({ - ...searchParams, + setParams({ keywordType, keyword, - bbsId: bbsId ? parseInt(bbsId) : null, + bbsId, delYn, frDateYmd: dateRange?.from ? dayjs(dateRange.from).format("YYYYMMDD") : "", toDateYmd: dateRange?.to ? dayjs(dateRange.to).format("YYYYMMDD") : "", + page: 0, }); }; const handleReset = () => { setKeywordType(""); setKeyword(""); - setBbsId(null); + setBbsId(""); setDelYn("N"); + setPresetDateRange(""); setDateRange({ from: undefined, to: undefined, }); - setSearchParams({ - ...searchParams, - keywordType: "", - keyword: "", - bbsId: null, - delYn: "N", - frDateYmd: "", - toDateYmd: "", - }); - setIsDeletePostData(false); + resetParams(); }; const handlePresetDateRange = (value: string) => { @@ -273,10 +289,7 @@ function RecentPage() { setDateRange={handleDateRangeChange} /> - @@ -289,7 +302,7 @@ function RecentPage() { - @@ -376,10 +389,10 @@ function RecentPage() { )} - + setParams({ sort: value })} + />
diff --git a/apps/cs/src/pages/role/ui/role-page.tsx b/apps/cs/src/pages/role/ui/role-page.tsx index b370ed338..a6c7ec2d1 100644 --- a/apps/cs/src/pages/role/ui/role-page.tsx +++ b/apps/cs/src/pages/role/ui/role-page.tsx @@ -2,39 +2,68 @@ import { useState } from "react"; import { useRouter } from "next/navigation"; -import { useQuery } from "@tanstack/react-query"; -import { getCoreRowModel, type PaginationState } from "@tanstack/react-table"; -import { Button, Input, Label } from "@common/components"; -import { RoleApi, type Role, type RoleParams } from "@/entities/role"; + +import { keepPreviousData, useQuery } from "@tanstack/react-query"; +import { + getCoreRowModel, + type OnChangeFn, + type PaginationState, +} from "@tanstack/react-table"; + import { ENDPOINT } from "@/shared/config"; -import { useAlertStore, useDataTable } from "@/shared/lib"; +import { useDataTable, useSearchParamsState } from "@/shared/lib"; +import { type Role, RoleApi } from "@/entities/role"; +import { Button, Input, Label } from "@common/components"; + import { createColumns } from "../model/table-columns"; +const DEFAULT_PARAMS = { + keywordType: "roleName", + keyword: "", + sort: "regDt,desc", + page: 0, + size: 10, +}; + function RolePage() { const router = useRouter(); - const alert = useAlertStore((state) => state.setMessage); - - const [keyword, setKeyword] = useState(""); - const [searchParams, setSearchParams] = useState({ - keywordType: "roleName", - keyword: "", - sort: "regDt,desc", - }); - const [pagination, setPagination] = useState({ - pageIndex: 0, - pageSize: 10, - }); + const { params, setParams, resetParams } = + useSearchParamsState(DEFAULT_PARAMS); + const [keyword, setKeyword] = useState(params.keyword); const query = useQuery({ - queryKey: [ENDPOINT.USER_SERVICE.ROLES, searchParams, pagination], + queryKey: [ENDPOINT.USER_SERVICE.ROLES, params], queryFn: () => RoleApi.getRoles({ - ...searchParams, - page: pagination.pageIndex, - size: pagination.pageSize, + keywordType: params.keywordType, + keyword: params.keyword, + sort: params.sort, + page: params.page, + size: params.size, }), + placeholderData: keepPreviousData, }); + const pagination: PaginationState = { + pageIndex: params.page, + pageSize: params.size, + }; + + const handlePaginationChange: OnChangeFn = (updater) => { + const next = typeof updater === "function" ? updater(pagination) : updater; + setParams({ page: next.pageIndex, size: next.pageSize }); + }; + + const handleSubmit = (e: React.FormEvent) => { + e.preventDefault(); + setParams({ keyword, page: 0 }); + }; + + const handleReset = () => { + setKeyword(""); + resetParams(); + }; + const handleRowClick = (row: Role) => { router.push(`/role/register/${row.roleId}`); }; @@ -48,7 +77,7 @@ function RolePage() { }, manualPagination: true, getCoreRowModel: getCoreRowModel(), - onPaginationChange: setPagination, + onPaginationChange: handlePaginationChange, }, dataTableOptions: { onRowClick: handleRowClick, @@ -56,26 +85,6 @@ function RolePage() { }, }); - const handleSubmit = (e: React.SubmitEvent) => { - e.preventDefault(); - setPagination({ - ...pagination, - pageIndex: 0, - }); - setSearchParams({ - ...searchParams, - keyword, - }); - }; - - const handleReset = () => { - setKeyword(""); - setSearchParams({ - ...searchParams, - keyword: "", - }); - }; - return (
diff --git a/apps/cs/src/pages/site/ui/site-page.tsx b/apps/cs/src/pages/site/ui/site-page.tsx index fbdd9d36c..20a38e998 100644 --- a/apps/cs/src/pages/site/ui/site-page.tsx +++ b/apps/cs/src/pages/site/ui/site-page.tsx @@ -1,54 +1,65 @@ "use client"; -import "@common/assets/styles/grid.css"; - import { useState } from "react"; import { useRouter } from "next/navigation"; + import { keepPreviousData, useQuery } from "@tanstack/react-query"; -import { getCoreRowModel, type PaginationState } from "@tanstack/react-table"; -import { Button, Input, Label } from "@common/components"; -import { SiteApi, type Site, type SiteParams } from "@/entities/site"; +import { + getCoreRowModel, + type OnChangeFn, + type PaginationState, +} from "@tanstack/react-table"; + import { ENDPOINT } from "@/shared/config"; -import { useDataTable } from "@/shared/lib"; +import { useDataTable, useSearchParamsState } from "@/shared/lib"; +import { type Site, SiteApi } from "@/entities/site"; +import { Button, Input, Label } from "@common/components"; + import { columns } from "../model/table-columns"; +const DEFAULT_PARAMS = { + siteNm: "", + sort: "regDt,desc", + page: 0, + size: 10, +}; + function SitePage() { const router = useRouter(); - const [siteNm, setSiteNm] = useState(""); - const [searchParams, setSearchParams] = useState({ - siteNm: "", - sort: "regDt,desc", - }); - const [pagination, setPagination] = useState({ - pageIndex: 0, - pageSize: 10, - }); + const { params, setParams, resetParams } = + useSearchParamsState(DEFAULT_PARAMS); + const [siteNm, setSiteNm] = useState(params.siteNm); const query = useQuery({ - queryKey: [ENDPOINT.CMS_SERVICE.SITES, searchParams, pagination], + queryKey: [ENDPOINT.CMS_SERVICE.SITES, params], queryFn: () => SiteApi.getSiteList({ - ...searchParams, - page: pagination.pageIndex, - size: pagination.pageSize, + siteNm: params.siteNm, + sort: params.sort, + page: params.page, + size: params.size, }), placeholderData: keepPreviousData, }); - const handleSubmit = (e: React.SubmitEvent) => { + const pagination: PaginationState = { + pageIndex: params.page, + pageSize: params.size, + }; + + const handlePaginationChange: OnChangeFn = (updater) => { + const next = typeof updater === "function" ? updater(pagination) : updater; + setParams({ page: next.pageIndex, size: next.pageSize }); + }; + + const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); - setSearchParams({ - ...searchParams, - siteNm, - }); + setParams({ siteNm, page: 0 }); }; const handleReset = () => { setSiteNm(""); - setSearchParams({ - ...searchParams, - siteNm: "", - }); + resetParams(); }; const handleRowClick = (row: Site) => { @@ -62,7 +73,7 @@ function SitePage() { state: { pagination, }, - onPaginationChange: setPagination, + onPaginationChange: handlePaginationChange, getCoreRowModel: getCoreRowModel(), manualPagination: true, }, diff --git a/apps/cs/src/pages/survey/ui/survey-page.tsx b/apps/cs/src/pages/survey/ui/survey-page.tsx index 27f080343..f3e0481d5 100644 --- a/apps/cs/src/pages/survey/ui/survey-page.tsx +++ b/apps/cs/src/pages/survey/ui/survey-page.tsx @@ -2,19 +2,23 @@ import { useEffect, useState } from "react"; import { useRouter } from "next/navigation"; + import { keepPreviousData, useQuery } from "@tanstack/react-query"; import { getCoreRowModel, + type OnChangeFn, type PaginationState, type RowSelectionState, } from "@tanstack/react-table"; -import { Button, Input, Label } from "@common/components"; -import { POSTING_TYPE, PostingDialog } from "@/entities/posting"; -import { AuthorityButton } from "@/entities/menu-authority"; + import { ENDPOINT } from "@/shared/config"; -import { useDataTable } from "@/shared/lib"; +import { useDataTable, useSearchParamsState } from "@/shared/lib"; +import { AuthorityButton } from "@/entities/menu-authority"; +import { POSTING_TYPE, PostingDialog } from "@/entities/posting"; +import { Button, Input, Label } from "@common/components"; + import { SurveyApi } from "../api/survey-service"; -import type { Survey, SurveyParams } from "../model/survey-interface"; +import type { Survey } from "../model/survey-interface"; import { columns } from "../model/survey-table-columns"; type PostingTarget = { @@ -22,32 +26,53 @@ type PostingTarget = { pstgTrgtNo: number; }; +const DEFAULT_PARAMS = { + srvyTtl: "", + sort: "regDt,desc", + page: 0, + size: 10, +}; + function SurveyPage() { const router = useRouter(); - - const [srvyTtl, setSrvyTtl] = useState(""); - const [searchParams, setSearchParams] = useState({ - srvyTtl: "", - sort: "regDt,desc", - }); - const [pagination, setPagination] = useState({ - pageIndex: 0, - pageSize: 10, - }); + const { params, setParams, resetParams } = + useSearchParamsState(DEFAULT_PARAMS); + const [srvyTtl, setSrvyTtl] = useState(params.srvyTtl); const [rowSelection, setRowSelection] = useState({}); const [postingTargets, setPostingTargets] = useState([]); const query = useQuery({ - queryKey: [ENDPOINT.CMS_SERVICE.SURVEY, searchParams, pagination], + queryKey: [ENDPOINT.CMS_SERVICE.SURVEY, params], queryFn: () => SurveyApi.getSurveyList({ - ...searchParams, - page: pagination.pageIndex, - size: pagination.pageSize, + srvyTtl: params.srvyTtl, + sort: params.sort, + page: params.page, + size: params.size, }), placeholderData: keepPreviousData, }); + const pagination: PaginationState = { + pageIndex: params.page, + pageSize: params.size, + }; + + const handlePaginationChange: OnChangeFn = (updater) => { + const next = typeof updater === "function" ? updater(pagination) : updater; + setParams({ page: next.pageIndex, size: next.pageSize }); + }; + + const handleSubmit = (e: React.FormEvent) => { + e.preventDefault(); + setParams({ srvyTtl, page: 0 }); + }; + + const handleReset = () => { + setSrvyTtl(""); + resetParams(); + }; + const handleRowClick = (row: Survey) => { router.push(`/survey/${row.srvySn}`); }; @@ -62,7 +87,7 @@ function SurveyPage() { }, manualPagination: true, getCoreRowModel: getCoreRowModel(), - onPaginationChange: setPagination, + onPaginationChange: handlePaginationChange, onRowSelectionChange: setRowSelection, }, dataTableOptions: { @@ -71,26 +96,6 @@ function SurveyPage() { }, }); - const handleSubmit = (e: React.SubmitEvent) => { - e.preventDefault(); - setPagination({ - ...pagination, - pageIndex: 0, - }); - setSearchParams({ - ...searchParams, - srvyTtl, - }); - }; - - const handleReset = () => { - setSrvyTtl(""); - setSearchParams({ - ...searchParams, - srvyTtl: "", - }); - }; - useEffect(() => { const postingTargets = table .getFilteredSelectedRowModel() diff --git a/apps/cs/src/pages/template/ui/template-page.tsx b/apps/cs/src/pages/template/ui/template-page.tsx index d4ceb3bca..5db3f1572 100644 --- a/apps/cs/src/pages/template/ui/template-page.tsx +++ b/apps/cs/src/pages/template/ui/template-page.tsx @@ -2,58 +2,70 @@ import { useState } from "react"; import { useRouter } from "next/navigation"; + import { keepPreviousData, useQuery } from "@tanstack/react-query"; -import { getCoreRowModel, type PaginationState } from "@tanstack/react-table"; -import { Button, Input, Label } from "@common/components"; -import { CodeSelect } from "@/entities/code"; +import { + getCoreRowModel, + type OnChangeFn, + type PaginationState, +} from "@tanstack/react-table"; + import { ENDPOINT } from "@/shared/config"; -import { useDataTable } from "@/shared/lib"; +import { useDataTable, useSearchParamsState } from "@/shared/lib"; +import { CodeSelect } from "@/entities/code"; +import { Button, Input, Label } from "@common/components"; + import { TemplateApi } from "../api/template-service"; +import type { Template } from "../model/template-interface"; import { columns } from "../model/template-table-columns"; -import type { Template, TemplateParams } from "../model/template-interface"; + +const DEFAULT_PARAMS = { + keyword: "", + tmpltSeCd: "", + sort: "regDt,desc", + page: 0, + size: 10, +}; function TemplatePage() { const router = useRouter(); - const [keyword, setKeyword] = useState(""); - const [tmpltSeCd, setTmpltSeCd] = useState(""); - const [searchParams, setSearchParams] = useState({ - keyword: "", - tmpltSeCd: "", - sort: "regDt,desc", - }); - const [pagination, setPagination] = useState({ - pageIndex: 0, - pageSize: 10, - }); + const { params, setParams, resetParams } = + useSearchParamsState(DEFAULT_PARAMS); + const [keyword, setKeyword] = useState(params.keyword); + const [tmpltSeCd, setTmpltSeCd] = useState(params.tmpltSeCd); const query = useQuery({ - queryKey: [ENDPOINT.CMS_SERVICE.TEMPLATE, searchParams, pagination], + queryKey: [ENDPOINT.CMS_SERVICE.TEMPLATE, params], queryFn: () => TemplateApi.getTemplateList({ - ...searchParams, - page: pagination.pageIndex, - size: pagination.pageSize, + keyword: params.keyword, + tmpltSeCd: params.tmpltSeCd, + sort: params.sort, + page: params.page, + size: params.size, }), placeholderData: keepPreviousData, }); - const handleSubmit = (e: React.SubmitEvent) => { + const pagination: PaginationState = { + pageIndex: params.page, + pageSize: params.size, + }; + + const handlePaginationChange: OnChangeFn = (updater) => { + const next = typeof updater === "function" ? updater(pagination) : updater; + setParams({ page: next.pageIndex, size: next.pageSize }); + }; + + const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); - setSearchParams({ - ...searchParams, - keyword, - tmpltSeCd, - }); + setParams({ keyword, tmpltSeCd, page: 0 }); }; const handleReset = () => { setKeyword(""); setTmpltSeCd(""); - setSearchParams({ - ...searchParams, - keyword: "", - tmpltSeCd: "", - }); + resetParams(); }; const handleRowClick = (row: Template) => { @@ -67,7 +79,7 @@ function TemplatePage() { state: { pagination, }, - onPaginationChange: setPagination, + onPaginationChange: handlePaginationChange, getCoreRowModel: getCoreRowModel(), manualPagination: true, }, diff --git a/apps/cs/src/pages/terms/ui/terms-page.tsx b/apps/cs/src/pages/terms/ui/terms-page.tsx index ea00276df..73b6b0d16 100644 --- a/apps/cs/src/pages/terms/ui/terms-page.tsx +++ b/apps/cs/src/pages/terms/ui/terms-page.tsx @@ -2,63 +2,70 @@ import { useState } from "react"; import { useRouter } from "next/navigation"; + import { keepPreviousData, useQuery } from "@tanstack/react-query"; -import { getCoreRowModel, type PaginationState } from "@tanstack/react-table"; -import { Button, Input, Label } from "@common/components"; -import { CodeSelect } from "@/entities/code"; +import { + getCoreRowModel, + type OnChangeFn, + type PaginationState, +} from "@tanstack/react-table"; + import { ENDPOINT } from "@/shared/config"; -import { useDataTable } from "@/shared/lib"; +import { useDataTable, useSearchParamsState } from "@/shared/lib"; +import { CodeSelect } from "@/entities/code"; +import { Button, Input, Label } from "@common/components"; + import { TermsApi } from "../api/terms-service"; +import type { Terms } from "../model/terms-interface"; import { columns } from "../model/terms-table-columns"; -import type { TermsParams, Terms } from "../model/terms-interface"; + +const DEFAULT_PARAMS = { + keyword: "", + trmsSeCd: "", + sort: "regDt,desc", + page: 0, + size: 10, +}; function TermsPage() { const router = useRouter(); - - const [keyword, setKeyword] = useState(""); - const [trmsSeCd, setTrmsSeCd] = useState(""); - const [searchParams, setSearchParams] = useState({ - keyword: "", - trmsSeCd: "", - sort: "regDt,desc", - }); - const [pagination, setPagination] = useState({ - pageIndex: 0, - pageSize: 10, - }); + const { params, setParams, resetParams } = + useSearchParamsState(DEFAULT_PARAMS); + const [keyword, setKeyword] = useState(params.keyword); + const [trmsSeCd, setTrmsSeCd] = useState(params.trmsSeCd); const query = useQuery({ - queryKey: [ENDPOINT.CMS_SERVICE.TERMS, searchParams, pagination], + queryKey: [ENDPOINT.CMS_SERVICE.TERMS, params], queryFn: () => TermsApi.getTermsList({ - ...searchParams, - page: pagination.pageIndex, - size: pagination.pageSize, + keyword: params.keyword, + trmsSeCd: params.trmsSeCd, + sort: params.sort, + page: params.page, + size: params.size, }), placeholderData: keepPreviousData, }); - const handleSubmit = (e: React.SubmitEvent) => { + const pagination: PaginationState = { + pageIndex: params.page, + pageSize: params.size, + }; + + const handlePaginationChange: OnChangeFn = (updater) => { + const next = typeof updater === "function" ? updater(pagination) : updater; + setParams({ page: next.pageIndex, size: next.pageSize }); + }; + + const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); - setPagination({ - ...pagination, - pageIndex: 0, - }); - setSearchParams({ - ...searchParams, - keyword, - trmsSeCd, - }); + setParams({ keyword, trmsSeCd, page: 0 }); }; const handleReset = () => { setKeyword(""); setTrmsSeCd(""); - setSearchParams({ - ...searchParams, - keyword: "", - trmsSeCd: "", - }); + resetParams(); }; const handleRowClick = (row: Terms) => { @@ -72,7 +79,7 @@ function TermsPage() { state: { pagination, }, - onPaginationChange: setPagination, + onPaginationChange: handlePaginationChange, getCoreRowModel: getCoreRowModel(), manualPagination: true, }, diff --git a/apps/cs/src/pages/users/ui/users-page.tsx b/apps/cs/src/pages/users/ui/users-page.tsx index 17b44707c..cabf8eb42 100644 --- a/apps/cs/src/pages/users/ui/users-page.tsx +++ b/apps/cs/src/pages/users/ui/users-page.tsx @@ -3,19 +3,19 @@ import { useState } from "react"; import { useRouter } from "next/navigation"; -import { useQuery } from "@tanstack/react-query"; -import { getCoreRowModel, type PaginationState } from "@tanstack/react-table"; +import { keepPreviousData, useQuery } from "@tanstack/react-query"; +import { + getCoreRowModel, + type OnChangeFn, + type PaginationState, +} from "@tanstack/react-table"; import dayjs from "dayjs"; import { ENDPOINT } from "@/shared/config"; -import { useDataTable } from "@/shared/lib"; +import { useDataTable, useSearchParamsState } from "@/shared/lib"; import { InputDateRangePicker } from "@/shared/ui/input-date-range-picker"; import { CodeApi } from "@/entities/code"; -import { - UserApi, - type UserListResponse, - type UserSearchParams, -} from "@/entities/user"; +import { UserApi, type UserListResponse } from "@/entities/user"; import { Button, Checkbox, @@ -35,34 +35,39 @@ type DateRange = { to?: Date | null; }; +const DEFAULT_PARAMS = { + keywordType: "all", + keyword: "", + userStateCode: "", + aprvYn: "", + grpId: "", + frDateYmd: "", + toDateYmd: "", + sort: "regDt,desc", + page: 0, + size: 10, +}; + +function parseDateRange(frDateYmd: string, toDateYmd: string): DateRange { + return { + from: frDateYmd ? dayjs(frDateYmd, "YYYYMMDD").toDate() : undefined, + to: toDateYmd ? dayjs(toDateYmd, "YYYYMMDD").toDate() : undefined, + }; +} + function UsersPage() { const router = useRouter(); - - const [pagination, setPagination] = useState({ - pageIndex: 0, - pageSize: 10, - }); + const { params, setParams, resetParams } = + useSearchParamsState(DEFAULT_PARAMS); const [presetDateRange, setPresetDateRange] = useState(""); - const [dateRange, setDateRange] = useState({ - from: undefined, - to: undefined, - }); - const [keywordType, setKeywordType] = useState("all"); - const [keyword, setKeyword] = useState(""); - const [userStateCode, setUserStateCode] = useState(""); - const [aprvYn, setAprvYn] = useState(""); - const [grpId, setGrpId] = useState(""); - - const [searchParams, setSearchParams] = useState({ - keywordType: "all", - keyword: "", - userStateCode: "", - aprvYn: "", - grpId: "", - frDateYmd: "", - toDateYmd: "", - sort: "regDt,desc", - }); + const [dateRange, setDateRange] = useState(() => + parseDateRange(params.frDateYmd, params.toDateYmd), + ); + const [keywordType, setKeywordType] = useState(params.keywordType); + const [keyword, setKeyword] = useState(params.keyword); + const [userStateCode, setUserStateCode] = useState(params.userStateCode); + const [aprvYn, setAprvYn] = useState(params.aprvYn); + const [grpId, setGrpId] = useState(params.grpId); const { data: userSttsStats } = useQuery({ queryKey: [ENDPOINT.USER_SERVICE.USERS, "userStatusStatistics"], @@ -70,13 +75,21 @@ function UsersPage() { }); const query = useQuery({ - queryKey: [ENDPOINT.USER_SERVICE.USERS, searchParams, pagination], + queryKey: [ENDPOINT.USER_SERVICE.USERS, params], queryFn: () => UserApi.findPageUser({ - ...searchParams, - page: pagination.pageIndex, - size: pagination.pageSize, + keywordType: params.keywordType, + keyword: params.keyword, + userStateCode: params.userStateCode, + aprvYn: params.aprvYn, + grpId: params.grpId, + frDateYmd: params.frDateYmd, + toDateYmd: params.toDateYmd, + sort: params.sort, + page: params.page, + size: params.size, }), + placeholderData: keepPreviousData, }); const { data: userStateCodes } = useQuery({ @@ -84,6 +97,16 @@ function UsersPage() { queryFn: () => CodeApi.getCode("USERSTTS"), }); + const pagination: PaginationState = { + pageIndex: params.page, + pageSize: params.size, + }; + + const handlePaginationChange: OnChangeFn = (updater) => { + const next = typeof updater === "function" ? updater(pagination) : updater; + setParams({ page: next.pageIndex, size: next.pageSize }); + }; + const handleRowClick = (row: UserListResponse) => { router.push(`/users/${row.userUnqId}`); }; @@ -97,7 +120,7 @@ function UsersPage() { }, manualPagination: true, getCoreRowModel: getCoreRowModel(), - onPaginationChange: setPagination, + onPaginationChange: handlePaginationChange, }, dataTableOptions: { onRowClick: handleRowClick, @@ -105,14 +128,9 @@ function UsersPage() { }, }); - const handleSubmit = (e: React.SubmitEvent) => { + const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); - setPagination({ - ...pagination, - pageIndex: 0, - }); - setSearchParams({ - ...searchParams, + setParams({ keywordType, keyword, userStateCode, @@ -122,6 +140,7 @@ function UsersPage() { ? dayjs(dateRange.from).format("YYYYMMDD") : "", toDateYmd: dateRange?.to ? dayjs(dateRange.to).format("YYYYMMDD") : "", + page: 0, }); }; @@ -131,20 +150,12 @@ function UsersPage() { setUserStateCode(""); setAprvYn(""); setGrpId(""); + setPresetDateRange(""); setDateRange({ from: undefined, to: undefined, }); - setSearchParams({ - ...searchParams, - keywordType: "all", - keyword: "", - userStateCode: "", - aprvYn: "", - grpId: "", - frDateYmd: "", - toDateYmd: "", - }); + resetParams(); }; const handlePresetDateRange = (value: string) => { @@ -351,12 +362,9 @@ function UsersPage() {

회원 목록