"use client"; import { useEffect, useState } from "react"; import useSWR from "swr"; import { useAlertStore, useUserStore } from "@/shared/lib"; import { statisticsApi } from "@/entities/statistics/api/statistics-service"; import type { ApiResponse, SearchCondition, Sgg, } from "@/entities/statistics/model/statistics-interface"; import { Button, Checkbox, Input, Label, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@common/components"; import { defaultSearchFormProps, type SearchFormClsfCd, type SearchFormProps, type SearchFormValues, } from "../type/SearchForm.type"; import { doList } from "../util/column/input/DoList"; const getSidoListFetcher = async ( key: [string, string], ): Promise> => { return statisticsApi.getSidoList({ instSeCd: key[1] }); }; const getSggListFetcher = async ( key: [string, string, string, string], ): Promise> => { const gugunSkipYn = doList.includes(key[3]) ? "N" : "Y"; return statisticsApi.getSggList(key[1], { instSeCd: key[2], gugunSkipYn, }); }; function buildSearchFormValues( props: SearchFormProps, sidoList: ApiResponse | undefined, defaultYear: number, ): SearchFormValues { const d = props.defaultValues; const initialClsfCd: SearchFormClsfCd = d?.clsfCd === "ALL" || d?.clsfCd === "INPT" || d?.clsfCd === "VRFC" ? d.clsfCd : "ALL"; if (d?.sido) { return { sido: d.sido, gugun: d.gugun || "", year: d.year || defaultYear.toString(), order: d.order || "", fctName: d.fctName || "", bsnmCd: d.bsnmCd || "", isDetail: false, isSummary: d.isSummary || "", clsfCd: initialClsfCd, }; } const first = sidoList?.data?.sidoList?.[0]; const useFirstSido = (props.sido ?? defaultSearchFormProps.sido) && first; return { sido: useFirstSido ? first.sido : "", gugun: "", year: d?.year || defaultYear.toString(), order: d?.order || "", fctName: d?.fctName || "", bsnmCd: useFirstSido ? first.bsnmCd : "", isDetail: false, isSummary: d?.isSummary || "", clsfCd: initialClsfCd, }; } const SearchForm = (props: SearchFormProps = {}) => { const { setMessage: alert } = useAlertStore((state) => state); const userInfo = useUserStore((state) => state.userInfo); const mergedProps = { ...defaultSearchFormProps, ...props }; const instSeCd = userInfo?.instSeCd ?? ""; const sidoSelectText = props.sidoSelectText && props.sidoSelectText.trim() !== "" ? props.sidoSelectText : "선택"; const currentYear = new Date().getFullYear(); const defaultYear = currentYear - 1; const { data: sidoList } = useSWR>( ["sido-list", instSeCd], getSidoListFetcher, { revalidateOnFocus: false, revalidateOnReconnect: false, revalidateIfStale: false, dedupingInterval: 2000, shouldRetryOnError: false, onSuccess: (data) => { if (data.status !== "success") { alert(`시도 목록을 불러오는데 실패했습니다. 새로고침 후 다시 시도해주세요.`); } }, onError: () => { alert(`시도 목록을 불러오는데 실패했습니다. 새로고침 후 다시 시도해주세요.`); }, }, ); // 마운트 시 SWR 캐시의 시도 목록으로 초기값 설정 (탭 닫았다 열 때 API 재호출 없이 동작) const [values, setValues] = useState(() => buildSearchFormValues(props, sidoList, defaultYear), ); // 최초 진입만 시도 API가 늦게 오는 경우 useEffect(() => { if (props.defaultValues?.sido) return; const first = sidoList?.data?.sidoList?.[0]; if (!first || !mergedProps.sido) return; setValues((prev) => prev.sido ? prev : { ...prev, sido: first.sido, gugun: "", bsnmCd: first.bsnmCd, }, ); }, [sidoList, props.defaultValues?.sido, mergedProps.sido]); const sggKey: [string, string, string, string] | null = values.sido && values.sido !== "ALL" ? ["sgg-list", values.sido, instSeCd, values.bsnmCd || ""] : null; const { data: sggList } = useSWR>( sggKey, getSggListFetcher, { revalidateOnFocus: false, revalidateOnReconnect: false, revalidateIfStale: false, dedupingInterval: 2000, shouldRetryOnError: false, onSuccess: (data) => { if (data.status !== "success") { alert(`시군구 목록을 불러오는데 실패했습니다. 새로고침 후 다시 시도해주세요.`); } }, onError: () => { alert(`시군구 목록을 불러오는데 실패했습니다. 새로고침 후 다시 시도해주세요.`); }, }, ); const sggOptions = sggList?.data ?? []; const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); props.onSubmit?.(values); }; const handleReset = () => { setValues(buildSearchFormValues(props, sidoList, defaultYear)); props.onReset?.(); }; const handleSidoChange = (value: string) => { const selectedBsnm = sidoList?.data.sidoList.find((v) => v.sido === value)?.bsnmCd || ""; setValues((prev) => ({ ...prev, sido: value, gugun: "", bsnmCd: selectedBsnm, })); }; const handleSggChange = (value: string) => { const listForBsnm = sggList?.data ?? []; const selectedBsnm = value === "ALL" ? sidoList?.data.sidoList.find((v) => v.sido === values.sido) ?.bsnmCd || "" : listForBsnm.find((v) => v.gugun === value)?.bsnmCd || ""; setValues((prev) => ({ ...prev, gugun: value, bsnmCd: selectedBsnm, })); }; useEffect(() => { props.onValuesChange?.(values); }, [values]); return (
{mergedProps.sido && (
)} {mergedProps.gugun && (
)} {mergedProps.year && (
)} {mergedProps.clsf && (
)} {mergedProps.fctName && (
setValues({ ...values, fctName: e.target.value, }) } autoComplete="off" />
)} {mergedProps.isDetail && (
setValues({ ...values, isDetail: value === true, }) } />
)} {mergedProps.isSummary && (
)} {mergedProps.order && (
)}
); }; export default SearchForm;