/** * 📄 useSearchModal Hook * 검색 모달 훅 * * - 탭 기반 검색 인터페이스 관리 (기본정보, 유지관리 정보, 보고서) * - 필터링된 데이터 조회 및 포맷팅 * - 조회 버튼을 통한 데이터 검색 트리거 * - 여러 시설 보기 기능 * - Zustand를 통한 상태 관리 및 로딩 처리 * - 데이터 매핑 및 코드 변환 (사업 유형 등) * * 🔗 사용 API * - 유지관리 정보 목록 조회: GET /api/v1/bizInfo (sewerage-service) */ import { getData } from "@/components/lib/api"; import { formatDisplayData } from "@/components/lib/utils/formatDisplayValue"; import useStore from "../../../store/useStore"; import GisApp from "@common/business_components/ui/map/lib/gis.core"; import useSearchModalStore, { SEARCH_MODAL_DEFAULT_BASIC_TYPE, SEARCH_MODAL_DEFAULT_WORK_TYPE, } from "../../../store/useSearchModalStore"; import useBasicTab from "./useBasicTab"; import useOperationTab from "./useOperationTab"; import { postPopupMessageAndClose } from "@/features/windowPopup/lib/popupMessage"; import { WINDOW_POPUP_MESSAGE_TYPE } from "@/features/windowPopup/model/types"; const isPopupWindow = () => typeof window !== "undefined" && !!window.opener && window.location.pathname.startsWith("/popup/"); export default function useSearchModal() { const { activeTab, tableData, detailTableData, setIsSearchModalOpen, setShowTable, setTableData, setCurPage, setIsLoading, setIsResetPage, setIsResetDetailPage, setIsResetSelection, setIsResetDetailSelection, getDateString, } = useSearchModalStore(); const { fetchBasicFilteredData } = useBasicTab(); const { OPERATION_TABLE_SIZE } = useOperationTab(); const { BIZ_TY_CD } = useStore(); const TABS = [ { val: "basic", text: "기본 정보" }, { val: "operation", text: "유지관리 정보" }, { val: "report", text: "하수도 정비 기본계획 보고서" }, ]; // 검색 API 호출 함수 const fetchFilteredData = async () => { const { activeTab: currentTab, curPage, var1, var2, yearFilter, workType, todayYear, todayMonth, todayDate, setTableData, setDetailTableData, setTableCount, setDetailTableCount, setShowTable, setIsLoading, setIsResetSelection, setIsResetDetailSelection, } = useSearchModalStore.getState(); setIsLoading(true); setIsResetSelection(true); setIsResetDetailSelection(true); try { if (currentTab === "basic") { await fetchBasicFilteredData(); } else if (currentTab === "operation") { const requestDto: Record = { page: `${curPage - 1}`, size: `${OPERATION_TABLE_SIZE}`, }; if (var1) requestDto.bizInfoNm = var1; if (var2 !== "0" && var2) requestDto.bizTypeCd = var2; const startDate = getDateString(yearFilter.start, "", "", "19000101"); const endDate = getDateString( yearFilter.end, "", "", `${todayYear}${todayMonth}${todayDate}`, ); requestDto.fromflfmtEndYmd = startDate; requestDto.toflfmtEndYmd = endDate; requestDto.workTypes = JSON.parse(workType.replace(/'/g, '"')); const params = new URLSearchParams(requestDto).toString(); const res = await getData(`v1/bizInfo?${params}`); const totalElements = Number(res.totalElements ?? 0); const mappedContent = (res.content || []).map( (item: any, index: number) => { const formattedItem = formatDisplayData(item); const matched = BIZ_TY_CD.find( (code) => code.lwpoCd === item.bizTypeCd, ); return { ...formattedItem, rowNumber: totalElements - ((curPage - 1) * OPERATION_TABLE_SIZE + index), bizTypeCd: matched ? matched.lwpoCdNm : item.bizTypeCd, }; }, ); setTableData(mappedContent || []); setTableCount(totalElements); setDetailTableData([]); setDetailTableCount(0); } setShowTable(true); setIsResetSelection(false); } catch (err) { console.error("API ERROR:", err); setTableData([]); setIsResetSelection(false); } finally { setIsLoading(false); setIsResetSelection(false); } }; // 조회 버튼 클릭 시 1페이지로 이동 및 데이터 초기화 const handleSearch = () => { setCurPage(1); void fetchFilteredData(); setIsResetPage(true); setIsResetDetailPage(true); setIsResetSelection(false); setIsResetDetailSelection(false); setShowTable(true); }; /** 현재 탭의 조건·페이지·선택을 기본값으로 복원하고 전체 기본 목록을 즉시 재조회한다. */ const handleResetSearch = () => { const state = useSearchModalStore.getState(); const resetsBasicType = state.activeTab === "basic" && state.basicType !== SEARCH_MODAL_DEFAULT_BASIC_TYPE; const resetsWorkType = state.activeTab === "operation" && state.workType !== SEARCH_MODAL_DEFAULT_WORK_TYPE; state.resetFilters(); if (state.activeTab === "basic") { state.setBasicType(SEARCH_MODAL_DEFAULT_BASIC_TYPE); } if (state.activeTab === "operation") { state.setWorkType(SEARCH_MODAL_DEFAULT_WORK_TYPE); } state.setCurPage(1); state.setDetailCurPage(1); state.setIsResetPage(true); state.setIsResetDetailPage(true); state.setIsResetSelection(true); state.setIsResetDetailSelection(true); // 구분 변경 시 SearchModal의 자동조회 effect가 실행되므로 중복 요청을 만들지 않는다. if (!resetsBasicType && !resetsWorkType) { void fetchFilteredData(); } }; // 여러 시설 보기 const viewMultipleFeature = async () => { if (activeTab === "basic") { if (!(tableData.length === 0)) { if (isPopupWindow()) { const row = tableData[0]; postPopupMessageAndClose( WINDOW_POPUP_MESSAGE_TYPE.MAP_SEARCH_SHOW_MULTIPLE, { layerNm: row.lyrTypeNm, fids: JSON.stringify(tableData.map((item) => item.fid)), }, ); return; } setIsLoading(true); const row = tableData[0]; const layerNm = row.lyrTypeNm; const fids = tableData.map((item) => item.fid); const core = GisApp.Module.layer as any; await core.showMultipleSearchResultsFromGeoJSON(layerNm, fids); setIsLoading(false); setIsSearchModalOpen(false); } } else if (activeTab === "operation") { if (!(detailTableData.length === 0)) { if (isPopupWindow()) { const row = detailTableData[0]; postPopupMessageAndClose( WINDOW_POPUP_MESSAGE_TYPE.MAP_SEARCH_SHOW_MULTIPLE, { layerNm: row.lyrTypeNm, fids: JSON.stringify(detailTableData.map((item) => item.fid)), }, ); return; } setIsLoading(true); const row = detailTableData[0]; const layerNm = row.lyrTypeNm; const fids = detailTableData.map((item) => item.fid); const core = GisApp.Module.layer as any; await core.showMultipleSearchResultsFromGeoJSON(layerNm, fids); setIsLoading(false); setIsSearchModalOpen(false); } } }; return { TABS, getDateString, handleSearch, handleResetSearch, viewMultipleFeature, fetchFilteredData, }; }