168 lines
5.4 KiB
TypeScript
168 lines
5.4 KiB
TypeScript
/**
|
|
* 📄 CtpvSggPrcsFcltSelectBox Component
|
|
* 시도/시군구/하수처리시설 선택 컴포넌트
|
|
*
|
|
* - 시도 선택 및 시군구 필터링 기능
|
|
* - 시군구 선택 시 하수처리시설 목록 조회
|
|
* - 선택 값 변경 시 콜백 함수 호출
|
|
* - 로딩 상태 관리 및 에러 핸들링
|
|
* - Zustand를 통한 시도/시군구 데이터 관리
|
|
* - CQL 필터를 통한 시설물 검색 조건 설정
|
|
*
|
|
* 🔗 사용 API
|
|
* - 시설물 조회: GET /v1/fclts (sewerage-service)
|
|
*/
|
|
import React, { useState, useEffect } from "react";
|
|
import { SelectBox } from '@common/business_components/ui'
|
|
import { Label } from '@common/components';
|
|
import useStore from '../../store/useStore';
|
|
import { getData } from '@/components/lib/api/index';
|
|
|
|
|
|
interface ApiSelectOption {
|
|
text: string;
|
|
val: string;
|
|
}
|
|
interface CtpvSggPrcsFcltSelectBoxProps {
|
|
sido: string;
|
|
sigungu: string;
|
|
sggName?: string;
|
|
onSidoChange: (id: string) => void;
|
|
onSigunguChange: (id: string) => void;
|
|
setCtpvName?: (name: string) => void;
|
|
setSggName?: (name: string) => void;
|
|
className?: string;
|
|
selectedSwagePrcsFclt?: string;
|
|
onSwagePrcsFcltChange?: (value: string) => void;
|
|
setSwtrmtFcltNm?: (name: string) => void;
|
|
setIsLoading?: (isLoading: boolean) => void;
|
|
}
|
|
|
|
const defaultOption: ApiSelectOption = { val: '0', text: '전체' };
|
|
|
|
export function CtpvSggPrcsFcltSelectBox({
|
|
sido,
|
|
sigungu,
|
|
sggName,
|
|
onSidoChange,
|
|
setCtpvName,
|
|
onSigunguChange,
|
|
setSggName,
|
|
className = "",
|
|
selectedSwagePrcsFclt,
|
|
onSwagePrcsFcltChange,
|
|
setSwtrmtFcltNm,
|
|
setIsLoading,
|
|
}: CtpvSggPrcsFcltSelectBoxProps) {
|
|
|
|
const [prcsFcltOptions, setPrcsFcltOptions] = useState<ApiSelectOption[]>([]);
|
|
const { ctpv, sgg } = useStore();
|
|
const sidoStr = String(sido ?? '');
|
|
const sidoPrefix = sidoStr.slice(0, 2);
|
|
|
|
useEffect(() => {
|
|
(async () => {
|
|
onSidoChange("0");
|
|
onSigunguChange("0");
|
|
if (setCtpvName && setSggName) {
|
|
setCtpvName("");
|
|
setSggName("");
|
|
}
|
|
if (setSwtrmtFcltNm) setSwtrmtFcltNm("");
|
|
})();
|
|
}, []);
|
|
|
|
useEffect(() => {
|
|
onSwagePrcsFcltChange?.('0');
|
|
|
|
const fetchData = async () => {
|
|
if (!sggName) {
|
|
setPrcsFcltOptions([]);
|
|
if (setIsLoading) setIsLoading(false);
|
|
return;
|
|
}
|
|
|
|
if (setIsLoading) setIsLoading(true);
|
|
try {
|
|
|
|
const queryParamsFacility = new URLSearchParams({
|
|
lyrTypeNm: 'tb_il_swage_prcs_fclt',
|
|
page: '0',
|
|
size: '100000', // 요청하신 URL에 맞게 50으로 변경 가능
|
|
sort: 'string',
|
|
});
|
|
const cqlFiltersFacility: string[] = [];
|
|
if (sggName) cqlFiltersFacility.push(`sgg_nm ILIKE '%${sggName}%'`);
|
|
if (cqlFiltersFacility.length > 0) queryParamsFacility.append('cqlFiter', cqlFiltersFacility.join(' and '));
|
|
|
|
const facilityRes = await getData(`v1/fclts?${queryParamsFacility.toString()}`);
|
|
|
|
const facilities = (facilityRes.data || [])
|
|
.map((item: any) => ({
|
|
text: item.swtrmtFcltNm,
|
|
val: item.fid
|
|
}))
|
|
.sort((a: ApiSelectOption, b: ApiSelectOption) => a.text.localeCompare(b.text, 'ko'));
|
|
setPrcsFcltOptions(facilities);
|
|
} catch (error) {
|
|
console.error("BaseLayout: 지역/시설 데이터 조회 중 오류 발생:", error);
|
|
setPrcsFcltOptions([]);
|
|
} finally {
|
|
if (setIsLoading) setIsLoading(false);
|
|
}
|
|
};
|
|
|
|
fetchData();
|
|
}, [sggName]);
|
|
|
|
|
|
return (
|
|
<div className={`flex items-center justify-center ${className} mr-8`}>
|
|
<Label className="text-xl text-gray-600 font-medium whitespace-nowrap mr-2">시도</Label>
|
|
<SelectBox
|
|
className="w-48 mr-8"
|
|
selectClass="rounded-lg bg-white"
|
|
label=""
|
|
selectArray={[defaultOption, ...ctpv]}
|
|
value={sido}
|
|
onSelectValue={val => {
|
|
onSidoChange(String(val));
|
|
if (setCtpvName) setCtpvName(ctpv.find(opt => String(opt.val) === String(val))?.text || "");
|
|
if (setSwtrmtFcltNm) setSwtrmtFcltNm("");
|
|
}}
|
|
selectContentClass="z-[101]"
|
|
/>
|
|
<Label className="text-xl text-gray-600 font-medium whitespace-nowrap mr-2">시군구</Label>
|
|
<SelectBox
|
|
className="w-48"
|
|
selectClass="w-48 rounded-lg bg-white truncate"
|
|
label=""
|
|
selectArray={[defaultOption, ...sgg.filter(opt => opt.val.startsWith(sidoPrefix))]}
|
|
value={sigungu}
|
|
onSelectValue={val => {
|
|
onSigunguChange(String(val))
|
|
if (setSggName) setSggName(sgg.find(opt => String(opt.val) === String(val))?.text || "");
|
|
if (setSwtrmtFcltNm) setSwtrmtFcltNm("")
|
|
}}
|
|
selectContentClass="z-[101]"
|
|
/>
|
|
{selectedSwagePrcsFclt && onSwagePrcsFcltChange && (
|
|
<>
|
|
<Label className="text-xl text-gray-600 font-medium whitespace-nowrap ml-8 mr-4">하수처리시설명</Label>
|
|
<SelectBox
|
|
className="w-[160px]"
|
|
selectClass="rounded-lg bg-white truncate"
|
|
label=""
|
|
selectArray={[defaultOption, ...prcsFcltOptions]}
|
|
value={selectedSwagePrcsFclt}
|
|
onSelectValue={(val) => {
|
|
onSwagePrcsFcltChange?.(String(val))
|
|
if (setSwtrmtFcltNm) setSwtrmtFcltNm(prcsFcltOptions.find(opt => String(opt.val) === String(val))?.text || "")
|
|
}}
|
|
selectContentClass="z-[101]"
|
|
/>
|
|
</>
|
|
)}
|
|
</div>
|
|
);
|
|
} |