"use client"; import { useEffect, useState } from "react"; import { useConfirm } from "@frontend-opensource/use-react-hooks"; import { useAlertStore } from "@/shared/lib"; import { statisticsApi } from "@/entities/statistics/api/statistics-service"; import type { StatsInputPeriodDeleteRequest, StatsInputPeriodSaveRequest, } from "@/entities/statistics/model/statistics-interface"; import { Button, Dialog, DialogClose, DialogContent, DialogFooter, DialogHeader, DialogTitle, Input, InputDatePicker, Label, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@common/components"; import { getUserInfo } from "../../../../../../packages/common/components/src/api"; export type StatisticsInputPeriodDialogValues = { statsYr: string; seType: "INPT" | "VRFC"; seCd: number; inptBgngYmd: Date | undefined; inptEndYmd: Date | undefined; }; export type StatisticsInputPeriodDialogMode = "edit" | "create"; function normalizeStatsYrInput(raw: string): string { return raw.replace(/\D/g, "").slice(0, 4); } function formatDateToYmd(d: Date | undefined): string | null { if (!d || Number.isNaN(d.getTime())) return null; const y = d.getFullYear(); const m = String(d.getMonth() + 1).padStart(2, "0"); const day = String(d.getDate()).padStart(2, "0"); return `${y}${m}${day}`; } export interface StatisticsInputPeriodDialogProps { open: boolean; onOpenChange: (open: boolean) => void; /** 행 클릭(수정) 시에만 전달. 등록 모드에서는 null */ initial: StatisticsInputPeriodDialogValues | null; mode: StatisticsInputPeriodDialogMode; /** mode가 create일 때 SearchForm의 연도 */ createDefaultStatsYr?: string; /** 저장 성공 후 목록 재조회 등 */ onSaveSuccess?: () => void | Promise; } export function StatisticsInputPeriodDialog({ open, onOpenChange, initial, mode, createDefaultStatsYr, onSaveSuccess, }: StatisticsInputPeriodDialogProps) { const { setMessage: alert } = useAlertStore((state) => state); const { confirm } = useConfirm(); const [statsYr, setStatsYr] = useState(""); const [seType, setSeType] = useState<"INPT" | "VRFC" | null>(null); const [seCdInput, setSeCdInput] = useState(""); const [inptBgngYmd, setInptBgngYmd] = useState(undefined); const [inptEndYmd, setInptEndYmd] = useState(undefined); const [isSubmitting, setIsSubmitting] = useState(false); useEffect(() => { if (!open) return; if (mode === "create") { setStatsYr(normalizeStatsYrInput(createDefaultStatsYr ?? "")); setSeType(null); setSeCdInput("0"); setInptBgngYmd(undefined); setInptEndYmd(undefined); return; } if (!initial) return; setStatsYr(normalizeStatsYrInput(String(initial.statsYr ?? ""))); setSeType(initial.seType); setSeCdInput(String(Number.isFinite(initial.seCd) ? initial.seCd : 0)); setInptBgngYmd(initial.inptBgngYmd); setInptEndYmd(initial.inptEndYmd); }, [open, mode, initial, createDefaultStatsYr]); const handleSave = async () => { const bgng = formatDateToYmd(inptBgngYmd); const end = formatDateToYmd(inptEndYmd); if (!bgng || !end) { alert("시작일과 종료일을 선택해주세요."); return; } if (bgng > end) { alert("시작일은 종료일보다 늦을 수 없습니다."); return; } if (seType === null) { alert("분류를 선택해주세요."); return; } const seCdParsed = mode === "create" ? 0 : (() => { const n = parseInt(seCdInput, 10); return Number.isFinite(n) && n >= 0 ? n : NaN; })(); if (mode === "edit" && !Number.isFinite(seCdParsed)) { alert("구분 값이 올바르지 않습니다."); return; } const yr = normalizeStatsYrInput(statsYr.trim()); if (mode === "create" && !/^\d{4}$/.test(yr)) { alert("연도는 숫자 4자리로 입력해 주세요."); return; } if (mode === "edit" && !yr) { alert("연도가 없습니다."); return; } try { setIsSubmitting(true); const userInfo = await getUserInfo(); const param: StatsInputPeriodSaveRequest = { statsYr: yr, seType, inptBgngYmd: bgng, inptEndYmd: end, rgtrId: userInfo.userUnqId, }; if (!isCreate) { param.seCd = seCdParsed; } const res = await statisticsApi.saveStatsInputPeriod(param); if (res.status === "success") { alert(`${isCreate ? '등록 되었습니다.' : '수정 되었습니다.'}`); onOpenChange(false); await onSaveSuccess?.(); } else { alert(res.message || "저장에 실패했습니다."); } } catch { alert("저장 중 오류가 발생했습니다."); } finally { setIsSubmitting(false); } }; const handleDelete = async () => { if (mode === "create" || !initial) return; if (!(await confirm("삭제하시겠습니까?"))) return; const bgng = formatDateToYmd(initial.inptBgngYmd); const end = formatDateToYmd(initial.inptEndYmd); if (!bgng || !end) { alert("삭제할 기간 정보가 없습니다."); return; } const yr = normalizeStatsYrInput(String(initial.statsYr ?? "")); if (!yr) { alert("연도가 없습니다."); return; } const seCd = Number.isFinite(initial.seCd) && initial.seCd >= 0 ? initial.seCd : 0; try { setIsSubmitting(true); const userInfo = await getUserInfo(); const param: StatsInputPeriodDeleteRequest = { statsYr: yr, seType: initial.seType, seCd, inptBgngYmd: bgng, inptEndYmd: end, rgtrId: userInfo.userUnqId, }; const res = await statisticsApi.deleteStatsInputPeriod(param); if (res.status === "success") { alert("삭제되었습니다."); onOpenChange(false); await onSaveSuccess?.(); } else { alert(res.message || "삭제에 실패했습니다."); } } catch { alert("삭제 중 오류가 발생했습니다."); } finally { setIsSubmitting(false); } }; const isCreate = mode === "create"; return ( {isCreate ? "입력 기간 등록" : "입력 관리"}
{isCreate ? ( setStatsYr(normalizeStatsYrInput(e.target.value)) } placeholder="예: 2025" disabled={isSubmitting} className="!text-[1.3rem]" /> ) : ( )}
{!isCreate && (
)}
{!isCreate && ( )}
); }