"use client"; import { useState, useEffect } from "react"; import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter, } from "@/components/ui/dialog"; import { Button } from "@/components/ui/button"; import { Label } from "@/components/ui/label"; import { Input } from "@/components/ui/input"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select"; import { Alert, AlertDescription } from "@/components/ui/alert"; import { Textarea } from "@/components/ui/textarea"; import { Upload, X, FileIcon, Info } from "lucide-react"; import { toast } from "sonner"; import { useTranslation } from "@/i18n/client"; import { UnifiedDwgReceiptItem, DetailDwgReceiptItem, editDetailDwgReceipt } from "../actions"; import { v4 as uuidv4 } from "uuid"; import { useFileUploadWithProgress } from "../hooks/use-file-upload-with-progress"; import { uploadFilesWithProgress } from "../utils/upload-with-progress"; import { FileUploadProgressList } from "../components/file-upload-progress-list"; import { getB3DrawingUsageOptions, getB3RegisterKindOptions, getB4DrawingUsageOptions, getB4RegisterKindOptions } from "../utils/code-translator"; interface AddAndModifyDetailDrawingDialogProps { open: boolean; onOpenChange: (open: boolean) => void; drawing: UnifiedDwgReceiptItem | null; vendorCode: string; userId: string; userName: string; userEmail: string; onComplete: () => void; drawingKind: "B3" | "B4"; lng: string; mode?: "add" | "edit"; detailDrawing?: DetailDwgReceiptItem | null; } export function AddAndModifyDetailDrawingDialog({ open, onOpenChange, drawing, vendorCode, userId, userName, userEmail, onComplete, drawingKind, lng, mode = "add", detailDrawing = null, }: AddAndModifyDetailDrawingDialogProps) { const { t } = useTranslation(lng, "dolce"); const [drawingUsage, setDrawingUsage] = useState(""); const [registerKind, setRegisterKind] = useState(""); const [revision, setRevision] = useState(""); const [revisionError, setRevisionError] = useState(""); const [comment, setComment] = useState(""); const [isSubmitting, setIsSubmitting] = useState(false); // Edit 모드일 때 초기값 설정 useEffect(() => { if (mode === "edit" && detailDrawing && open) { setDrawingUsage(detailDrawing.DrawingUsage || ""); setRegisterKind(detailDrawing.RegisterKind || ""); setRevision(detailDrawing.DrawingRevNo || ""); setComment(detailDrawing.RegisterDesc || ""); } else if (mode === "add" && open) { // Add 모드로 열릴 때는 초기화 resetForm(); } }, [mode, detailDrawing, open]); // 옵션 생성 (다국어 지원) const drawingUsageOptions = drawingKind === "B3" ? getB3DrawingUsageOptions(lng) : getB4DrawingUsageOptions(lng); const registerKindOptions = drawingKind === "B3" ? getB3RegisterKindOptions(drawingUsage, lng).map(opt => ({ ...opt, revisionRule: lng === "ko" ? "예: A, B, C 또는 R00, R01, R02" : "e.g. A, B, C or R00, R01, R02" })) : getB4RegisterKindOptions(drawingUsage, lng).map(opt => ({ ...opt, revisionRule: lng === "ko" ? "예: R00, R01, R02, R03" : "e.g. R00, R01, R02, R03" })); // 파일 업로드 훅 사용 (진행도 추적) const { fileProgresses, files, removeFile, clearFiles, updateFileProgress, getRootProps, getInputProps, isDragActive, } = useFileUploadWithProgress(); // Revision 유효성 검증 함수 const validateRevision = (value: string): string => { if (!value.trim()) { return t("addDetailDialog.revisionRequired"); } const upperValue = value.toUpperCase().trim(); // A-Z 패턴 (단일 알파벳) if (/^[A-Z]$/.test(upperValue)) { return ""; } // R00-R99 패턴 if (/^R\d{2}$/.test(upperValue)) { return ""; } return t("addDetailDialog.revisionInvalidFormat"); }; // Revision 입력 핸들러 const handleRevisionChange = (value: string) => { const processedValue = value.toUpperCase(); setRevision(processedValue); // 값이 있을 때만 validation if (processedValue.trim()) { const error = validateRevision(processedValue); setRevisionError(error); } else { setRevisionError(""); } }; // 폼 초기화 const resetForm = () => { setDrawingUsage(""); setRegisterKind(""); setRevision(""); setRevisionError(""); setComment(""); clearFiles(); }; // 제출 const handleSubmit = async () => { // 유효성 검사 if (!registerKind) { toast.error(t("addDetailDialog.selectRegisterKindError")); return; } if (drawingUsage !== "CMT") { if (!revision.trim()) { toast.error(t("addDetailDialog.selectRevisionError")); setRevisionError(t("addDetailDialog.revisionRequired")); return; } // Revision 형식 검증 const revisionValidationError = validateRevision(revision); if (revisionValidationError) { toast.error(revisionValidationError); setRevisionError(revisionValidationError); return; } } // Add 모드일 때만 파일 필수 if (mode === "add") { if (!drawing) return; if (!drawingUsage) { toast.error(t("addDetailDialog.selectDrawingUsageError")); return; } if (files.length === 0) { toast.error(t("addDetailDialog.selectFilesError")); return; } } // Edit 모드일 때는 detailDrawing 필수 if (mode === "edit" && !detailDrawing) { toast.error(t("editDetailDialog.editError")); return; } try { setIsSubmitting(true); if (mode === "add" && drawing) { // 파일 업로드 ID 생성 const uploadId = uuidv4(); // 상세도면 추가 const result = await editDetailDwgReceipt({ dwgList: [ { Mode: "ADD", Status: "Submitted", RegisterId: 0, ProjectNo: drawing.ProjectNo, Discipline: drawing.Discipline, DrawingKind: drawing.DrawingKind, DrawingNo: drawing.DrawingNo, DrawingName: drawing.DrawingName, RegisterGroupId: drawing.RegisterGroupId, RegisterSerialNo: 0, // 자동 증가 RegisterKind: registerKind, DrawingRevNo: drawingUsage === "CMT" ? null : revision, Category: "TS", // To SHI (벤더가 SHI에게 제출) Receiver: null, Manager: "", RegisterDesc: comment, UploadId: uploadId, RegCompanyCode: vendorCode, }, ], userId, userNm: userName, vendorCode, email: userEmail, }); if (result > 0) { // 파일 업로드 처리 (상세도면 추가 후) if (files.length > 0) { toast.info(t("addDetailDialog.uploadingFiles", { count: files.length })); // 모든 파일 상태를 uploading으로 변경 files.forEach((_, index) => { updateFileProgress(index, 0, "uploading"); }); const uploadResult = await uploadFilesWithProgress({ uploadId, userId, files, callbacks: { onProgress: (fileIndex, progress) => { updateFileProgress(fileIndex, progress, "uploading"); }, onFileComplete: (fileIndex) => { updateFileProgress(fileIndex, 100, "completed"); }, onFileError: (fileIndex, error) => { updateFileProgress(fileIndex, 0, "error", error); }, }, }); if (uploadResult.success) { toast.success(t("addDetailDialog.addSuccessWithUpload", { count: uploadResult.uploadedCount })); } else { toast.warning(t("addDetailDialog.addSuccessPartialUpload", { error: uploadResult.error })); } } else { toast.success(t("addDetailDialog.addSuccess")); } // API 호출 성공 시 무조건 다이얼로그 닫기 (파일 업로드 성공 여부와 무관) resetForm(); onComplete(); onOpenChange(false); } else { toast.error(t("addDetailDialog.addError")); } } else if (mode === "edit" && detailDrawing) { // 상세도면 수정 const result = await editDetailDwgReceipt({ dwgList: [ { Mode: "MOD", Status: detailDrawing.Status, RegisterId: detailDrawing.RegisterId, ProjectNo: detailDrawing.ProjectNo, Discipline: detailDrawing.Discipline, DrawingKind: detailDrawing.DrawingKind, DrawingNo: detailDrawing.DrawingNo, DrawingName: detailDrawing.DrawingName, RegisterGroupId: detailDrawing.RegisterGroupId, RegisterSerialNo: detailDrawing.RegisterSerialNo, RegisterKind: registerKind, DrawingRevNo: drawingUsage === "CMT" ? null : revision, Category: detailDrawing.Category, Receiver: detailDrawing.Receiver, Manager: detailDrawing.Manager, RegisterDesc: comment, UploadId: detailDrawing.UploadId, RegCompanyCode: detailDrawing.RegCompanyCode || vendorCode, }, ], userId, userNm: userName, vendorCode, email: userEmail, }); if (result > 0) { toast.success(t("editDetailDialog.editSuccess")); resetForm(); onComplete(); onOpenChange(false); } else { toast.error(t("editDetailDialog.editError")); } } } catch (error) { console.error("상세도면 처리 실패:", error); toast.error(mode === "add" ? t("addDetailDialog.addErrorMessage") : t("editDetailDialog.editErrorMessage")); } finally { setIsSubmitting(false); } }; const handleCancel = () => { resetForm(); onOpenChange(false); }; // DrawingUsage가 변경되면 RegisterKind 초기화 const handleDrawingUsageChange = (value: string) => { setDrawingUsage(value); setRegisterKind(""); setRevision(""); setRevisionError(""); }; // 선택된 RegisterKind의 Revision Rule const revisionRule = registerKindOptions.find((opt) => opt.value === registerKind)?.revisionRule || ""; // 버튼 활성화 조건 const isFormValid = mode === "add" ? drawingUsage.trim() !== "" && registerKind.trim() !== "" && (drawingUsage === "CMT" || (revision.trim() !== "" && !revisionError)) && files.length > 0 : registerKind.trim() !== "" && (drawingUsage === "CMT" || (revision.trim() !== "" && !revisionError)); return ( {mode === "edit" ? t("editDetailDialog.title") : t("addDetailDialog.title")}
{/* 도면 정보 표시 */} {mode === "add" && drawing && (
{drawing.DrawingNo}
{drawing.DrawingName}
)} {mode === "edit" && detailDrawing && (
{detailDrawing.DrawingNo} - Rev. {detailDrawing.DrawingRevNo}
{detailDrawing.DrawingName}
)} {/* 도면용도 선택 (Add 모드에서만 표시) */} {mode === "add" && (
)} {/* 등록종류 선택 */}
{revisionRule && (

{t("addDetailDialog.revisionFormatPrefix")}{revisionRule}

)}
{/* Revision 입력 */} {drawingUsage !== "CMT" && (
handleRevisionChange(e.target.value)} placeholder={t("addDetailDialog.revisionPlaceholder")} disabled={!registerKind} className={revisionError ? "border-red-500 focus-visible:ring-red-500" : ""} /> {revisionError && (

{revisionError}

)} {!revisionError && revision && (

{t("addDetailDialog.revisionValid")}

)}
)} {/* Comment 입력 */}