Files
frontend/apps/fo/app/pages/map/searchBar/searchBar.tsx
T
2025-08-04 10:29:37 +09:00

159 lines
5.5 KiB
TypeScript

"use client";
import { SelectBox, type SelectDataType } from "@common/business_components/ui";
import { Button } from "@common/components/ui";
import { useCallback, useEffect, useState } from "react";
interface SearchBarProps {
onFeatureSelect: (feature: any) => void;
gisMaps: React.RefObject<any>;
}
export function SearchBar({ onFeatureSelect, gisMaps }: SearchBarProps) {
const [sidoValue, setSidoValue] = useState("0");
const [sigunValue, setSigunValue] = useState("0");
const [sidoData, setSidoData] = useState<SelectDataType[]>([{ text: "선택", val: "0" }]);
const [sigunData, setSigunData] = useState<SelectDataType[]>([{ text: "선택", val: "0" }]);
const [filteredSigunData, setFilteredSigunData] = useState<SelectDataType[]>([{ text: "선택", val: "0" }]);
const [facilityData, setFacilityData] = useState<SelectDataType[]>([{ text: "선택", val: "0" }]);
const [facilityValue, setFacilityValue] = useState("0");
const fetchSido = async () => {
const url = `/geoserver/hasudo/ows?service=WFS&version=1.0.0&request=GetFeature&typeName=hasudo:tb_ms_ctpv&outputFormat=application/json&propertyName=mctpv_korn_nm,mctpv_cd`;
const res = await fetch(url);
const json = await res.json();
const list = json.features.map((f: any) => ({
text: f.properties.mctpv_korn_nm,
val: f.properties.mctpv_cd,
}));
setSidoData([{ text: "선택", val: "0" }, ...list]);
};
const fetchSigun = async () => {
const url = `/geoserver/hasudo/ows?service=WFS&version=1.0.0&request=GetFeature&typeName=hasudo:tb_ms_sgg&outputFormat=application/json&propertyName=sgg_cd,sgg_korn_nm`;
const res = await fetch(url);
const json = await res.json();
const list = json.features.map((f: any) => ({
text: f.properties.sgg_korn_nm,
val: f.properties.sgg_cd,
}));
setSigunData(list);
};
const fetchFacilitiesBySggNm = async (sggNm: string) => {
const encodedSggNm = encodeURIComponent(sggNm);
const url = `/geoserver/hasudo/ows?service=WFS&version=1.0.0&request=GetFeature&typeName=hasudo:tb_il_swage_prcs_fclt&outputFormat=application/json&cql_filter=sgg_nm='${encodedSggNm}'`;
const res = await fetch(url);
const json = await res.json();
const list = json.features.map((f: any) => ({
text: f.properties.swtrmt_fclt_nm ?? "(이름없음)",
val: f.id, // f.properties.swtrmt_fclt_cd 도 가능
}));
setFacilityData([{ text: "선택", val: "0" }, ...list]);
setFacilityValue("0");
};
useEffect(() => {
fetchSido();
fetchSigun();
}, []);
const initializeSigunData = useCallback(
(sidoCd: string) => {
if (sidoCd === "0") {
setFilteredSigunData([{ text: "선택", val: "0" }]);
setSigunValue("0");
return;
}
const prefix = sidoCd.substring(0, 2);
const filtered = sigunData.filter((item) => item.val.startsWith(prefix));
setFilteredSigunData([{ text: "선택", val: "0" }, ...filtered]);
setSigunValue("0");
},
[sigunData]
);
const onSelectValue = useCallback(
(val: string, type: string) => {
if (type === "ctpvCd") {
setSidoValue(val);
initializeSigunData(val);
setFacilityData([{ text: "선택", val: "0" }]);
} else if (type === "sggCd") {
setSigunValue(val);
const sggNm = sigunData.find((item) => item.val === val)?.text || "";
if (sggNm) fetchFacilitiesBySggNm(sggNm);
} else if (type === "fcltCd") {
setFacilityValue(val);
}
},
[initializeSigunData, sigunData]
);
const handleSearch = () => {
if (!gisMaps.current || facilityValue === "0") return;
const layers = gisMaps.current.getLayers().getArray();
for (const layer of layers) {
const source = layer.getSource?.();
const feature = source?.getFeatureById?.(facilityValue);
if (feature) {
onFeatureSelect(feature);
return;
}
}
alert("해당 처리시설을 지도에서 찾을 수 없습니다.");
};
return (
<div className="grid grid-cols-4 gap-4">
<div className="col-span-4">
<div className="card card-border flex">
<div className="col-span-10 flex flex-row">
<SelectBox
labelClass="w-[40px]"
className="mr-10 w-[200px]"
selectClass="rounded-lg bg-white"
label="시도"
selectArray={sidoData}
onSelectValue={(val) => onSelectValue(val.toString(), "ctpvCd")}
value={sidoValue}
/>
<SelectBox
labelClass="w-[65px]"
className="mr-10 w-[200px]"
selectClass="rounded-lg bg-white"
label="시군구"
selectArray={filteredSigunData}
onSelectValue={(val) => onSelectValue(val.toString(), "sggCd")}
value={sigunValue}
/>
<SelectBox
labelClass="w-[140px]"
className="mr-3 w-[250px]"
selectClass="rounded-lg bg-white"
label="하수처리시설"
selectArray={facilityData}
onSelectValue={(val) => onSelectValue(val.toString(), "fcltCd")}
value={facilityValue}
/>
</div>
<div className="flex flex-row space-x-2">
<Button
color="primary"
className="mx-2 mt-1 ml-10"
size={"sm"}
onClick={handleSearch}
>
조회
</Button>
</div>
</div>
</div>
</div>
);
}