From 9694acd0ec21b3f50a8bd65d3a328befd85cbbee Mon Sep 17 00:00:00 2001
From: joonhoekim <26rote@gmail.com>
Date: Sun, 2 Nov 2025 17:42:18 +0900
Subject: (김준회) dolce: GTT(B4) 일괄업로드 drag&drop 오류 수정
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../ship/bulk-b4-upload-dialog.tsx                 | 72 ++++++++++++++++++----
 1 file changed, 61 insertions(+), 11 deletions(-)

(limited to 'lib/vendor-document-list/ship/bulk-b4-upload-dialog.tsx')

diff --git a/lib/vendor-document-list/ship/bulk-b4-upload-dialog.tsx b/lib/vendor-document-list/ship/bulk-b4-upload-dialog.tsx
index db0fa08e..52252e14 100644
--- a/lib/vendor-document-list/ship/bulk-b4-upload-dialog.tsx
+++ b/lib/vendor-document-list/ship/bulk-b4-upload-dialog.tsx
@@ -32,14 +32,11 @@ import {
   SelectValue,
 } from "@/components/ui/select"
 import { ScrollArea } from "@/components/ui/scroll-area"
-import { Separator } from "@/components/ui/separator"
 import { Badge } from "@/components/ui/badge"
 import {
   Upload,
   X,
   Loader2,
-  FileSpreadsheet,
-  Files,
   CheckCircle2,
   AlertCircle,
   AlertTriangle,
@@ -76,7 +73,7 @@ function parseFileName(fileName: string): { docNumber: string | null; revision:
     /\b([A-Za-z]{2,3})\s+([A-Za-z]{2,3})\s+([A-Za-z0-9]{2,4})\b/,
   ]
   
-  let docNumber = null
+  let docNumber: string | null = null
   for (const pattern of docNumberPatterns) {
     const match = normalizedName.match(pattern) || cleanedName.match(pattern)
     if (match) {
@@ -115,6 +112,7 @@ export function BulkB4UploadDialog({
 }: BulkB4UploadDialogProps) {
   const [isUploading, setIsUploading] = React.useState(false)
   const [parsedFiles, setParsedFiles] = React.useState<ParsedFile[]>([])
+  const [isDragging, setIsDragging] = React.useState(false)
   const router = useRouter()
   
   // 프로젝트 ID 추출
@@ -158,6 +156,40 @@ export function BulkB4UploadDialog({
     form.setValue("files", newParsedFiles.map(pf => pf.file))
   }
   
+  // Drag & Drop 핸들러
+  const handleDragEnter = (e: React.DragEvent) => {
+    e.preventDefault()
+    e.stopPropagation()
+    setIsDragging(true)
+  }
+  
+  const handleDragLeave = (e: React.DragEvent) => {
+    e.preventDefault()
+    e.stopPropagation()
+    // 자식 요소로 이동할 때도 leave가 발생하므로 실제로 영역을 벗어날 때만 처리
+    if (e.currentTarget === e.target) {
+      setIsDragging(false)
+    }
+  }
+  
+  const handleDragOver = (e: React.DragEvent) => {
+    e.preventDefault()
+    e.stopPropagation()
+    // 드롭 가능하도록 설정
+    e.dataTransfer.dropEffect = 'copy'
+  }
+  
+  const handleDrop = (e: React.DragEvent) => {
+    e.preventDefault()
+    e.stopPropagation()
+    setIsDragging(false)
+    
+    const droppedFiles = Array.from(e.dataTransfer.files)
+    if (droppedFiles.length > 0) {
+      handleFilesChange(droppedFiles)
+    }
+  }
+  
   // 업로드 처리
   async function onSubmit(values: z.infer<typeof formSchema>) {
     setIsUploading(true)
@@ -225,7 +257,7 @@ export function BulkB4UploadDialog({
             : pf
         ))
       }
-    } catch (error) {
+    } catch {
       toast.error("업로드 중 오류가 발생했습니다")
       setParsedFiles(prev => prev.map(pf => 
         pf.status === 'uploading' 
@@ -242,6 +274,7 @@ export function BulkB4UploadDialog({
     if (!open) {
       form.reset()
       setParsedFiles([])
+      setIsDragging(false)
     }
   }, [open, form])
   
@@ -255,7 +288,7 @@ export function BulkB4UploadDialog({
           <DialogTitle>B4 Document Bulk Upload</DialogTitle>
           <DialogDescription>
             Document numbers and revisions will be automatically extracted from file names.
-            Example: "agadfg de na oc R01.pdf" → Document Number: DE-NA-OC, Revision: R01
+            Example: &quot;agadfg de na oc R01.pdf&quot; → Document Number: DE-NA-OC, Revision: R01
           </DialogDescription>
         </DialogHeader>
         
@@ -288,7 +321,17 @@ export function BulkB4UploadDialog({
             
             <div className="space-y-2">
               <FormLabel>Select Files</FormLabel>
-              <div className="border-2 border-dashed rounded-lg p-6">
+              <div 
+                className={`border-2 border-dashed rounded-lg p-6 transition-all duration-200 ${
+                  isDragging 
+                    ? 'border-primary bg-primary/5 scale-[1.02]' 
+                    : 'border-muted-foreground/30 hover:border-muted-foreground/50'
+                }`}
+                onDragEnter={handleDragEnter}
+                onDragLeave={handleDragLeave}
+                onDragOver={handleDragOver}
+                onDrop={handleDrop}
+              >
                 <input
                   type="file"
                   multiple
@@ -296,14 +339,21 @@ export function BulkB4UploadDialog({
                   onChange={(e) => handleFilesChange(Array.from(e.target.files || []))}
                   className="hidden"
                   id="file-upload"
+                  disabled={isUploading}
                 />
                 <label
                   htmlFor="file-upload"
-                  className="flex flex-col items-center justify-center cursor-pointer"
+                  className={`flex flex-col items-center justify-center ${
+                    isUploading ? 'cursor-not-allowed opacity-50' : 'cursor-pointer'
+                  }`}
                 >
-                  <Upload className="h-10 w-10 text-muted-foreground mb-2" />
-                  <p className="text-sm text-muted-foreground">
-                    Click or drag files to upload
+                  <Upload className={`h-10 w-10 mb-2 transition-colors ${
+                    isDragging ? 'text-primary' : 'text-muted-foreground'
+                  }`} />
+                  <p className={`text-sm transition-colors ${
+                    isDragging ? 'text-primary font-medium' : 'text-muted-foreground'
+                  }`}>
+                    {isDragging ? '파일을 여기에 놓으세요' : '클릭하거나 파일을 드래그하여 업로드'}
                   </p>
                   <p className="text-xs text-muted-foreground mt-1">
                     PDF, DOC, DOCX, XLS, XLSX, DWG, DXF
-- 
cgit v1.2.3

