"use client"; import { useState } 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 { Upload, X, FileIcon, Info } from "lucide-react"; import { toast } from "sonner"; import { UnifiedDwgReceiptItem, 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 AddDetailDrawingDialogProps { open: boolean; onOpenChange: (open: boolean) => void; drawing: UnifiedDwgReceiptItem | null; vendorCode: string; userId: string; userName: string; userEmail: string; onComplete: () => void; drawingKind: "B3" | "B4"; lng?: string; // i18n support } export function AddDetailDrawingDialog({ open, onOpenChange, drawing, vendorCode, userId, userName, userEmail, onComplete, drawingKind, lng = "ko", }: AddDetailDrawingDialogProps) { const [drawingUsage, setDrawingUsage] = useState(""); const [registerKind, setRegisterKind] = useState(""); const [revision, setRevision] = useState(""); const [revisionError, setRevisionError] = useState(""); const [isSubmitting, setIsSubmitting] = useState(false); // 옵션 생성 (다국어 지원) 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 "Revision을 입력하세요"; } const upperValue = value.toUpperCase().trim(); // A-Z 패턴 (단일 알파벳) if (/^[A-Z]$/.test(upperValue)) { return ""; } // R00-R99 패턴 if (/^R\d{2}$/.test(upperValue)) { return ""; } return "올바른 형식이 아닙니다 (A-Z 또는 R00-R99)"; }; // 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(""); clearFiles(); }; // 제출 const handleSubmit = async () => { if (!drawing) return; // 유효성 검사 if (!drawingUsage) { toast.error("도면용도를 선택하세요"); return; } if (!registerKind) { toast.error("등록종류를 선택하세요"); return; } if (!revision.trim()) { toast.error("Revision을 입력하세요"); setRevisionError("Revision을 입력하세요"); return; } // Revision 형식 검증 const revisionValidationError = validateRevision(revision); if (revisionValidationError) { toast.error(revisionValidationError); setRevisionError(revisionValidationError); return; } if (files.length === 0) { toast.error("최소 1개 이상의 파일을 첨부해야 합니다"); return; } try { setIsSubmitting(true); // 파일 업로드 ID 생성 const uploadId = uuidv4(); // 상세도면 추가 const result = await editDetailDwgReceipt({ dwgList: [ { Mode: "ADD", Status: "Draft", 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: revision, Category: "TS", // To SHI (벤더가 SHI에게 제출) Receiver: null, Manager: "", RegisterDesc: "", UploadId: uploadId, RegCompanyCode: vendorCode, }, ], userId, userNm: userName, vendorCode, email: userEmail, }); if (result > 0) { // 파일 업로드 처리 (상세도면 추가 후) if (files.length > 0) { toast.info(`${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(`상세도면 추가 및 ${uploadResult.uploadedCount}개 파일 업로드 완료`); } else { toast.warning(`상세도면은 추가되었으나 파일 업로드 실패: ${uploadResult.error}`); } } else { toast.success("상세도면이 추가되었습니다"); } // API 호출 성공 시 무조건 다이얼로그 닫기 (파일 업로드 성공 여부와 무관) resetForm(); onComplete(); onOpenChange(false); } else { toast.error("상세도면 추가에 실패했습니다"); } } catch (error) { console.error("상세도면 추가 실패:", error); toast.error("상세도면 추가 중 오류가 발생했습니다"); } 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 = drawingUsage.trim() !== "" && registerKind.trim() !== "" && revision.trim() !== "" && !revisionError && files.length > 0; return ( 상세도면 추가
{/* 도면 정보 표시 */} {drawing && (
{drawing.DrawingNo}
{drawing.DrawingName}
)} {/* 도면용도 선택 */}
{/* 등록종류 선택 */}
{revisionRule && (

Revision 입력 형식: {revisionRule}

)}
{/* Revision 입력 */}
handleRevisionChange(e.target.value)} placeholder="예: A, B, R00, R01" disabled={!registerKind} className={revisionError ? "border-red-500 focus-visible:ring-red-500" : ""} /> {revisionError && (

{revisionError}

)} {!revisionError && revision && (

✓ 올바른 형식입니다

)}
{/* 파일 업로드 */}
0 ? "py-4" : ""} `} > {files.length === 0 ? (

파일을 드래그하거나 클릭하여 선택

여러 파일을 한 번에 업로드할 수 있습니다 (최대 1GB/파일)

) : (

{files.length}개 파일 선택됨

추가로 파일을 드래그하거나 클릭하여 더 추가할 수 있습니다

)}
{/* 선택된 파일 목록 */} {files.length > 0 && (
{isSubmitting ? ( // 업로드 중: 진행도 표시 ) : ( // 대기 중: 삭제 버튼 표시 <>

선택된 파일 ({files.length}개)

{files.map((file, index) => (

{file.name}

{(file.size / 1024 / 1024).toFixed(2)} MB

))}
)}
)}
); }