) => {
event.preventDefault();
- setPagination((prev) => ({ ...prev, pageIndex: DEFAULT_PAGE_INDEX }));
- setSearchParams({
- ...DEFAULT_SEARCH_PARAMS,
+ setParams({
sewerBscPlanNm,
sewerBscPlanSeComCd,
taskSeComCd,
- admdstCd: sggComCd || sidoComCd || "",
+ sidoComCd,
+ sggComCd,
page: DEFAULT_PAGE_INDEX,
- size: pagination.pageSize,
});
};
+ const handlePaginationChange = (next: PaginationState) => {
+ setParams({ page: next.pageIndex, size: next.pageSize });
+ };
+
return (
@@ -163,7 +178,7 @@ function SewerBscPlanListPage() {
);
diff --git a/apps/as/src/pages/sewer-bsc-plan/ui/sewer-bsc-plan-list.tsx b/apps/as/src/pages/sewer-bsc-plan/ui/sewer-bsc-plan-list.tsx
index f5156c5b7..08bfb44a6 100644
--- a/apps/as/src/pages/sewer-bsc-plan/ui/sewer-bsc-plan-list.tsx
+++ b/apps/as/src/pages/sewer-bsc-plan/ui/sewer-bsc-plan-list.tsx
@@ -5,7 +5,7 @@ import { useRouter } from "next/navigation";
import { getCoreRowModel, type PaginationState } from "@tanstack/react-table";
-import { useDataTable } from "@/shared/lib";
+import { useDataTable, withListQs } from "@/shared/lib";
import {
type SewerBscPlanResponseDto,
type SewerBscPlanSearchRequestDto,
@@ -47,7 +47,7 @@ function SewerBscPlanList({ searchParams, pagination, onPaginationChange }: Sewe
const columns = useMemo(() => createSewerBscPlanColumns(), []);
const handleRowClick = (row: SewerBscPlanResponseDto) => {
- router.push(`/sewer-bsc-plan/${row.sewerBscPlanDocNo}?chgCycl=${row.chgCycl}`);
+ router.push(withListQs(`/sewer-bsc-plan/${row.sewerBscPlanDocNo}?chgCycl=${row.chgCycl}`));
};
const { tableComponent } = useDataTable({
diff --git a/apps/as/src/pages/sewer-bsc-plan/ui/sewer-bsc-plan-view-page.tsx b/apps/as/src/pages/sewer-bsc-plan/ui/sewer-bsc-plan-view-page.tsx
index 3099c4c37..079f56198 100644
--- a/apps/as/src/pages/sewer-bsc-plan/ui/sewer-bsc-plan-view-page.tsx
+++ b/apps/as/src/pages/sewer-bsc-plan/ui/sewer-bsc-plan-view-page.tsx
@@ -102,7 +102,9 @@ function SewerBscPlanViewPage({ id, propChgCycl }: SewerBscPlanViewPageProps) {
return (
-
+
+
+
>(
+ defaults: T,
+): UseSearchParamsStateReturn {
+ const searchParams = useSearchParams();
+ const defaultsRef = useRef(defaults);
+
+ const params = useMemo(
+ () => parseParams(searchParams, defaultsRef.current),
+ [searchParams],
+ );
+
+ const setParams = useCallback((partial: Partial) => {
+ const next = new URLSearchParams(window.location.search);
+ for (const [key, value] of Object.entries(partial)) {
+ if (value === undefined || value === defaultsRef.current[key]) {
+ next.delete(key);
+ } else {
+ next.set(key, String(value));
+ }
+ }
+ replaceUrl(next);
+ }, []);
+
+ const resetParams = useCallback(() => {
+ const next = new URLSearchParams(window.location.search);
+ for (const key of Object.keys(defaultsRef.current)) {
+ next.delete(key);
+ }
+ replaceUrl(next);
+ }, []);
+
+ return { params, setParams, resetParams };
+}
+
+function parseParams>(
+ searchParams: ReturnType,
+ defaults: T,
+): T {
+ const result = { ...defaults };
+
+ for (const key of Object.keys(defaults) as (keyof T)[]) {
+ const raw = searchParams?.get(key as string) ?? null;
+ if (raw === null) continue;
+
+ if (typeof defaults[key] === "number") {
+ const parsed = Number(raw);
+ if (!Number.isNaN(parsed)) result[key] = parsed as T[keyof T];
+ } else {
+ result[key] = raw as T[keyof T];
+ }
+ }
+
+ return result;
+}
+
+function replaceUrl(searchParams: URLSearchParams) {
+ const qs = searchParams.toString();
+ const url = qs
+ ? `${window.location.pathname}?${qs}`
+ : window.location.pathname;
+ window.history.replaceState(null, "", url);
+}
+
+type ParamValue = string | number | null;
+
+interface UseSearchParamsStateReturn {
+ params: T;
+ setParams: (partial: Partial) => void;
+ resetParams: () => void;
+}