"use client"; import { useEffect, useState } from "react"; import { useAlertStore } from "@/shared/lib"; import { Button, Dialog, DialogClose, DialogContent, DialogFooter, DialogHeader, DialogTitle, Input, InputDatePicker, Label, } from "@common/components"; export interface MainFacilityMappingSaveDialogValues { prxyBzentyNmCn: string; /** 위탁비용(백만원/년) */ cnsgnCstVl: number; wholNope: number; /** YYYYMMDD~YYYYMMDD */ prxyCtrtCn: string; } export interface MainFacilityMappingSaveDialogProps { open: boolean; onOpenChange: (open: boolean) => void; initialPrxyBzentyNmCn: string; /** 위탁비용(백만원/년) 초기값 */ initialCnsgnCstVl: number; initialWholNope: number; /** 위탁계약기간 초기값 (YYYYMMDD~YYYYMMDD) */ initialPrxyCtrtCn: string; onConfirm?: (values: MainFacilityMappingSaveDialogValues) => void | Promise; } 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}`; } /** `YYYYMMDD` → `Date` (로컬 자정) */ function parseYmdToDate(ymd: string): Date | undefined { const s = ymd.replace(/\D/g, ""); if (s.length !== 8) return undefined; const y = Number(s.slice(0, 4)); const mo = Number(s.slice(4, 6)) - 1; const day = Number(s.slice(6, 8)); const d = new Date(y, mo, day); if (d.getFullYear() !== y || d.getMonth() !== mo || d.getDate() !== day) return undefined; return d; } function parseInitialPrxyCtrtCnToDates(initial: string): { start: Date | undefined; end: Date | undefined } { const t = initial.trim(); if (!/^\d{8}~\d{8}$/.test(t)) { return { start: undefined, end: undefined }; } const start = parseYmdToDate(t.slice(0, 8)); const end = parseYmdToDate(t.slice(9, 17)); return { start, end }; } function validateContractRange(start: Date | undefined, end: Date | undefined): string | null { const startYmd = formatDateToYmd(start); const endYmd = formatDateToYmd(end); if (!startYmd || !endYmd) { return "시작일과 종료일을 선택해 주세요."; } if (startYmd > endYmd) { return "시작일이 종료일보다 늦을 수 없습니다."; } return null; } export function MainFacilityMappingSaveDialog({ open, onOpenChange, initialPrxyBzentyNmCn, initialCnsgnCstVl, initialWholNope, initialPrxyCtrtCn, onConfirm, }: MainFacilityMappingSaveDialogProps) { const { setMessage: alert } = useAlertStore((state) => state); const [prxyBzentyNmCn, setPrxyBzentyNmCn] = useState(""); const [cnsgnCstInput, setCnsgnCstInput] = useState(""); const [wholNopeInput, setWholNopeInput] = useState(""); const [prxyCtrtStart, setPrxyCtrtStart] = useState(undefined); const [prxyCtrtEnd, setPrxyCtrtEnd] = useState(undefined); const [isSubmitting, setIsSubmitting] = useState(false); useEffect(() => { if (open) { setPrxyBzentyNmCn(initialPrxyBzentyNmCn ?? ""); const initCost = Number(initialCnsgnCstVl); setCnsgnCstInput( initialCnsgnCstVl === null || initialCnsgnCstVl === undefined || Number.isNaN(initCost) ? "" : String(initCost), ); setWholNopeInput( initialWholNope === null || initialWholNope === undefined || Number.isNaN(Number(initialWholNope)) ? "" : String(initialWholNope), ); const { start, end } = parseInitialPrxyCtrtCnToDates(initialPrxyCtrtCn ?? ""); setPrxyCtrtStart(start); setPrxyCtrtEnd(end); } }, [open, initialPrxyBzentyNmCn, initialCnsgnCstVl, initialWholNope, initialPrxyCtrtCn]); const handleDialogOpenChange = (nextOpen: boolean) => { if (!nextOpen && !isSubmitting) { setPrxyBzentyNmCn(""); setCnsgnCstInput(""); setWholNopeInput(""); setPrxyCtrtStart(undefined); setPrxyCtrtEnd(undefined); } onOpenChange(nextOpen); }; const handleConfirm = async () => { const trimmedCost = cnsgnCstInput.trim(); const cnsgnCstVl = trimmedCost === "" ? 0 : Number.parseFloat(trimmedCost.replace(/,/g, "")); if (!Number.isFinite(cnsgnCstVl) || cnsgnCstVl < 0) { alert("위탁비용은 0 이상의 숫자로 입력해 주세요."); return; } const trimmedWhol = wholNopeInput.trim(); const wholNope = trimmedWhol === "" ? 0 : Number.parseInt(trimmedWhol, 10); if (!Number.isFinite(wholNope) || wholNope < 0) { alert("전체 인원은 0 이상의 정수로 입력해 주세요."); return; } const prxyCtrtErr = validateContractRange(prxyCtrtStart, prxyCtrtEnd); if (prxyCtrtErr) { alert(prxyCtrtErr); return; } const startYmd = formatDateToYmd(prxyCtrtStart)!; const endYmd = formatDateToYmd(prxyCtrtEnd)!; const prxyCtrtCnParam = `${startYmd}~${endYmd}`; try { setIsSubmitting(true); await onConfirm?.({ prxyBzentyNmCn: prxyBzentyNmCn.trim(), cnsgnCstVl, wholNope, prxyCtrtCn: prxyCtrtCnParam, }); } finally { setIsSubmitting(false); } }; return ( 저장 정보 입력
setPrxyBzentyNmCn(e.target.value)} className="!text-[1.3rem]" placeholder="위탁사업자명을 입력하세요." disabled={isSubmitting} />
{ const v = e.target.value.replace(/[^\d.]/g, ""); const firstDot = v.indexOf("."); const next = firstDot === -1 ? v : v.slice(0, firstDot + 1) + v.slice(firstDot + 1).replace(/\./g, ""); setCnsgnCstInput(next); }} className="!text-[1.3rem]" placeholder="0" disabled={isSubmitting} />
{ const v = e.target.value.replace(/\D/g, ""); setWholNopeInput(v); }} className="!text-[1.3rem]" placeholder="0" disabled={isSubmitting} />
); }