import { useCallback, useRef, useState } from "react"; import { useAlertStore } from "@/shared/lib"; import { statisticsApi } from "@/entities/statistics/api/statistics-service"; import type { StatsInputPeriodItem, StatsInputPeriodListRequest, } from "@/entities/statistics/model/statistics-interface"; import { Button, LoadingWithAnimation } from "@common/components"; import { StatisticsInputPeriodDialog, type StatisticsInputPeriodDialogValues, } from "./StatisticsInputPeriodDialog"; import DataGrid from "@/components/module/DataGrid"; import SearchForm from "@/components/module/SearchForm"; import type { ColumnConfig, DataCellClickCallbackParams } from "@/components/type/DataGrid.type"; import type { SearchFormValues } from "@/components/type/SearchForm.type"; import { toGridRows } from "@/components/util/grid/gridFunction"; /** API `YYYYMMDD` 등 → Date */ function seTypeToDisplayLabel(seType: StatsInputPeriodItem["seType"]): string { if (seType === "INPT") return "입력"; if (seType === "VRFC") return "검증"; return seType; } function rowSeTypeToCode(row: Record): "INPT" | "VRFC" { const v = String(row.seType ?? ""); if (v === "INPT" || v === "입력") return "INPT"; if (v === "VRFC" || v === "검증") return "VRFC"; return "INPT"; } function parseExtSchdlId(value: string | number | undefined): number | undefined { if (typeof value === "number" && Number.isFinite(value)) return value; const parsed = parseInt(String(value ?? ""), 10); return Number.isFinite(parsed) ? parsed : undefined; } function parseYmdToDate(ymd: string): Date | undefined { const s = String(ymd ?? "").replace(/\D/g, ""); if (s.length !== 8) return undefined; const y = Number(s.slice(0, 4)); const m = Number(s.slice(4, 6)); const d = Number(s.slice(6, 8)); if (!y || m < 1 || m > 12 || d < 1 || d > 31) return undefined; const dt = new Date(y, m - 1, d); if (dt.getFullYear() !== y || dt.getMonth() !== m - 1 || dt.getDate() !== d) { return undefined; } return dt; } function formatYmdForDisplay(ymd: string): string { const s = String(ymd ?? "").replace(/\D/g, ""); if (s.length !== 8) return String(ymd ?? ""); return `${s.slice(0, 4)}-${s.slice(4, 6)}-${s.slice(6, 8)}`; } const PERIOD_DETAIL_FIELD = "detailInfo"; const StatisticsInputManagement = () => { const { setMessage: alert } = useAlertStore((state) => state); const [isLoading, setIsLoading] = useState(false); const [rowData, setRowData] = useState[]>( [], ); const [periodDialogOpen, setPeriodDialogOpen] = useState(false); const [periodDialogMode, setPeriodDialogMode] = useState<"edit" | "create">("edit"); const [createDefaultStatsYr, setCreateDefaultStatsYr] = useState(""); const [periodDialogInitial, setPeriodDialogInitial] = useState(null); const [searchFormValues, setSearchFormValues] = useState(null); const lastSearchRef = useRef(null); const handleSearch = async (values: SearchFormValues) => { if (!values.year) { alert("년도를 선택해주세요."); return; } lastSearchRef.current = values; try { setIsLoading(true); const params: StatsInputPeriodListRequest = { statsYr: values.year, ...(values.clsfCd && values.clsfCd !== "ALL" ? { seType: values.clsfCd } : {}), }; const res = await statisticsApi.getStatsInputPeriodList(params); if (res.status === "success" && Array.isArray(res.data)) { const rowsForGrid = res.data.map((row) => ({ ...row, seType: seTypeToDisplayLabel(row.seType), inptBgngYmd: formatYmdForDisplay(row.inptBgngYmd), inptEndYmd: formatYmdForDisplay(row.inptEndYmd), [PERIOD_DETAIL_FIELD]: "상세정보", })); setRowData(toGridRows(rowsForGrid)); } else { setRowData([]); alert(res.message || "데이터 조회에 실패했습니다."); } } catch { setRowData([]); alert("데이터 조회 중 오류가 발생했습니다."); } finally { setIsLoading(false); } }; const handleReset = () => { setRowData([]); }; const handleRegisterClick = () => { const yr = searchFormValues?.year ?? lastSearchRef.current?.year ?? ""; if (!yr) { alert("검색 폼에서 년도를 선택해 주세요."); return; } setPeriodDialogMode("create"); setCreateDefaultStatsYr(yr); setPeriodDialogInitial(null); setPeriodDialogOpen(true); }; const openPeriodDetailForRow = useCallback( async (row: Record) => { const seCdRaw = row.seCd; const seCdNum = typeof seCdRaw === "number" ? seCdRaw : parseInt(String(seCdRaw ?? ""), 10); const seCd = Number.isFinite(seCdNum) ? seCdNum : 0; const statsYr = String(row.statsYr ?? ""); const seType = rowSeTypeToCode(row); const extSchdlId = parseExtSchdlId(row.extSchdlId); try { setIsLoading(true); const res = await statisticsApi.getStatsInputPeriodDetail({ statsYr, seType, seCd, ...(extSchdlId != null ? { extSchdlId } : {}), }); if (res.status !== "success" || !res.data) { alert(res.message || "상세 정보를 조회하지 못했습니다."); return; } const detail = res.data; const detailExtSchdlId = parseExtSchdlId(detail.extSchdlId) ?? extSchdlId; setPeriodDialogMode("edit"); setPeriodDialogInitial({ extSchdlId: detailExtSchdlId, statsYr: String(detail.statsYr ?? statsYr), seType: detail.seType === "VRFC" ? "VRFC" : "INPT", seCd: typeof detail.seCd === "number" && Number.isFinite(detail.seCd) ? detail.seCd : seCd, inptBgngYmd: parseYmdToDate(detail.inptBgngYmd), inptEndYmd: parseYmdToDate(detail.inptEndYmd), }); setPeriodDialogOpen(true); } catch { alert("상세 정보 조회 중 오류가 발생했습니다."); } finally { setIsLoading(false); } }, [alert], ); const handlePeriodDetailCellClick = useCallback( ({ fieldName, row }: DataCellClickCallbackParams) => { if (fieldName !== PERIOD_DETAIL_FIELD) return; void openPeriodDetailForRow(row); }, [openPeriodDetailForRow], ); const columns: ColumnConfig[] = [ { name: "statsYr", fieldName: "statsYr", header: { text: "연도" }, editable: false, }, { name: "seType", fieldName: "seType", header: { text: "분류" }, editable: false, }, { name: "inptBgngYmd", fieldName: "inptBgngYmd", header: { text: "시작일" }, editable: false, }, { name: "inptEndYmd", fieldName: "inptEndYmd", header: { text: "종료일" }, editable: false, }, { name: PERIOD_DETAIL_FIELD, fieldName: PERIOD_DETAIL_FIELD, header: { text: "상세정보" }, editable: false, width: 118, styleName: "rg-cell-outline-action-btn", }, ]; const columnLayout = [ "statsYr", "seType", "inptBgngYmd", "inptEndYmd", PERIOD_DETAIL_FIELD, ]; return (
{ setPeriodDialogOpen(open); if (!open) { setPeriodDialogInitial(null); setPeriodDialogMode("edit"); } }} initial={periodDialogInitial} onSaveSuccess={async () => { const v = lastSearchRef.current; if (v) await handleSearch(v); }} /> {isLoading && (
)}
); }; export default StatisticsInputManagement;