diff options
Diffstat (limited to 'lib/dolce/dialogs/b4-bulk-upload-dialog.tsx')
| -rw-r--r-- | lib/dolce/dialogs/b4-bulk-upload-dialog.tsx | 108 |
1 files changed, 81 insertions, 27 deletions
diff --git a/lib/dolce/dialogs/b4-bulk-upload-dialog.tsx b/lib/dolce/dialogs/b4-bulk-upload-dialog.tsx index 21647e63..b7b25fca 100644 --- a/lib/dolce/dialogs/b4-bulk-upload-dialog.tsx +++ b/lib/dolce/dialogs/b4-bulk-upload-dialog.tsx @@ -36,6 +36,9 @@ import { type B4MappingSaveItem, } from "../actions"; import { v4 as uuidv4 } from "uuid"; +import { uploadFilesWithProgress } from "../utils/upload-with-progress"; +import { FileUploadProgressList } from "../components/file-upload-progress-list"; +import type { FileUploadProgress } from "../hooks/use-file-upload-with-progress"; interface B4BulkUploadDialogProps { open: boolean; @@ -73,6 +76,7 @@ export function B4BulkUploadDialog({ const [isDragging, setIsDragging] = useState(false); const [uploadProgress, setUploadProgress] = useState(0); const [uploadResult, setUploadResult] = useState<B4BulkUploadResult | null>(null); + const [fileProgresses, setFileProgresses] = useState<FileUploadProgress[]>([]); // B4 GTT 옵션 (코드 번역 유틸리티 사용) const drawingUsageOptions = [ @@ -98,6 +102,7 @@ export function B4BulkUploadDialog({ setIsDragging(false); setUploadProgress(0); setUploadResult(null); + setFileProgresses([]); } }, [open]); @@ -275,6 +280,14 @@ export function B4BulkUploadDialog({ try { console.log(`[B4 일괄 업로드] 시작: ${validFiles.length}개 파일`); + // 0단계: 모든 파일에 대한 진행도 상태 초기화 + const initialProgresses: FileUploadProgress[] = validFiles.map((fileResult) => ({ + file: fileResult.file, + progress: 0, + status: "pending" as const, + })); + setFileProgresses(initialProgresses); + // 파일을 DrawingNo + RevNo로 그룹화 const uploadGroups = new Map< string, @@ -284,10 +297,11 @@ export function B4BulkUploadDialog({ revNo: string; fileName: string; registerGroupId: number; + fileIndex: number; // 전체 배열에서의 인덱스 }> >(); - validFiles.forEach((fileResult) => { + validFiles.forEach((fileResult, index) => { const groupKey = `${fileResult.parsed!.drawingNo}_${fileResult.parsed!.revNo}`; if (!uploadGroups.has(groupKey)) { uploadGroups.set(groupKey, []); @@ -298,6 +312,7 @@ export function B4BulkUploadDialog({ revNo: fileResult.parsed!.revNo, fileName: fileResult.file.name, registerGroupId: fileResult.registerGroupId || 0, + fileIndex: index, }); }); @@ -317,27 +332,63 @@ export function B4BulkUploadDialog({ // 1. UploadId 생성 const uploadId = uuidv4(); - // 2. 파일 업로드 (공통 API 사용) - const formData = new FormData(); - formData.append("uploadId", uploadId); - formData.append("userId", userId); - formData.append("fileCount", String(files.length)); - - files.forEach((fileInfo, index) => { - formData.append(`file_${index}`, fileInfo.file); - }); - - const uploadResponse = await fetch("/api/dolce/upload-files", { - method: "POST", - body: formData, + // 그룹 내 모든 파일 상태를 uploading으로 변경 + setFileProgresses((prev) => + prev.map((fp, index) => + files.some((f) => f.fileIndex === index) + ? { ...fp, status: "uploading" as const } + : fp + ) + ); + + // 2. 파일 업로드 (uploadFilesWithProgress 사용) + const uploadResult = await uploadFilesWithProgress({ + uploadId, + userId, + files: files.map((f) => f.file), + callbacks: { + onProgress: (fileIndexInGroup, progress) => { + // 그룹 내 파일 인덱스를 전체 인덱스로 변환 + const globalFileIndex = files[fileIndexInGroup].fileIndex; + + // 개별 파일 진행도 업데이트 + setFileProgresses((prev) => + prev.map((fp, index) => + index === globalFileIndex + ? { ...fp, progress, status: "uploading" as const } + : fp + ) + ); + + // 전체 진행도 계산 + const groupProgress = (completedGroups / uploadGroups.size) * 100; + const currentGroupProgress = (progress / 100) * (100 / uploadGroups.size); + setUploadProgress(Math.round(groupProgress + currentGroupProgress)); + }, + onFileComplete: (fileIndexInGroup) => { + const globalFileIndex = files[fileIndexInGroup].fileIndex; + setFileProgresses((prev) => + prev.map((fp, index) => + index === globalFileIndex + ? { ...fp, progress: 100, status: "completed" as const } + : fp + ) + ); + }, + onFileError: (fileIndexInGroup, error) => { + const globalFileIndex = files[fileIndexInGroup].fileIndex; + console.error(`[B4 업로드] 파일 ${globalFileIndex} 업로드 실패:`, error); + setFileProgresses((prev) => + prev.map((fp, index) => + index === globalFileIndex + ? { ...fp, status: "error" as const, error } + : fp + ) + ); + }, + }, }); - if (!uploadResponse.ok) { - throw new Error(`파일 업로드 실패: ${uploadResponse.status}`); - } - - const uploadResult = await uploadResponse.json(); - if (!uploadResult.success) { throw new Error(uploadResult.error || "파일 업로드 실패"); } @@ -599,7 +650,7 @@ export function B4BulkUploadDialog({ {/* 4단계: 업로드 진행 중 */} {currentStep === "uploading" && ( - <div className="space-y-6 py-8"> + <div className="space-y-6 py-4"> <div className="flex flex-col items-center"> <Loader2 className="h-12 w-12 animate-spin text-primary mb-4" /> <h3 className="text-lg font-semibold mb-2">{t("bulkUpload.uploading")}</h3> @@ -607,19 +658,22 @@ export function B4BulkUploadDialog({ {t("bulkUpload.uploadingWait")} </p> </div> + + {/* 전체 진행도 */} <div className="space-y-2"> <div className="flex justify-between text-sm"> <span>{t("bulkUpload.uploadProgress")}</span> <span>{uploadProgress}%</span> </div> <Progress value={uploadProgress} className="h-2" /> - {/* 90% 이상일 때 추가 안내 메시지 */} - {uploadProgress >= 90 && uploadProgress < 100 && ( - <p className="text-xs text-muted-foreground text-center pt-2"> - {t("bulkUpload.uploadingToServer")} - </p> - )} </div> + + {/* 개별 파일 진행도 리스트 */} + {fileProgresses.length > 0 && ( + <div className="border rounded-lg p-4 max-h-96 overflow-y-auto"> + <FileUploadProgressList fileProgresses={fileProgresses} /> + </div> + )} </div> )} |
