"use client" import { useState, useRef } from "react" import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card" import { Button } from "@/components/ui/button" import { Badge } from "@/components/ui/badge" import { Alert, AlertDescription } from "@/components/ui/alert" import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from "@/components/ui/table" import { Upload, FileText, File, Trash2, Download, AlertCircle, Paperclip, FileCheck, Calculator, Wrench } from "lucide-react" import { formatBytes } from "@/lib/utils" import { cn } from "@/lib/utils" interface FileWithType extends File { attachmentType?: "구매" | "설계" description?: string } interface AttachmentsUploadProps { attachments: FileWithType[] onAttachmentsChange: (files: FileWithType[]) => void existingAttachments?: any[] } const acceptedFileTypes = { documents: ".pdf,.doc,.docx,.xls,.xlsx,.ppt,.pptx", images: ".jpg,.jpeg,.png,.gif,.bmp", compressed: ".zip,.rar,.7z", all: ".pdf,.doc,.docx,.xls,.xlsx,.ppt,.pptx,.jpg,.jpeg,.png,.gif,.bmp,.zip,.rar,.7z" } export default function AttachmentsUpload({ attachments, onAttachmentsChange, existingAttachments = [] }: AttachmentsUploadProps) { const purchaseInputRef = useRef(null) const designInputRef = useRef(null) const [purchaseDragActive, setPurchaseDragActive] = useState(false) const [designDragActive, setDesignDragActive] = useState(false) const [uploadErrors, setUploadErrors] = useState([]) // 파일 유효성 검사 const validateFile = (file: File): string | null => { const maxSize = 1024 * 1024 * 1024 // 10MB const allowedExtensions = acceptedFileTypes.all.split(',') const fileExtension = `.${file.name.split('.').pop()?.toLowerCase()}` if (file.size > maxSize) { return `${file.name}: 파일 크기가 1GB를 초과합니다` } if (!allowedExtensions.includes(fileExtension)) { return `${file.name}: 허용되지 않은 파일 형식입니다` } return null } // 파일 추가 const handleFileAdd = (files: FileList | null, type: "구매" | "설계") => { if (!files) return const newFiles: FileWithType[] = [] const errors: string[] = [] Array.from(files).forEach(file => { const error = validateFile(file) if (error) { errors.push(error) } else { const fileWithType = Object.assign(file, { attachmentType: type, description: "" }) newFiles.push(fileWithType) } }) if (errors.length > 0) { setUploadErrors(errors) setTimeout(() => setUploadErrors([]), 5000) } if (newFiles.length > 0) { onAttachmentsChange([...attachments, ...newFiles]) } } // 구매 드래그 앤 드롭 핸들러 const handlePurchaseDrag = (e: React.DragEvent) => { e.preventDefault() e.stopPropagation() if (e.type === "dragenter" || e.type === "dragover") { setPurchaseDragActive(true) } else if (e.type === "dragleave") { setPurchaseDragActive(false) } } const handlePurchaseDrop = (e: React.DragEvent) => { e.preventDefault() e.stopPropagation() setPurchaseDragActive(false) if (e.dataTransfer.files && e.dataTransfer.files[0]) { handleFileAdd(e.dataTransfer.files, "구매") } } // 설계 드래그 앤 드롭 핸들러 const handleDesignDrag = (e: React.DragEvent) => { e.preventDefault() e.stopPropagation() if (e.type === "dragenter" || e.type === "dragover") { setDesignDragActive(true) } else if (e.type === "dragleave") { setDesignDragActive(false) } } const handleDesignDrop = (e: React.DragEvent) => { e.preventDefault() e.stopPropagation() setDesignDragActive(false) if (e.dataTransfer.files && e.dataTransfer.files[0]) { handleFileAdd(e.dataTransfer.files, "설계") } } // 파일 삭제 const handleFileRemove = (index: number) => { const newFiles = attachments.filter((_, i) => i !== index) onAttachmentsChange(newFiles) } // 파일 타입 변경 const handleTypeChange = (index: number, newType: "구매" | "설계") => { const newFiles = [...attachments] newFiles[index].attachmentType = newType onAttachmentsChange(newFiles) } // 파일 아이콘 가져오기 const getFileIcon = (fileName: string) => { const extension = fileName.split('.').pop()?.toLowerCase() const imageExtensions = ['jpg', 'jpeg', 'png', 'gif', 'bmp'] if (imageExtensions.includes(extension || '')) { return } return } // 구매/설계 문서 개수 계산 const purchaseCount = attachments.filter(f => f.attachmentType === "구매").length + existingAttachments.filter(f => f.attachmentType === "구매").length const designCount = attachments.filter(f => f.attachmentType === "설계").length + existingAttachments.filter(f => f.attachmentType === "설계").length return (
{/* 필수 파일 안내 */} 문서 분류: 구매 문서(견적서, 상업조건 등)와 설계 문서(기술문서, 성적서, 인증서 등)를 구분하여 업로드하세요.
허용 파일: PDF, Word, Excel, PowerPoint, 이미지 파일, 압축 파일(ZIP, RAR, 7Z) (최대 1GB)
{/* 업로드 오류 표시 */} {uploadErrors.length > 0 && (
    {uploadErrors.map((error, index) => (
  • {error}
  • ))}
)} {/* 두 개의 드래그존 */}
{/* 구매 문서 업로드 영역 */} 구매 문서 견적서, 금액, 상업조건 관련 문서

구매 문서를 드래그하여 업로드

handleFileAdd(e.target.files, "구매")} className="hidden" /> {purchaseCount > 0 && (
{purchaseCount}개 업로드됨
)}
{/* 설계 문서 업로드 영역 */} 설계 문서 기술문서, 성적서, 인증서, 도면 등

설계 문서를 드래그하여 업로드

handleFileAdd(e.target.files, "설계")} className="hidden" /> {designCount > 0 && (
{designCount}개 업로드됨
)} {/*

최대 1GB, 여러 파일 선택 가능

*/}
{/* 첨부파일 목록 */} {(attachments.length > 0 || existingAttachments.length > 0) && (
첨부파일 목록
구매 {purchaseCount} 설계 {designCount} 총 {attachments.length + existingAttachments.length}개
유형 파일명 크기 문서 구분 상태 작업 {/* 기존 첨부파일 */} {existingAttachments.map((file, index) => ( {getFileIcon(file.originalFileName)}

{file.originalFileName}

{file.description && (

{file.description}

)}
{formatBytes(file.fileSize || 0)} {file.attachmentType === "구매" ? : } {file.attachmentType} 기존
))} {/* 새로 추가된 파일 */} {attachments.map((file, index) => ( {getFileIcon(file.name)}

{file.name}

{formatBytes(file.size)}
신규
))}
)}
) }