From 18c46ce8296ab73c1e39dce6ef3caabcbce0dcf9 Mon Sep 17 00:00:00 2001 From: swcho Date: Wed, 3 Sep 2025 10:57:28 +0900 Subject: [PATCH] =?UTF-8?q?refactor:=20useSearchModal.tsx=20store=20?= =?UTF-8?q?=EC=9D=B4=EC=9A=A9=ED=95=98=EC=97=AC=20=EC=83=81=ED=83=9C?= =?UTF-8?q?=EA=B4=80=EB=A6=AC=20=EB=A6=AC=ED=8C=A9=ED=86=A0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../(map-layout)/map/searchModal/basicTab.tsx | 174 ++-------------- .../map/searchModal/operationTab.tsx | 33 +-- .../map/searchModal/searchModal.tsx | 86 +++----- .../(map-layout)/map/searchModal/stofcbr.tsx | 38 ++-- .../(map-layout)/map/searchModal/swageMhl.tsx | 55 ++--- .../map/searchModal/swagePmstn.tsx | 55 ++--- .../(map-layout)/map/searchModal/swagePpl.tsx | 95 +++++---- .../map/searchModal/swagePrcsFclt.tsx | 57 ++--- .../map/searchModal/swagePrcsZone.tsx | 43 ++-- .../map/searchModal/useSearchModal.tsx | 119 +++-------- apps/sn/app/store/useSearchModalStore.ts | 195 ++++++++++++++++++ 11 files changed, 395 insertions(+), 555 deletions(-) create mode 100644 apps/sn/app/store/useSearchModalStore.ts diff --git a/apps/sn/app/(map-layout)/map/searchModal/basicTab.tsx b/apps/sn/app/(map-layout)/map/searchModal/basicTab.tsx index 70cd18884..5443bb65d 100644 --- a/apps/sn/app/(map-layout)/map/searchModal/basicTab.tsx +++ b/apps/sn/app/(map-layout)/map/searchModal/basicTab.tsx @@ -8,6 +8,9 @@ import SwagePrcsZone from './swagePrcsZone'; import SwageMhl from './swageMhl'; import SwagePmstn from './swagePmstn'; import Stofcbr from './stofcbr'; +import { useSearchModal, type SearchModalProps } from './useSearchModal'; +import useSearchModalStore from '../../../store/useSearchModalStore'; + // 기본정보 '구분' 선택 목록 export const BASIC_TYPES = [ @@ -19,57 +22,9 @@ export const BASIC_TYPES = [ { val: "tb_ms_stofcbr", text: "우수토실" }, ]; -interface BasicTabProps { - basicType: string; - city: string; - sgg: string; - start1: string; - start2: string; - end1: string; - end2: string; - var1: string; - var2: string; - yearFilter: { start: string; end: string; }; - handleSearch: () => void; - setBasicType: (type: string) => void; - setCity: (city: string) => void; - setCtpvName: (name: string) => void; - setSgg: (sgg: string) => void; - setSggName: (name: string) => void; - setYearFilter: (filter: { start: string; end: string }) => void; - setStart1: (value: string) => void; - setStart2: (value: string) => void; - setEnd1: (value: string) => void; - setEnd2: (value: string) => void; - setVar1: (value: string) => void; - setVar2: (value: string) => void; -} +const BasicTab: React.FC = (props) => { + const { basicType, setBasicType } = useSearchModalStore(); -const BasicTab: React.FC = ({ - basicType, - city, - sgg, - start1, - start2, - end1, - end2, - var1, - var2, - yearFilter, - handleSearch, - setBasicType, - setCity, - setCtpvName, - setSgg, - setSggName, - setYearFilter, - setStart1, - setStart2, - setEnd1, - setEnd2, - setVar1, - setVar2, -}) => { return (
{/* 구분 */} @@ -89,118 +44,13 @@ const BasicTab: React.FC = ({ />
- {/* 분기처리: 하수관로 */} - {basicType === "tb_ms_swage_ppl" && ( - - )} - {/* 분기처리: 하수처리시설 */} - {basicType === "tb_il_swage_prcs_fclt" && ( - - )} - {/* 분기처리: 하수처리구역 */} - {basicType === "tb_ms_swage_prcs_zone" && ( - - )} - {/* 분기처리: 하수맨홀 */} - {basicType === "tb_ms_swage_mhl" && ( - - )} - {/* 분기처리: 하수펌프장 */} - {basicType === "tb_ms_swage_pmstn" && ( - - )} - {/* 분기처리: 우수토실 */} - {basicType === "tb_ms_stofcbr" && ( - - )} + {/* 조회 조건 */} + {basicType === "tb_ms_swage_ppl" && ()} {/* 하수관로 */} + {basicType === "tb_il_swage_prcs_fclt" && ()} {/* 하수처리시설 */} + {basicType === "tb_ms_swage_prcs_zone" && ()} {/* 하수처리구역 */} + {basicType === "tb_ms_swage_mhl" && ()} {/* 하수맨홀 */} + {basicType === "tb_ms_swage_pmstn" && ()} {/* 하수펌프장 */} + {basicType === "tb_ms_stofcbr" && ()} {/* 우수토실 */} ); }; diff --git a/apps/sn/app/(map-layout)/map/searchModal/operationTab.tsx b/apps/sn/app/(map-layout)/map/searchModal/operationTab.tsx index 1068bb2e5..6f9e532a1 100644 --- a/apps/sn/app/(map-layout)/map/searchModal/operationTab.tsx +++ b/apps/sn/app/(map-layout)/map/searchModal/operationTab.tsx @@ -3,6 +3,8 @@ import { YearRangeSelectBox } from '@/components/ui/YearRangeSelectBox'; import { SelectBox } from '@common/business_components/ui'; import { Button, Input, Label } from '@common/components'; import useStore from '../../../store/useStore'; +import useSearchModalStore from '../../../store/useSearchModalStore'; +import { useSearchModal, type SearchModalProps } from './useSearchModal'; // 운영정보 '구분' 선택 목록 export const WORK_TYPES = [ @@ -65,30 +67,15 @@ export const operationInspectionTableHeadlist = [ { id: "oper_stts_grd", title: "운영적 상태등급" }, ]; -interface OperationTabProps { - workType: string; - var1: string; - var2: string; - yearFilter: { start: string; end: string; }; - handleSearch: () => void; - setWorkType: (type: string) => void; - setYearFilter: (filter: { start: string; end: string }) => void; - setVar1: (value: string) => void; - setVar2: (value: string) => void; -} - -const OperationTab: React.FC = ({ - workType, - var1, - var2, - yearFilter, - handleSearch, - setWorkType, - setVar1, - setVar2, - setYearFilter, -}) => { +const OperationTab: React.FC = (props) => { + const { + workType, setWorkType, + var1, setVar1, var2, setVar2, + yearFilter, setYearFilter, + } = useSearchModalStore(); + const { handleSearch } = useSearchModal(props); + const { BIZ_TY_CD } = useStore(); const BIZ_TY_CD_SELECT_ARRAY = BIZ_TY_CD.map(item => ({ diff --git a/apps/sn/app/(map-layout)/map/searchModal/searchModal.tsx b/apps/sn/app/(map-layout)/map/searchModal/searchModal.tsx index b9eb29a10..078f3d473 100644 --- a/apps/sn/app/(map-layout)/map/searchModal/searchModal.tsx +++ b/apps/sn/app/(map-layout)/map/searchModal/searchModal.tsx @@ -1,4 +1,4 @@ -import React, { useMemo } from 'react'; +import React, { useEffect, useMemo } from 'react'; import LoadingOverlay from '@/components/ui/LoadingBar'; import { UiModal, UITab, UiTable } from '@common/business_components/ui'; import { Button } from '@common/components/ui'; @@ -14,27 +14,12 @@ import ReportTab from './reportTab'; import { formatDisplayData } from '@/components/lib/utils/formatDisplayValue'; import { Toaster } from "react-hot-toast"; import { useSearchModal, OPERATION_TABLE_SIZE, type SearchModalProps } from './useSearchModal'; +import useSearchModalStore from '../../../store/useSearchModalStore'; const SearchModal: React.FC = (props) => { const { open, onOpenChange, TABS, - activeTab, setActiveTab, - basicType, setBasicType, - workType, setWorkType, - tableData, detailTableData, - tableCount, detailTableCount, - curPage, setCurPage, - detailCurPage, setDetailCurPage, - isLoading, isDetailLoading, - isResetPage, isResetDetailPage, - isResetSelection, isResetDetailSelection, - ctpvCd, setCtpvCd, setCtpvName, - sggCd, setSggCd, setSggName, - start1, setStart1, start2, setStart2, - end1, setEnd1, end2, setEnd2, - var1, setVar1, var2, setVar2, - yearFilter, setYearFilter, handleSearch, handleBasicCellClick, handleOperationCellClick, @@ -44,28 +29,39 @@ const SearchModal: React.FC = (props) => { operationResultExcelDownload, viewMultipleFeature, } = useSearchModal(props); + const { + activeTab, basicType, workType, + tableData, detailTableData, + tableCount, detailTableCount, + curPage, detailCurPage, + isLoading, isDetailLoading, + isResetPage, isResetDetailPage, + isResetSelection, isResetDetailSelection, + setActiveTab, + setCurPage, setDetailCurPage, + } = useSearchModalStore(); const dynamicHeadlist: { id: string, title: string }[] = useMemo(() => { - if (activeTab === 'basic') { - if (basicType === 'tb_ms_swage_ppl') return MsSwagePplCol2; // 하수관로 - if (basicType === 'tb_il_swage_prcs_fclt') return SwtrmtFcltCol2; // 하수처리시설 + if (activeTab === 'basic') { // 기본정보 + if (basicType === 'tb_ms_swage_ppl') return MsSwagePplCol2;// 하수관로 + if (basicType === 'tb_il_swage_prcs_fclt') return SwtrmtFcltCol2;// 하수처리시설 if (basicType === 'tb_ms_swage_prcs_zone') return SwtrmtPrcsZoneCol2; // 하수처리구역 if (basicType === 'tb_ms_swage_mhl') return MsSwageMhlCol2; // 하수맨홀 - if (basicType === 'tb_ms_swage_pmstn') return ExclnSewagePumpCol2; // 하수펌프장 - if (basicType === 'tb_ms_stofcbr') return stofcbrCol2; // 우수토실 + if (basicType === 'tb_ms_swage_pmstn') return ExclnSewagePumpCol2; // 하수펌프장 + if (basicType === 'tb_ms_stofcbr') return stofcbrCol2; // 우수토실 return []; } - if (activeTab === 'operation') return operationTableHeadlist; + if (activeTab === 'operation') return operationTableHeadlist; // 운영정보 return []; }, [activeTab, basicType, workType]); const dynamicHeadlist2: { id: string, title: string }[] = useMemo(() => { if (activeTab === 'operation') { - if (workType === WORK_TYPES[0]?.val) return operationMaintenanceTableHeadlist; - if (workType === WORK_TYPES[1]?.val) return operationInspectionTableHeadlist; - if (workType === WORK_TYPES[2]?.val) return operationCleaningTableHeadlist; + if (workType === WORK_TYPES[0]?.val) return operationMaintenanceTableHeadlist; // 보수 및 갱신 + if (workType === WORK_TYPES[1]?.val) return operationInspectionTableHeadlist; // 점검 및 진단 + if (workType === WORK_TYPES[2]?.val) return operationCleaningTableHeadlist; // 청소 및 준설 } return []; @@ -85,45 +81,11 @@ const SearchModal: React.FC = (props) => { /> {/* 기본정보 탭 */} {activeTab === 'basic' && ( - + )} {/* 운영정보 탭 */} {activeTab === 'operation' && ( - + )} {/* 하수도정비기본계획보고서 탭 */} {activeTab === 'report' && ( diff --git a/apps/sn/app/(map-layout)/map/searchModal/stofcbr.tsx b/apps/sn/app/(map-layout)/map/searchModal/stofcbr.tsx index 2e4fd26f0..455a17a60 100644 --- a/apps/sn/app/(map-layout)/map/searchModal/stofcbr.tsx +++ b/apps/sn/app/(map-layout)/map/searchModal/stofcbr.tsx @@ -4,38 +4,30 @@ import { YearRangeSelectBox } from '@/components/ui/YearRangeSelectBox'; import { Button } from '@common/components'; import React from 'react'; import { CtpvSggPrcsFcltSelectBox } from '@/components/ui/ctpvSggPrcsFcltSelectBox'; +import useSearchModalStore from '../../../store/useSearchModalStore'; +import { useSearchModal, type SearchModalProps } from './useSearchModal'; + +const Stofcbr: React.FC = (props) => { + const { + ctpvCd, setCtpvCd, + sggCd, setSggCd, + yearFilter, setYearFilter, + } = useSearchModalStore(); + const { handleSearch } = useSearchModal(props); -interface StofcbrProps { - city: string; - sgg: string; - yearFilter: { start: string; end: string }; - setCity: (value: string) => void; - setSgg: (value: string) => void; - setYearFilter: (filter: { start: string; end: string }) => void; - handleSearch: () => void; -} -const Stofcbr: React.FC = ({ - city, - sgg, - yearFilter, - setCity, - setSgg, - setYearFilter, - handleSearch, -}) => { return (
{/* 시도, 시군구 */} { - setCity(sidoId); - setSgg("0"); + setCtpvCd(sidoId); + setSggCd("0"); }} - onSigunguChange={setSgg} + onSigunguChange={setSggCd} /> {/* 설치년도 */}
diff --git a/apps/sn/app/(map-layout)/map/searchModal/swageMhl.tsx b/apps/sn/app/(map-layout)/map/searchModal/swageMhl.tsx index 1c578a3e6..f16fae331 100644 --- a/apps/sn/app/(map-layout)/map/searchModal/swageMhl.tsx +++ b/apps/sn/app/(map-layout)/map/searchModal/swageMhl.tsx @@ -1,56 +1,35 @@ // 하수맨홀 +import React from 'react'; import { YearRangeSelectBox } from '@/components/ui/YearRangeSelectBox'; import { Button, Input, Label } from '@common/components'; -import React from 'react'; import { MS_SWAGE_MHL_USE_CODES } from '../components/common/table'; import { SelectBox } from '@common/business_components/ui'; import { CtpvSggPrcsFcltSelectBox } from '@/components/ui/ctpvSggPrcsFcltSelectBox'; +import useSearchModalStore from '../../../store/useSearchModalStore'; +import { useSearchModal, type SearchModalProps } from './useSearchModal'; - -interface SwageMhlProps { - var1: string; - start1: string; - end1: string; - city: string; - sgg: string; - yearFilter: { start: string; end: string }; - setVar1: (value: string) => void; - setStart1: (value: string) => void; - setEnd1: (value: string) => void; - setCity: (value: string) => void; - setSgg: (value: string) => void; - setYearFilter: (filter: { start: string; end: string }) => void; - handleSearch: () => void; -} - -const SwageMhl: React.FC = ({ - var1, - start1, - end1, - city, - sgg, - yearFilter, - setVar1, - setStart1, - setEnd1, - setCity, - setSgg, - setYearFilter, - handleSearch, -}) => { +const SwageMhl: React.FC = (props) => { + const { + var1, setVar1, + start1, setStart1, end1, setEnd1, + ctpvCd, setCtpvCd, + sggCd, setSggCd, + yearFilter, setYearFilter, + } = useSearchModalStore(); + const { handleSearch } = useSearchModal(props); return (
{ - setCity(sidoId); - setSgg("0"); + setCtpvCd(sidoId); + setSggCd("0"); }} - onSigunguChange={setSgg} + onSigunguChange={setSggCd} /> {/* 설치년도 */} void; - setStart2: (value: string) => void; - setEnd1: (value: string) => void; - setEnd2: (value: string) => void; - setCity: (value: string) => void; - setSgg: (value: string) => void; - setYearFilter: (filter: { start: string; end: string }) => void; - handleSearch: () => void; -} -const SwagePmstn: React.FC = ({ - start1, - start2, - end1, - end2, - city, - sgg, - yearFilter, - setStart1, - setStart2, - setEnd1, - setEnd2, - setCity, - setSgg, - setYearFilter, - handleSearch, -}) => { +const SwagePmstn: React.FC = (props) => { + const { + start1, setStart1, + end1, setEnd1, + ctpvCd, setCtpvCd, + sggCd, setSggCd, + yearFilter, setYearFilter, + } = useSearchModalStore(); + const { handleSearch } = useSearchModal(props); return (
{/* 시도, 시군구 */} { - setCity(sidoId); - setSgg("0"); + setCtpvCd(sidoId); + setSggCd("0"); }} - onSigunguChange={setSgg} + onSigunguChange={setSggCd} /> {/* 설치년도 */} void; - setVar2: (value: string) => void; - setStart1: (value: string) => void; - setStart2: (value: string) => void; - setEnd1: (value: string) => void; - setEnd2: (value: string) => void; - setCity: (value: string) => void; - setSgg: (value: string) => void; - setYearFilter: (filter: { start: string; end: string }) => void; - handleSearch: () => void; -} +// 하수관로용 CQL 필터 생성 +export const pplCqlFilters = () => { + const store = useSearchModalStore(); + const { + todayYear, todayMonth, todayDate, + ctpvCd, sggCd, + start1, start2, end1, end2, + var1, var2, + yearFilter, getDateString + } = store; -const SwagePpl: React.FC = ({ - var1, - var2, - start1, - start2, - end1, - end2, - city, - sgg, - yearFilter, - setVar1, - setVar2, - setStart1, - setStart2, - setEnd1, - setEnd2, - setCity, - setSgg, - setYearFilter, - handleSearch, -}) => { + const cqlFilters: string[] = []; + if (var1) cqlFilters.push(`usg_cd='${var1}'`); + if (var2) cqlFilters.push(`mqlt_cd='${var2}'`); + if (ctpvCd !== '0' && sggCd !== '0') cqlFilters.push(`pbadms_emd_cd LIKE '${sggCd}%'`); + else if (ctpvCd !== '0') cqlFilters.push(`pbadms_emd_cd LIKE '${ctpvCd?.trim()}%'`); + // 설치년도 범위 + const startDate = getDateString(yearFilter.start, '', '', "19000101"); + const endDate = getDateString(yearFilter.end, '', '', `${todayYear}${todayMonth}${todayDate}`); + cqlFilters.push(`instl_ymd >= '${startDate}' and instl_ymd <= '${endDate}'`); + // 관경(mm) 범위 + if (start1 && end1) cqlFilters.push(`pdmt_vl BETWEEN ${start1} AND ${end1}`); + else if (start1) cqlFilters.push(`pdmt_vl >= ${start1}`); + else if (end1) cqlFilters.push(`pdmt_vl <= ${end1}`); + // 연장(m) 범위 + if (start2 && end2) cqlFilters.push(`prlg_vl BETWEEN ${start2} AND ${end2}`); + else if (start2) cqlFilters.push(`prlg_vl >= ${start2}`); + else if (end2) cqlFilters.push(`prlg_vl <= ${end2}`); + + return cqlFilters; +}; + +const SwagePpl: React.FC = (props) => { + const { + var1, setVar1, + start1, setStart1, end1, setEnd1, + ctpvCd, setCtpvCd, sggCd, setSggCd, + yearFilter, setYearFilter, + } = useSearchModalStore(); + const { handleSearch } = useSearchModal(props); return (
{ - setCity(sidoId); - setSgg("0"); + setCtpvCd(sidoId); + setSggCd("0"); }} - onSigunguChange={setSgg} + onSigunguChange={setSggCd} /> {/* 설치년도 */} = ({ className="w-32 mr-8" selectClass="rounded-lg bg-white text-xl" label="" - selectArray={[{val: "0", text: "전체"}, ...MS_SWAGE_PPL_USE_CODES]} + selectArray={[{ val: "0", text: "전체" }, ...MS_SWAGE_PPL_USE_CODES]} value={var1} onSelectValue={(val) => { setVar1(String(val)); diff --git a/apps/sn/app/(map-layout)/map/searchModal/swagePrcsFclt.tsx b/apps/sn/app/(map-layout)/map/searchModal/swagePrcsFclt.tsx index a3db595a5..934499a6c 100644 --- a/apps/sn/app/(map-layout)/map/searchModal/swagePrcsFclt.tsx +++ b/apps/sn/app/(map-layout)/map/searchModal/swagePrcsFclt.tsx @@ -4,57 +4,30 @@ import React from 'react'; import { YearRangeSelectBox } from '@/components/ui/YearRangeSelectBox'; import { Button, Input, Label } from '@common/components'; import { CtpvSggPrcsFcltSelectBox } from '@/components/ui/ctpvSggPrcsFcltSelectBox'; +import useSearchModalStore from '../../../store/useSearchModalStore'; +import { useSearchModal, type SearchModalProps } from './useSearchModal'; -interface SwagePrcsFcltProps { - var1: string; - start1: string; - start2: string; - end1: string; - end2: string; - city: string; - sgg: string; - yearFilter: { start: string; end: string }; - setVar1: (value: string) => void; - setStart1: (value: string) => void; - setStart2: (value: string) => void; - setEnd1: (value: string) => void; - setEnd2: (value: string) => void; - setCity: (value: string) => void; - setCtpvName: (name: string) => void; - setSgg: (value: string) => void; - setSggName: (name: string) => void; - setYearFilter: (filter: { start: string; end: string }) => void; - handleSearch: () => void; -} - -const SwagePrcsFclt: React.FC = ({ - start1, - end1, - city, - sgg, - yearFilter, - setStart1, - setEnd1, - setCity, - setCtpvName, - setSgg, - setSggName, - setYearFilter, - handleSearch, -}) => { +const SwagePrcsFclt: React.FC = (props) => { + const { + start1, setStart1, end1, setEnd1, + ctpvCd, setCtpvCd, setCtpvName, + sggCd, setSggCd, setSggName, + yearFilter, setYearFilter, + } = useSearchModalStore(); + const { handleSearch } = useSearchModal(props); return (
{ - setCity(sidoId); - setSgg("0"); + setCtpvCd(sidoId); + setSggCd("0"); }} - onSigunguChange={setSgg} + onSigunguChange={setSggCd} setCtpvName={setCtpvName} setSggName={setSggName} /> diff --git a/apps/sn/app/(map-layout)/map/searchModal/swagePrcsZone.tsx b/apps/sn/app/(map-layout)/map/searchModal/swagePrcsZone.tsx index 9f8e8a181..c7d3df3ce 100644 --- a/apps/sn/app/(map-layout)/map/searchModal/swagePrcsZone.tsx +++ b/apps/sn/app/(map-layout)/map/searchModal/swagePrcsZone.tsx @@ -1,44 +1,31 @@ // 하수처리구역 +import React from 'react'; import { CtpvSggPrcsFcltSelectBox } from '@/components/ui/ctpvSggPrcsFcltSelectBox'; import { Button, Input, Label } from '@common/components'; -import React from 'react'; +import useSearchModalStore from '../../../store/useSearchModalStore'; +import { useSearchModal, type SearchModalProps } from './useSearchModal'; -interface swagePrcsZoneProps { - var1: string; - var2: string; - city: string; - sgg: string; - setVar1: (value: string) => void; - setVar2: (value: string) => void; - setCity: (value: string) => void; - setSgg: (value: string) => void; - handleSearch: () => void; -} -const swagePrcsZone: React.FC = ({ - var1, - var2, - city, - sgg, - setVar1, - setVar2, - setCity, - setSgg, - handleSearch, -}) => { +const swagePrcsZone: React.FC = (props) => { + const { + var1, setVar1, var2, setVar2, + ctpvCd, setCtpvCd, + sggCd, setSggCd, + } = useSearchModalStore(); + const { handleSearch } = useSearchModal(props); return (
{ - setCity(sidoId); - setSgg("0"); + setCtpvCd(sidoId); + setSggCd("0"); }} - onSigunguChange={setSgg} + onSigunguChange={setSggCd} /> { - if (!year && !month && !day) return defaultDate; - const y = year || defaultDate.slice(0, 4); - const m = month || defaultDate.slice(4, 6); - const d = day || defaultDate.slice(6, 8); - return `${y}${m}${d}`; -}; - export interface SearchModalProps { open: boolean; onOpenChange: (open: boolean) => void; @@ -38,72 +25,39 @@ export interface SearchModalProps { } export function useSearchModal({ open, onOpenChange, onFeatureSelect }: SearchModalProps) { + const { + activeTab, basicType, workType, + showTable, + tableData, detailTableData, + curPage, detailCurPage, + detailBizId, + ctpvCd, ctpvName, sggCd, sggName, + start1, start2, end1, end2, + var1, var2, + yearFilter, + todayYear, todayMonth, todayDate, + setShowTable, + setTableData, setDetailTableData, + setTableCount, setDetailTableCount, + setCurPage, setDetailCurPage, + setIsLoading, setIsDetailLoading, + setIsResetPage, setIsResetDetailPage, + setIsResetSelection, setIsResetDetailSelection, + setDetailBizId, + resetFilters, + getDateString + } = useSearchModalStore(); + const { ctpv, sgg, BIZ_TY_CD } = useStore(); + const TABS = [ { val: "basic", text: "기본정보" }, { val: "operation", text: "운영정보" }, { val: "report", text: "하수도정비기본계획보고서" }, ]; - const [activeTab, setActiveTab] = useState(TABS[0]?.val ?? "basic"); - const [basicType, setBasicType] = useState(BASIC_TYPES[0]?.val ?? ""); - const [workType, setWorkType] = useState(WORK_TYPES[0]?.val ?? ""); - const [showTable, setShowTable] = useState(false); - const [isLoading, setIsLoading] = useState(false); - const [isDetailLoading, setIsDetailLoading] = useState(false); - const [tableData, setTableData] = useState([]); - const [detailTableData, setDetailTableData] = useState([]); - const [tableCount, setTableCount] = useState(0); - const [detailTableCount, setDetailTableCount] = useState(0); - const [curPage, setCurPage] = useState(1); - const [detailCurPage, setDetailCurPage] = useState(1); - const [isResetPage, setIsResetPage] = useState(false); - const [isResetDetailPage, setIsResetDetailPage] = useState(false); - const [isResetSelection, setIsResetSelection] = useState(false); - const [isResetDetailSelection, setIsResetDetailSelection] = useState(false); - const [detailBizId, setDetailBizId] = useState(0); - const [ctpvCd, setCtpvCd] = useState("0"); - const [ctpvName, setCtpvName] = useState(''); - const [sggCd, setSggCd] = useState("0"); - const [sggName, setSggName] = useState(''); - const [start1, setStart1] = useState(""); - const [start2, setStart2] = useState(""); - const [end1, setEnd1] = useState(""); - const [end2, setEnd2] = useState(""); - const [var1, setVar1] = useState(""); - const [var2, setVar2] = useState(""); - const [yearFilter, setYearFilter] = useState({ start: "", end: "" }); - - const { ctpv, sgg, BIZ_TY_CD } = useStore(); - - // 오늘 날짜 구하기 - const today = new Date(); - const todayYear = today.getFullYear().toString(); - const todayMonth = (today.getMonth() + 1).toString().padStart(2, "0"); - const todayDate = today.getDate().toString().padStart(2, "0"); useEffect(() => { - // filterParams 초기화 - setStart1(""); - setStart2(""); - setEnd1(""); - setEnd2(""); - setVar1(""); - setVar2(""); - setCtpvCd("0"); - setSggCd("0"); - setYearFilter({ start: "", end: "" }); - setShowTable(false); - setTableData([]); - setDetailTableData([]); - setTableCount(0); - setDetailTableCount(0); - setCurPage(1); - setDetailCurPage(1); - setIsResetPage(true); - setIsResetDetailPage(true); - setIsResetSelection(true); - setIsResetDetailSelection(true); - setDetailBizId(0); + resetFilters(); }, [activeTab, basicType, workType]); // 페이지 변경 시마다 데이터 fetch @@ -939,6 +893,7 @@ export function useSearchModal({ open, onOpenChange, onFeatureSelect }: SearchMo } }; + // 여러 시설 보기 const viewMultipleFeature = async () => { if (activeTab === 'basic') { if (!(tableData.length === 0)) { @@ -970,23 +925,7 @@ export function useSearchModal({ open, onOpenChange, onFeatureSelect }: SearchMo return { open, onOpenChange, onFeatureSelect, TABS, - activeTab, setActiveTab, - basicType, setBasicType, - workType, setWorkType, - tableData, detailTableData, - tableCount, detailTableCount, - curPage, setCurPage, - detailCurPage, setDetailCurPage, - isLoading, isDetailLoading, - isResetPage, isResetDetailPage, - isResetSelection, isResetDetailSelection, - detailBizId, setDetailBizId, - ctpvCd, setCtpvCd, ctpvName, setCtpvName, - sggCd, setSggCd, sggName, setSggName, - start1, setStart1, start2, setStart2, - end1, setEnd1, end2, setEnd2, - var1, setVar1, var2, setVar2, - yearFilter, setYearFilter, + getDateString, handleSearch, handleBasicCellClick, handleOperationCellClick, diff --git a/apps/sn/app/store/useSearchModalStore.ts b/apps/sn/app/store/useSearchModalStore.ts new file mode 100644 index 000000000..8ad1c356c --- /dev/null +++ b/apps/sn/app/store/useSearchModalStore.ts @@ -0,0 +1,195 @@ +import { create } from "zustand"; +import { type SelectDataType } from "@common/business_components"; + + +// 날짜 조합 함수 +const getDateString = ( + year: string, + month: string, + day: string, + defaultDate: string, +) => { + if (!year && !month && !day) return defaultDate; + const y = year || defaultDate.slice(0, 4); + const m = month || defaultDate.slice(4, 6); + const d = day || defaultDate.slice(6, 8); + return `${y}${m}${d}`; +}; + +// 오늘 날짜 계산 +const today = new Date(); +const todayYear = today.getFullYear().toString(); +const todayMonth = (today.getMonth() + 1).toString().padStart(2, "0"); +const todayDate = today.getDate().toString().padStart(2, "0"); + +export interface SearchModalState { + // 탭 관련 + activeTab: string; + basicType: string; + workType: string; + // 최초 렌더 방지 플래그 + showTable: boolean; + // 테이블 데이터 + tableData: any[]; + detailTableData: any[]; + tableCount: number; + detailTableCount: number; + // 페이지네이션 + curPage: number; + detailCurPage: number; + // 로딩 상태 + isLoading: boolean; + isDetailLoading: boolean; + // 리셋 플래그 + isResetPage: boolean; + isResetDetailPage: boolean; + isResetSelection: boolean; + isResetDetailSelection: boolean; + // 사업 ID + detailBizId: number; + // 지역 필터 + ctpvCd: string; + ctpvName: string; + sggCd: string; + sggName: string; + // 범위 필터 + start1: string; + start2: string; + end1: string; + end2: string; + // 변수 필터 + var1: string; + var2: string; + // 연도 필터 + yearFilter: { start: string; end: string }; + // 날짜 관련 + today: Date; + todayYear: string; + todayMonth: string; + todayDate: string; + getDateString: (year: string, month: string, day: string, defaultDate: string) => string; + + // setters + setActiveTab: (tab: string) => void; + setBasicType: (type: string) => void; + setWorkType: (type: string) => void; + setShowTable: (show: boolean) => void; + setTableData: (data: any[]) => void; + setDetailTableData: (data: any[]) => void; + setTableCount: (count: number) => void; + setDetailTableCount: (count: number) => void; + setCurPage: (page: number) => void; + setDetailCurPage: (page: number) => void; + setIsLoading: (loading: boolean) => void; + setIsDetailLoading: (loading: boolean) => void; + setIsResetPage: (reset: boolean) => void; + setIsResetDetailPage: (reset: boolean) => void; + setIsResetSelection: (reset: boolean) => void; + setIsResetDetailSelection: (reset: boolean) => void; + setDetailBizId: (id: number) => void; + setCtpvCd: (cd: string) => void; + setCtpvName: (name: string) => void; + setSggCd: (cd: string) => void; + setSggName: (name: string) => void; + setStart1: (val: string) => void; + setStart2: (val: string) => void; + setEnd1: (val: string) => void; + setEnd2: (val: string) => void; + setVar1: (val: string) => void; + setVar2: (val: string) => void; + setYearFilter: (filter: { start: string; end: string }) => void; + // 초기화 액션 + resetFilters: () => void; +} + +const useSearchModalStore = create((set) => ({ + activeTab: "basic", + basicType: "tb_ms_swage_ppl", + workType: "['200', '201', '204']", + showTable: false, + tableData: [], + detailTableData: [], + tableCount: 0, + detailTableCount: 0, + curPage: 1, + detailCurPage: 1, + isLoading: false, + isDetailLoading: false, + isResetPage: false, + isResetDetailPage: false, + isResetSelection: false, + isResetDetailSelection: false, + detailBizId: 0, + ctpvCd: "0", + ctpvName: "", + sggCd: "0", + sggName: "", + start1: "", + start2: "", + end1: "", + end2: "", + var1: "", + var2: "", + yearFilter: { start: "", end: "" }, + today, + todayYear, + todayMonth, + todayDate, + getDateString, + setActiveTab: (tab) => set({ activeTab: tab }), + setBasicType: (type) => set({ basicType: type }), + setWorkType: (type) => set({ workType: type }), + setShowTable: (show) => set({ showTable: show }), + setTableData: (data) => set({ tableData: data }), + setDetailTableData: (data) => set({ detailTableData: data }), + setTableCount: (count) => set({ tableCount: count }), + setDetailTableCount: (count) => set({ detailTableCount: count }), + setCurPage: (page) => set({ curPage: page }), + setDetailCurPage: (page) => set({ detailCurPage: page }), + setIsLoading: (loading) => set({ isLoading: loading }), + setIsDetailLoading: (loading) => set({ isDetailLoading: loading }), + setIsResetPage: (reset) => set({ isResetPage: reset }), + setIsResetDetailPage: (reset) => set({ isResetDetailPage: reset }), + setIsResetSelection: (reset) => set({ isResetSelection: reset }), + setIsResetDetailSelection: (reset) => set({ isResetDetailSelection: reset }), + setDetailBizId: (id) => set({ detailBizId: id }), + setCtpvCd: (cd) => set({ ctpvCd: cd }), + setCtpvName: (name) => set({ ctpvName: name }), + setSggCd: (cd) => set({ sggCd: cd }), + setSggName: (name) => set({ sggName: name }), + setStart1: (val) => set({ start1: val }), + setStart2: (val) => set({ start2: val }), + setEnd1: (val) => set({ end1: val }), + setEnd2: (val) => set({ end2: val }), + setVar1: (val) => set({ var1: val }), + setVar2: (val) => set({ var2: val }), + setYearFilter: (filter) => set({ yearFilter: filter }), + + // 초기화 액션 + resetFilters: () => + set({ + showTable: false, + start1: "", + start2: "", + end1: "", + end2: "", + var1: "", + var2: "", + ctpvCd: "0", + sggCd: "0", + yearFilter: { start: "", end: "" }, + tableData: [], + detailTableData: [], + tableCount: 0, + detailTableCount: 0, + curPage: 1, + detailCurPage: 1, + isResetPage: true, + isResetDetailPage: true, + isResetSelection: true, + isResetDetailSelection: true, + detailBizId: 0, + }), +})); + +export default useSearchModalStore; \ No newline at end of file