// lib/vendor-document-list/plant/upload/components/single-upload-dialog.tsx "use client" import * as React from "react" import { useState } from "react" import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, } from "@/components/ui/dialog" import { Button } from "@/components/ui/button" import { Input } from "@/components/ui/input" import { Label } from "@/components/ui/label" import { Textarea } from "@/components/ui/textarea" import { Badge } from "@/components/ui/badge" import { Alert, AlertDescription } from "@/components/ui/alert" import { FileList, FileListAction, FileListIcon, FileListInfo, FileListItem, FileListName, FileListSize, } from "@/components/ui/file-list" import { Upload, X, FileIcon, Loader2, AlertCircle } from "lucide-react" import { toast } from "sonner" import { StageSubmissionView } from "@/db/schema" interface SingleUploadDialogProps { open: boolean onOpenChange: (open: boolean) => void submission: StageSubmissionView onUploadComplete?: () => void } export function SingleUploadDialog({ open, onOpenChange, submission, onUploadComplete }: SingleUploadDialogProps) { const [files, setFiles] = useState([]) const [description, setDescription] = useState("") const [isUploading, setIsUploading] = useState(false) const fileInputRef = React.useRef(null) // 파일 선택 const handleFileChange = (e: React.ChangeEvent) => { const fileList = e.target.files if (fileList) { setFiles(Array.from(fileList)) } } // 파일 제거 const removeFile = (index: number) => { setFiles(prev => prev.filter((_, i) => i !== index)) } // 업로드 처리 const handleUpload = async () => { if (files.length === 0) { toast.error("Please select files to upload") return } setIsUploading(true) try { const formData = new FormData() files.forEach((file) => { formData.append("files", file) }) formData.append("documentId", submission.documentId.toString()) formData.append("stageId", submission.stageId!.toString()) formData.append("description", description) // 현재 리비전 + 1 const nextRevision = (submission.latestRevisionNumber || 0) + 1 formData.append("revision", nextRevision.toString()) const response = await fetch("/api/stage-submissions/upload", { method: "POST", body: formData, }) if (!response.ok) { throw new Error("Upload failed") } const result = await response.json() toast.success(`Successfully uploaded ${files.length} file(s)`) // 초기화 및 닫기 setFiles([]) setDescription("") onOpenChange(false) onUploadComplete?.() } catch (error) { console.error("Upload error:", error) toast.error("Failed to upload files") } finally { setIsUploading(false) } } const formatFileSize = (bytes: number) => { if (bytes === 0) return '0 Bytes' const k = 1024 const sizes = ['Bytes', 'KB', 'MB', 'GB'] const i = Math.floor(Math.log(bytes) / Math.log(k)) return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i] } const totalSize = files.reduce((acc, file) => acc + file.size, 0) return ( Upload Documents Upload documents for this stage submission {/* Document Info */}
Document: {submission.docNumber} {submission.vendorDocNumber && ( ({submission.vendorDocNumber}) )}
Stage: {submission.stageName}
Current Revision: Rev. {submission.latestRevisionNumber || 0} Next: Rev. {(submission.latestRevisionNumber || 0) + 1}
{/* File Upload Area */}
fileInputRef.current?.click()} >

Click to browse files

You can select multiple files

{/* File List */} {files.length > 0 && ( <> {files.map((file, index) => ( {file.name} {file.size} ))}
{files.length} file(s) selected Total: {formatFileSize(totalSize)}
)} {/* Description */}