feat: 시도, 시군구 zustand Store로 메인 화면에서 호출 후 SearchModal.tsx에서 사용

This commit is contained in:
swcho
2025-07-30 20:55:57 +09:00
parent 4cfa032be2
commit b5c7f09bc9
5 changed files with 62 additions and 99 deletions
+7
View File
@@ -6,6 +6,7 @@ import { useCallback, useEffect, useRef, useState } from "react";
import GisApp from "@common/business_components/ui/map/lib/gis.core";
import SearchModal from "./searchModal/searchModal";
import FeatureClickEventPopup from "./components/popupComponent/featureClickEventPopup";
import useStore from "../../store/useStore";
// 타입 정의 추가
export type LyrStngProps = {
@@ -38,6 +39,12 @@ const Map = () => {
const [isOpen, setIsOpen] = useState(false); // 팝업 열기/닫기 상태
const [isSearchModalOpen, setIsSearchModalOpen] = useState(false); // SearchModal 열림 상태
const [featureData, setFeatureData] = useState(null); // 선택된 피쳐 데이터
const { fetchCtpvData, fetchSggData } = useStore();
useEffect(() => {
fetchCtpvData();
fetchSggData();
}, [fetchCtpvData, fetchSggData]);
const fetchData = async () => {
try {
@@ -29,19 +29,13 @@ interface SwagePrcsFcltProps {
}
const SwagePrcsFclt: React.FC<SwagePrcsFcltProps> = ({
var1,
start1,
start2,
end1,
end2,
city,
sgg,
yearFilter,
setVar1,
setStart1,
setStart2,
setEnd1,
setEnd2,
setCity,
setCtpvName,
setSgg,
@@ -114,57 +108,6 @@ const SwagePrcsFclt: React.FC<SwagePrcsFcltProps> = ({
}
}}
/>
{/* 처리구역 면적 */}
{/* <Label className="text-xl text-gray-600 font-medium whitespace-nowrap mr-2">처리구역 면적(m²)</Label>
<Input
className="w-[60px] !text-xl placeholder:text-center"
placeholder="입력"
value={start2}
onChange={(e) => {
// 숫자만 입력 허용
const val = e.target.value.replace(/[^0-9]/g, "");
setStart2(val);
}}
onKeyDown={(e) => {
if (e.key === 'Enter') {
e.preventDefault(); // Enter 키 기본 동작 방지
handleSearch();
}
}}
/>
<span className="mx-2 text-xl font-semibold">~</span>
<Input
className="mr-8 w-[60px] !text-xl placeholder:text-center"
placeholder="입력"
value={end2}
onChange={(e) => {
// 숫자만 입력 허용
const val = e.target.value.replace(/[^0-9]/g, "");
setEnd2(val);
}}
onKeyDown={(e) => {
if (e.key === 'Enter') {
e.preventDefault(); // Enter 키 기본 동작 방지
handleSearch();
}
}}
/> */}
{/* 하수처리시설명 */}
{/* <Label className="text-xl text-gray-600 font-medium whitespace-nowrap mr-2">하수처리시설명</Label>
<Input
className="mr-8 w-[100px] !text-xl placeholder:text-center"
placeholder="입력"
value={var1}
onChange={(e) => {
setVar1(e.target.value);
}}
onKeyDown={(e) => {
if (e.key === 'Enter') {
e.preventDefault(); // Enter 키 기본 동작 방지
handleSearch();
}
}}
/> */}
{/* 조회 버튼 */}
<div className="flex-1 flex justify-end">
<Button className="text-base py-2" onClick={handleSearch}>조회</Button>
@@ -40,13 +40,13 @@ const swagePrcsZone: React.FC<swagePrcsZoneProps> = ({
}}
onSigunguChange={setSgg}
/>
<Label className="text-xl text-gray-600 font-medium whitespace-nowrap mr-2">하수처리구역명</Label>
<Label className="text-xl text-gray-600 font-medium whitespace-nowrap mr-2">하수처리시설명</Label>
<Input
className="mr-8 w-[100px] !text-xl placeholder:text-center"
className='!text-xl w-[120px] placeholder:text-center mr-8'
placeholder="입력"
value={var1}
value={var2}
onChange={(e) => {
setVar1(e.target.value);
setVar2(e.target.value);
}}
onKeyDown={(e) => {
if (e.key === 'Enter') {
@@ -55,13 +55,13 @@ const swagePrcsZone: React.FC<swagePrcsZoneProps> = ({
}
}}
/>
<Label className="text-xl text-gray-600 font-medium whitespace-nowrap mr-2">하수처리시설명</Label>
<Label className="text-xl text-gray-600 font-medium whitespace-nowrap mr-2">하수처리구역명</Label>
<Input
className='!text-xl w-[120px] placeholder:text-center mr-8'
className="mr-8 w-[100px] !text-xl placeholder:text-center"
placeholder="입력"
value={var2}
value={var1}
onChange={(e) => {
setVar2(e.target.value);
setVar1(e.target.value);
}}
onKeyDown={(e) => {
if (e.key === 'Enter') {
@@ -1,7 +1,7 @@
import React, { useState, useMemo, useEffect } from "react";
import { SelectBox } from '@common/business_components/ui'
import { Label } from '@common/components';
import { getGeoData } from '@/components/lib/api';
import useStore from '../../store/useStore';
interface Option {
id: number;
@@ -28,38 +28,10 @@ export function SidoSigunguSelectBox({
className = "",
}: SidoSigunguSelectBoxProps) {
const [ctpvList, setCtpvList] = useState<Option[]>([]);
const [sggList, setSggList] = useState<Option[]>([]);
// 선택된 시도에 따라 시군구 리스트를 가져옴
const fetchCtpvData = useMemo(() => (
async () => {
const ctpvData = await getGeoData('/hasudo/ows?service=WFS&version=1.0.0&request=GetFeature&typeName=hasudo%3Atb_ms_ctpv&outputFormat=application%2Fjson');
const ctpvList: Option[] = ctpvData.features
.map((feature: any) => ({
id: feature.properties.mctpv_cd.trim(),
name: feature.properties.mctpv_korn_nm
}))
.sort((a: Option, b: Option) => a.name.localeCompare(b.name, 'ko')); // 가나다순 정렬
setCtpvList(ctpvList);
}
), []);
// 선택된 시도에 따라 시군구 리스트를 가져옴
const fetchSggData = useMemo(() => (
async () => {
const sggData = await getGeoData('/hasudo/ows?service=WFS&version=1.0.0&request=GetFeature&typeName=hasudo%3Atb_ms_sgg&outputFormat=application%2Fjson');
const sggList: Option[] = sggData.features
.map((feature: any) => ({ id: feature.properties.sgg_cd, name: feature.properties.sgg_korn_nm }))
.sort((a: Option, b: Option) => a.name.localeCompare(b.name, 'ko')); // 가나다순 정렬
setSggList(sggList);
}
), []);
const { ctpv, sgg} = useStore();
useEffect(() => {
(async () => {
await fetchCtpvData();
await fetchSggData();
onSidoChange(0);
onSigunguChange(0);
if (setCtpvName && setSggName) {
@@ -79,13 +51,13 @@ export function SidoSigunguSelectBox({
label=""
selectArray={
[{ val: 0, text: '전체' },
...ctpvList.map(opt => ({ val: opt.id, text: opt.name }))
...ctpv.map(opt => ({ val: opt.id, text: opt.name }))
]
}
value={sido}
onSelectValue={val => {
onSidoChange(Number(val));
if (setCtpvName) setCtpvName(ctpvList.find(opt => Number(opt.id) === Number(val))?.name || "");
if (setCtpvName) setCtpvName(ctpv.find(opt => Number(opt.id) === Number(val))?.name || "");
}}
selectContentClass="z-[101]"
/>
@@ -96,7 +68,7 @@ export function SidoSigunguSelectBox({
label=""
selectArray={
[{ val: 0, text: '전체' },
...sggList
...sgg
.filter(opt => String(opt.id).slice(0, 2) === String(sido))
.map(opt => ({ val: opt.id, text: opt.name }))
]
@@ -104,7 +76,7 @@ export function SidoSigunguSelectBox({
value={sigungu}
onSelectValue={val => {
onSigunguChange(Number(val))
if (setSggName) setSggName(sggList.find(opt => Number(opt.id) === Number(val))?.name || "");
if (setSggName) setSggName(sgg.find(opt => Number(opt.id) === Number(val))?.name || "");
}}
selectContentClass="z-[101]"
/>
+41
View File
@@ -0,0 +1,41 @@
import { useMemo } from "react";
import { create } from "zustand";
import { getGeoData } from "@/components/lib/api";
import { get } from "http";
interface Option { id: number, name: string }
interface SnStoreState {
ctpv: Option[];
sgg: Option[];
fetchCtpvData: () => Promise<void>;
fetchSggData: () => Promise<void>;
}
const useStore = create<SnStoreState>((set) => ({
// Define your store state and actions here
ctpv: [],
sgg: [],
fetchCtpvData: async () => {
const ctpvData = await getGeoData('/hasudo/ows?service=WFS&version=1.0.0&request=GetFeature&typeName=hasudo%3Atb_ms_ctpv&outputFormat=application%2Fjson');
const ctpvList: Option[] = ctpvData.features
.map((feature: any) => ({
id: feature.properties.mctpv_cd.trim(),
name: feature.properties.mctpv_korn_nm
}))
.sort((a: Option, b: Option) => a.name.localeCompare(b.name, 'ko'));
set({ ctpv: ctpvList });
},
fetchSggData: async () => {
const sggData = await getGeoData('/hasudo/ows?service=WFS&version=1.0.0&request=GetFeature&typeName=hasudo%3Atb_ms_sgg&outputFormat=application%2Fjson');
const sggList: Option[] = sggData.features
.map((feature: any) => ({
id: feature.properties.sgg_cd,
name: feature.properties.sgg_korn_nm
}))
.sort((a: Option, b: Option) => a.name.localeCompare(b.name, 'ko'));
set({ sgg: sggList });
}
}));
export default useStore;