summaryrefslogtreecommitdiff
path: root/lib/dolce/dialogs/add-detail-drawing-dialog.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'lib/dolce/dialogs/add-detail-drawing-dialog.tsx')
-rw-r--r--lib/dolce/dialogs/add-detail-drawing-dialog.tsx129
1 files changed, 82 insertions, 47 deletions
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<string>("");
const [registerKind, setRegisterKind] = useState<string>("");
const [revision, setRevision] = useState<string>("");
- const [files, setFiles] = useState<File[]>([]);
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({
파일을 드래그하거나 클릭하여 선택
</p>
<p className="text-xs text-muted-foreground">
- 여러 파일을 한 번에 업로드할 수 있습니다
+ 여러 파일을 한 번에 업로드할 수 있습니다 (최대 1GB/파일)
</p>
</div>
</div>
@@ -337,25 +348,49 @@ export function AddDetailDrawingDialog({
{/* 선택된 파일 목록 */}
{files.length > 0 && (
<div className="space-y-2 mt-4">
- {files.map((file, index) => (
- <div
- key={index}
- className="flex items-center gap-2 p-2 border rounded-lg"
- >
- <FileIcon className="h-4 w-4 text-muted-foreground" />
- <span className="flex-1 text-sm truncate">{file.name}</span>
- <span className="text-xs text-muted-foreground">
- {(file.size / 1024).toFixed(2)} KB
- </span>
- <Button
- variant="ghost"
- size="icon"
- onClick={() => removeFile(index)}
- >
- <X className="h-4 w-4" />
- </Button>
- </div>
- ))}
+ {isSubmitting ? (
+ // 업로드 중: 진행도 표시
+ <FileUploadProgressList fileProgresses={fileProgresses} />
+ ) : (
+ // 대기 중: 삭제 버튼 표시
+ <>
+ <div className="flex items-center justify-between mb-2">
+ <h4 className="text-sm font-medium">
+ 선택된 파일 ({files.length}개)
+ </h4>
+ <Button
+ variant="ghost"
+ size="sm"
+ onClick={clearFiles}
+ >
+ 전체 제거
+ </Button>
+ </div>
+ <div className="max-h-48 overflow-auto space-y-2">
+ {files.map((file, index) => (
+ <div
+ key={index}
+ className="flex items-center gap-2 p-2 border rounded-lg bg-muted/50"
+ >
+ <FileIcon className="h-4 w-4 text-muted-foreground shrink-0" />
+ <div className="flex-1 min-w-0">
+ <p className="text-sm truncate">{file.name}</p>
+ <p className="text-xs text-muted-foreground">
+ {(file.size / 1024 / 1024).toFixed(2)} MB
+ </p>
+ </div>
+ <Button
+ variant="ghost"
+ size="sm"
+ onClick={() => removeFile(index)}
+ >
+ <X className="h-4 w-4" />
+ </Button>
+ </div>
+ ))}
+ </div>
+ </>
+ )}
</div>
)}
</div>