From 26365ef08588d53b8c5d9c7cfaefb244536e6743 Mon Sep 17 00:00:00 2001 From: joonhoekim <26rote@gmail.com> Date: Mon, 24 Nov 2025 10:41:46 +0900 Subject: (김준회) 돌체 재개발 - 2차: 업로드 개선, 다운로드 오류 수정 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/dolce/dialogs/add-detail-drawing-dialog.tsx | 129 +++++++++++++++--------- 1 file changed, 82 insertions(+), 47 deletions(-) (limited to 'lib/dolce/dialogs/add-detail-drawing-dialog.tsx') diff --git a/lib/dolce/dialogs/add-detail-drawing-dialog.tsx b/lib/dolce/dialogs/add-detail-drawing-dialog.tsx index 290a226b..34d06368 100644 --- a/lib/dolce/dialogs/add-detail-drawing-dialog.tsx +++ b/lib/dolce/dialogs/add-detail-drawing-dialog.tsx @@ -1,7 +1,6 @@ "use client"; -import { useState, useCallback } from "react"; -import { useDropzone } from "react-dropzone"; +import { useState } from "react"; import { Dialog, DialogContent, @@ -22,8 +21,11 @@ import { import { Alert, AlertDescription } from "@/components/ui/alert"; import { Upload, X, FileIcon, Info } from "lucide-react"; import { toast } from "sonner"; -import { UnifiedDwgReceiptItem, editDetailDwgReceipt, uploadFilesToDetailDrawing } from "../actions"; +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"; interface AddDetailDrawingDialogProps { open: boolean; @@ -80,30 +82,26 @@ export function AddDetailDrawingDialog({ const [drawingUsage, setDrawingUsage] = useState(""); const [registerKind, setRegisterKind] = useState(""); const [revision, setRevision] = useState(""); - const [files, setFiles] = useState([]); const [isSubmitting, setIsSubmitting] = useState(false); - // 파일 드롭 핸들러 - const onDrop = useCallback((acceptedFiles: File[]) => { - setFiles((prev) => [...prev, ...acceptedFiles]); - }, []); - - const { getRootProps, getInputProps, isDragActive } = useDropzone({ - onDrop, - multiple: true, - }); - - // 파일 제거 - const removeFile = (index: number) => { - setFiles((prev) => prev.filter((_, i) => i !== index)); - }; + // 파일 업로드 훅 사용 (진행도 추적) + const { + fileProgresses, + files, + removeFile, + clearFiles, + updateFileProgress, + getRootProps, + getInputProps, + isDragActive, + } = useFileUploadWithProgress(); // 폼 초기화 const resetForm = () => { setDrawingUsage(""); setRegisterKind(""); setRevision(""); - setFiles([]); + clearFiles(); }; // 제출 @@ -169,16 +167,27 @@ export function AddDetailDrawingDialog({ if (files.length > 0) { toast.info(`${files.length}개 파일 업로드를 진행합니다...`); - const formData = new FormData(); - formData.append("uploadId", uploadId); - formData.append("userId", userId); - formData.append("fileCount", String(files.length)); - - files.forEach((file, index) => { - formData.append(`file_${index}`, file); + // 모든 파일 상태를 uploading으로 변경 + files.forEach((_, index) => { + updateFileProgress(index, 0, "uploading"); }); - const uploadResult = await uploadFilesToDetailDrawing(formData); + 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}개 파일 업로드 완료`); @@ -189,8 +198,10 @@ export function AddDetailDrawingDialog({ toast.success("상세도면이 추가되었습니다"); } + // API 호출 성공 시 무조건 다이얼로그 닫기 (파일 업로드 성공 여부와 무관) resetForm(); onComplete(); + onOpenChange(false); } else { toast.error("상세도면 추가에 실패했습니다"); } @@ -318,7 +329,7 @@ export function AddDetailDrawingDialog({ 파일을 드래그하거나 클릭하여 선택

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

@@ -337,25 +348,49 @@ export function AddDetailDrawingDialog({ {/* 선택된 파일 목록 */} {files.length > 0 && (
- {files.map((file, index) => ( -
- - {file.name} - - {(file.size / 1024).toFixed(2)} KB - - -
- ))} + {isSubmitting ? ( + // 업로드 중: 진행도 표시 + + ) : ( + // 대기 중: 삭제 버튼 표시 + <> +
+

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

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

{file.name}

+

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

+
+ +
+ ))} +
+ + )}
)} -- cgit v1.2.3