refactor: useSearchModal.tsx store 이용하여 상태관리 리팩토링

This commit is contained in:
swcho
2025-09-03 10:57:28 +09:00
parent 0506464a97
commit 18c46ce829
11 changed files with 395 additions and 555 deletions
@@ -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<SearchModalProps> = (props) => {
const { basicType, setBasicType } = useSearchModalStore();
const BasicTab: React.FC<BasicTabProps> = ({
basicType,
city,
sgg,
start1,
start2,
end1,
end2,
var1,
var2,
yearFilter,
handleSearch,
setBasicType,
setCity,
setCtpvName,
setSgg,
setSggName,
setYearFilter,
setStart1,
setStart2,
setEnd1,
setEnd2,
setVar1,
setVar2,
}) => {
return (
<div className="relative border rounded-lg p-5 w-full h-[10vh]">
{/* 구분 */}
@@ -89,118 +44,13 @@ const BasicTab: React.FC<BasicTabProps> = ({
/>
</div>
</div>
{/* 분기처리: 하수관로 */}
{basicType === "tb_ms_swage_ppl" && (
<SwagePpl
var1={var1}
var2={var2}
start1={start1}
start2={start2}
end1={end1}
end2={end2}
city={city}
sgg={sgg}
yearFilter={yearFilter}
setVar1={setVar1}
setVar2={setVar2}
setStart1={setStart1}
setStart2={setStart2}
setEnd1={setEnd1}
setEnd2={setEnd2}
setCity={setCity}
setSgg={setSgg}
setYearFilter={setYearFilter}
handleSearch={handleSearch}
/>
)}
{/* 분기처리: 하수처리시설 */}
{basicType === "tb_il_swage_prcs_fclt" && (
<SwagePrcsFclt
var1={var1}
start1={start1}
start2={start2}
end1={end1}
end2={end2}
city={city}
sgg={sgg}
yearFilter={yearFilter}
setVar1={setVar1}
setStart1={setStart1}
setStart2={setStart2}
setEnd1={setEnd1}
setEnd2={setEnd2}
setCity={setCity}
setCtpvName={setCtpvName}
setSgg={setSgg}
setSggName={setSggName}
setYearFilter={setYearFilter}
handleSearch={handleSearch}
/>
)}
{/* 분기처리: 하수처리구역 */}
{basicType === "tb_ms_swage_prcs_zone" && (
<SwagePrcsZone
var1={var1}
var2={var2}
city={city}
sgg={sgg}
setVar1={setVar1}
setVar2={setVar2}
setCity={setCity}
setSgg={setSgg}
handleSearch={handleSearch}
/>
)}
{/* 분기처리: 하수맨홀 */}
{basicType === "tb_ms_swage_mhl" && (
<SwageMhl
var1={var1}
start1={start1}
end1={end1}
city={city}
sgg={sgg}
yearFilter={yearFilter}
setVar1={setVar1}
setStart1={setStart1}
setEnd1={setEnd1}
setCity={setCity}
setSgg={setSgg}
setYearFilter={setYearFilter}
handleSearch={handleSearch}
/>
)}
{/* 분기처리: 하수펌프장 */}
{basicType === "tb_ms_swage_pmstn" && (
<SwagePmstn
start1={start1}
start2={start2}
end1={end1}
end2={end2}
city={city}
sgg={sgg}
yearFilter={yearFilter}
setStart1={setStart1}
setStart2={setStart2}
setEnd1={setEnd1}
setEnd2={setEnd2}
setCity={setCity}
setSgg={setSgg}
setYearFilter={setYearFilter}
handleSearch={handleSearch}
/>
)}
{/* 분기처리: 우수토실 */}
{basicType === "tb_ms_stofcbr" && (
<Stofcbr
city={city}
sgg={sgg}
yearFilter={yearFilter}
setCity={setCity}
setSgg={setSgg}
setYearFilter={setYearFilter}
handleSearch={handleSearch}
/>
)}
{/* 조회 조건 */}
{basicType === "tb_ms_swage_ppl" && (<SwagePpl {...props} />)} {/* 하수관로 */}
{basicType === "tb_il_swage_prcs_fclt" && (<SwagePrcsFclt {...props} />)} {/* 하수처리시설 */}
{basicType === "tb_ms_swage_prcs_zone" && (<SwagePrcsZone {...props} />)} {/* 하수처리구역 */}
{basicType === "tb_ms_swage_mhl" && (<SwageMhl {...props} />)} {/* 하수맨홀 */}
{basicType === "tb_ms_swage_pmstn" && (<SwagePmstn {...props} />)} {/* 하수펌프장 */}
{basicType === "tb_ms_stofcbr" && (<Stofcbr {...props} />)} {/* 우수토실 */}
</div>
);
};
@@ -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<OperationTabProps> = ({
workType,
var1,
var2,
yearFilter,
handleSearch,
setWorkType,
setVar1,
setVar2,
setYearFilter,
}) => {
const OperationTab: React.FC<SearchModalProps> = (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 => ({
@@ -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<SearchModalProps> = (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<SearchModalProps> = (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<SearchModalProps> = (props) => {
/>
{/* 기본정보 탭 */}
{activeTab === 'basic' && (
<BasicTab
basicType={basicType}
city={ctpvCd}
sgg={sggCd}
start1={start1}
start2={start2}
end1={end1}
end2={end2}
var1={var1}
var2={var2}
yearFilter={yearFilter}
handleSearch={handleSearch}
setBasicType={setBasicType}
setCity={setCtpvCd}
setCtpvName={setCtpvName}
setSgg={setSggCd}
setSggName={setSggName}
setYearFilter={setYearFilter}
setStart1={setStart1}
setStart2={setStart2}
setEnd1={setEnd1}
setEnd2={setEnd2}
setVar1={setVar1}
setVar2={setVar2}
/>
<BasicTab {...props} />
)}
{/* 운영정보 탭 */}
{activeTab === 'operation' && (
<OperationTab
workType={workType}
var1={var1}
var2={var2}
yearFilter={yearFilter}
handleSearch={handleSearch}
setWorkType={setWorkType}
setVar1={setVar1}
setVar2={setVar2}
setYearFilter={setYearFilter}
/>
<OperationTab {...props} />
)}
{/* 하수도정비기본계획보고서 탭 */}
{activeTab === 'report' && (
@@ -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<SearchModalProps> = (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<StofcbrProps> = ({
city,
sgg,
yearFilter,
setCity,
setSgg,
setYearFilter,
handleSearch,
}) => {
return (
<div className="mb-3">
<div className="flex items-center mb-2">
{/* 시도, 시군구 */}
<CtpvSggPrcsFcltSelectBox
sido={city}
sigungu={sgg}
sido={ctpvCd}
sigungu={sggCd}
onSidoChange={(sidoId: string) => {
setCity(sidoId);
setSgg("0");
setCtpvCd(sidoId);
setSggCd("0");
}}
onSigunguChange={setSgg}
onSigunguChange={setSggCd}
/>
{/* 설치년도 */}
<div className="flex items-center mb-2">
@@ -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<SwageMhlProps> = ({
var1,
start1,
end1,
city,
sgg,
yearFilter,
setVar1,
setStart1,
setEnd1,
setCity,
setSgg,
setYearFilter,
handleSearch,
}) => {
const SwageMhl: React.FC<SearchModalProps> = (props) => {
const {
var1, setVar1,
start1, setStart1, end1, setEnd1,
ctpvCd, setCtpvCd,
sggCd, setSggCd,
yearFilter, setYearFilter,
} = useSearchModalStore();
const { handleSearch } = useSearchModal(props);
return (
<div className="mb-3">
<div className="mb-2 flex items-center">
<CtpvSggPrcsFcltSelectBox
sido={city}
sigungu={sgg}
sido={ctpvCd}
sigungu={sggCd}
onSidoChange={(sidoId: string) => {
setCity(sidoId);
setSgg("0");
setCtpvCd(sidoId);
setSggCd("0");
}}
onSigunguChange={setSgg}
onSigunguChange={setSggCd}
/>
{/* 설치년도 */}
<YearRangeSelectBox
@@ -4,55 +4,32 @@ import { YearRangeSelectBox } from '@/components/ui/YearRangeSelectBox';
import { Button, Input, Label } from '@common/components';
import React from 'react';
import { CtpvSggPrcsFcltSelectBox } from '@/components/ui/ctpvSggPrcsFcltSelectBox';
import useSearchModalStore from '../../../store/useSearchModalStore';
import { useSearchModal, type SearchModalProps } from './useSearchModal';
interface SwagePmstnProps {
start1: string;
start2: string;
end1: string;
end2: string;
city: string;
sgg: string;
yearFilter: { start: string; end: string };
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;
}
const SwagePmstn: React.FC<SwagePmstnProps> = ({
start1,
start2,
end1,
end2,
city,
sgg,
yearFilter,
setStart1,
setStart2,
setEnd1,
setEnd2,
setCity,
setSgg,
setYearFilter,
handleSearch,
}) => {
const SwagePmstn: React.FC<SearchModalProps> = (props) => {
const {
start1, setStart1,
end1, setEnd1,
ctpvCd, setCtpvCd,
sggCd, setSggCd,
yearFilter, setYearFilter,
} = useSearchModalStore();
const { handleSearch } = useSearchModal(props);
return (
<div className="mb-3">
<div className="flex items-center mb-2">
{/* 시도, 시군구 */}
<CtpvSggPrcsFcltSelectBox
sido={city}
sigungu={sgg}
sido={ctpvCd}
sigungu={sggCd}
onSidoChange={(sidoId: string) => {
setCity(sidoId);
setSgg("0");
setCtpvCd(sidoId);
setSggCd("0");
}}
onSigunguChange={setSgg}
onSigunguChange={setSggCd}
/>
{/* 설치년도 */}
<YearRangeSelectBox
@@ -6,62 +6,61 @@ import { Button, Input, Label } from '@common/components';
import React from 'react';
import { MS_SWAGE_PPL_CODES, MS_SWAGE_PPL_USE_CODES } from '../components/common/table';
import { CtpvSggPrcsFcltSelectBox } from '@/components/ui/ctpvSggPrcsFcltSelectBox';
import useSearchModalStore from '../../../store/useSearchModalStore';
import { useSearchModal, type SearchModalProps } from './useSearchModal';
interface SwagePplProps {
var1: string;
var2: string;
start1: string;
start2: string;
end1: string;
end2: string;
city: string;
sgg: string;
yearFilter: { start: string; end: string };
setVar1: (value: string) => 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<SwagePplProps> = ({
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<SearchModalProps> = (props) => {
const {
var1, setVar1,
start1, setStart1, end1, setEnd1,
ctpvCd, setCtpvCd, sggCd, setSggCd,
yearFilter, setYearFilter,
} = useSearchModalStore();
const { handleSearch } = useSearchModal(props);
return (
<div className="mb-6">
<div className="mb-2 flex items-center">
<CtpvSggPrcsFcltSelectBox
sido={city}
sigungu={sgg}
sido={ctpvCd}
sigungu={sggCd}
onSidoChange={(sidoId: string) => {
setCity(sidoId);
setSgg("0");
setCtpvCd(sidoId);
setSggCd("0");
}}
onSigunguChange={setSgg}
onSigunguChange={setSggCd}
/>
{/* 설치년도 */}
<YearRangeSelectBox
@@ -83,7 +82,7 @@ const SwagePpl: React.FC<SwagePplProps> = ({
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));
@@ -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<SwagePrcsFcltProps> = ({
start1,
end1,
city,
sgg,
yearFilter,
setStart1,
setEnd1,
setCity,
setCtpvName,
setSgg,
setSggName,
setYearFilter,
handleSearch,
}) => {
const SwagePrcsFclt: React.FC<SearchModalProps> = (props) => {
const {
start1, setStart1, end1, setEnd1,
ctpvCd, setCtpvCd, setCtpvName,
sggCd, setSggCd, setSggName,
yearFilter, setYearFilter,
} = useSearchModalStore();
const { handleSearch } = useSearchModal(props);
return (
<div className="mb-3">
<div className="mb-2 flex items-center">
<CtpvSggPrcsFcltSelectBox
sido={city}
sigungu={sgg}
sido={ctpvCd}
sigungu={sggCd}
onSidoChange={(sidoId) => {
setCity(sidoId);
setSgg("0");
setCtpvCd(sidoId);
setSggCd("0");
}}
onSigunguChange={setSgg}
onSigunguChange={setSggCd}
setCtpvName={setCtpvName}
setSggName={setSggName}
/>
@@ -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<swagePrcsZoneProps> = ({
var1,
var2,
city,
sgg,
setVar1,
setVar2,
setCity,
setSgg,
handleSearch,
}) => {
const swagePrcsZone: React.FC<SearchModalProps> = (props) => {
const {
var1, setVar1, var2, setVar2,
ctpvCd, setCtpvCd,
sggCd, setSggCd,
} = useSearchModalStore();
const { handleSearch } = useSearchModal(props);
return (
<div className="mb-3">
<div className="mb-2 flex items-center">
<CtpvSggPrcsFcltSelectBox
sido={city}
sigungu={sgg}
sido={ctpvCd}
sigungu={sggCd}
onSidoChange={(sidoId: string) => {
setCity(sidoId);
setSgg("0");
setCtpvCd(sidoId);
setSggCd("0");
}}
onSigunguChange={setSgg}
onSigunguChange={setSggCd}
/>
<Label className="text-xl text-gray-600 font-medium whitespace-nowrap mr-2">하수처리시설명</Label>
<Input
@@ -7,30 +7,17 @@ import {
} from '../components/common/table';
import { getData } from "@/components/lib/api";
import { BASIC_TYPES } from './basicTab';
import { WORK_TYPES } from './operationTab';
import { WORK_TYPES } from './operationTab';
import { formatDisplayData } from '@/components/lib/utils/formatDisplayValue';
import useStore from '../../../store/useStore';
import GisApp from "@common/business_components/ui/map/lib/gis.core";
import { confirmToast } from '@/components/ui/toast'
import { toast } from "react-hot-toast";
import useSearchModalStore from '../../../store/useSearchModalStore';
const API_URL = `${process.env.NEXT_PUBLIC_SEWERAGE_API_URL}`;
export const OPERATION_TABLE_SIZE = 5;
// 날짜 조합 함수
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}`;
};
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<boolean>(false);
const [isLoading, setIsLoading] = useState<boolean>(false);
const [isDetailLoading, setIsDetailLoading] = useState<boolean>(false);
const [tableData, setTableData] = useState<any[]>([]);
const [detailTableData, setDetailTableData] = useState<any[]>([]);
const [tableCount, setTableCount] = useState<number>(0);
const [detailTableCount, setDetailTableCount] = useState<number>(0);
const [curPage, setCurPage] = useState<number>(1);
const [detailCurPage, setDetailCurPage] = useState<number>(1);
const [isResetPage, setIsResetPage] = useState<boolean>(false);
const [isResetDetailPage, setIsResetDetailPage] = useState<boolean>(false);
const [isResetSelection, setIsResetSelection] = useState<boolean>(false);
const [isResetDetailSelection, setIsResetDetailSelection] = useState<boolean>(false);
const [detailBizId, setDetailBizId] = useState(0);
const [ctpvCd, setCtpvCd] = useState<string>("0");
const [ctpvName, setCtpvName] = useState<string>('');
const [sggCd, setSggCd] = useState<string>("0");
const [sggName, setSggName] = useState<string>('');
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,
+195
View File
@@ -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<SearchModalState>((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;