From 684cd304bf0ab1c2b0b72668fb4efd9f9892339d Mon Sep 17 00:00:00 2001
From: joonhoekim <26rote@gmail.com>
Date: Tue, 4 Nov 2025 10:15:32 +0900
Subject: (김준회) dolce: B4 일괄업로드 UX 개선 (추가 업로드시 파일리스트 상태
 유지, 프로젝트 우선 선택 강제, 프로젝트 변경시 이전 데이터 삭제 경고)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../ship/bulk-b4-upload-dialog.tsx                 | 153 ++++++++++++++-------
 1 file changed, 104 insertions(+), 49 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 44f9c801..43788c8a 100644
--- a/lib/vendor-document-list/ship/bulk-b4-upload-dialog.tsx
+++ b/lib/vendor-document-list/ship/bulk-b4-upload-dialog.tsx
@@ -15,6 +15,16 @@ import {
   DialogHeader,
   DialogTitle,
 } from "@/components/ui/dialog"
+import {
+  AlertDialog,
+  AlertDialogAction,
+  AlertDialogCancel,
+  AlertDialogContent,
+  AlertDialogDescription,
+  AlertDialogFooter,
+  AlertDialogHeader,
+  AlertDialogTitle,
+} from "@/components/ui/alert-dialog"
 import { Button } from "@/components/ui/button"
 import {
   Form,
@@ -107,6 +117,8 @@ export function BulkB4UploadDialog({
   const [parsedFiles, setParsedFiles] = React.useState<ParsedFile[]>([])
   const [isDragging, setIsDragging] = React.useState(false)
   const [currentProjectId, setCurrentProjectId] = React.useState<string>("")
+  const [showProjectChangeWarning, setShowProjectChangeWarning] = React.useState(false)
+  const [pendingProjectId, setPendingProjectId] = React.useState<string>("")
   const router = useRouter()
   
   // 프로젝트 ID 추출
@@ -126,47 +138,57 @@ export function BulkB4UploadDialog({
     },
   })
   
+  // 프로젝트 변경 핸들러
+  const handleProjectChange = (newProjectId: string) => {
+    // 기존 파일 목록이 있고, 다른 프로젝트로 변경하는 경우 경고 표시
+    if (parsedFiles.length > 0 && currentProjectId && currentProjectId !== newProjectId) {
+      setPendingProjectId(newProjectId)
+      setShowProjectChangeWarning(true)
+    } else {
+      // 파일 목록이 비어있거나 첫 선택인 경우 바로 변경
+      setCurrentProjectId(newProjectId)
+      form.setValue("projectId", newProjectId)
+    }
+  }
+  
+  // 프로젝트 변경 확인 처리
+  const confirmProjectChange = () => {
+    // 파일 목록 초기화하고 프로젝트 변경
+    setParsedFiles([])
+    form.setValue("files", [])
+    setCurrentProjectId(pendingProjectId)
+    form.setValue("projectId", pendingProjectId)
+    setShowProjectChangeWarning(false)
+    setPendingProjectId("")
+  }
+  
+  // 프로젝트 변경 취소 처리
+  const cancelProjectChange = () => {
+    setShowProjectChangeWarning(false)
+    setPendingProjectId("")
+  }
+  
   // 파일 선택 시 파싱
   const handleFilesChange = (files: File[]) => {
-    const currentProject = form.watch("projectId")
-
-    // 프로젝트가 변경되었거나 처음 선택하는 경우
-    if (!currentProject || currentProject !== currentProjectId) {
-      setCurrentProjectId(currentProject)
-      const parsed = files.map(file => {
-        const { docNumber, revision } = parseFileName(file.name)
-        return {
-          file,
-          docNumber,
-          revision,
-          status: docNumber ? 'pending' as const : 'ignored' as const,
-          message: !docNumber ? 'docNumber를 찾을 수 없음' : undefined
-        }
-      })
-      setParsedFiles(parsed)
-      form.setValue("files", files)
-    } else {
-      // 같은 프로젝트에서 파일 추가하는 경우
-      const parsed = files.map(file => {
-        const { docNumber, revision } = parseFileName(file.name)
-        return {
-          file,
-          docNumber,
-          revision,
-          status: docNumber ? 'pending' as const : 'ignored' as const,
-          message: !docNumber ? 'docNumber를 찾을 수 없음' : undefined
-        }
-      })
+    const parsed = files.map(file => {
+      const { docNumber, revision } = parseFileName(file.name)
+      return {
+        file,
+        docNumber,
+        revision,
+        status: docNumber ? 'pending' as const : 'ignored' as const,
+        message: !docNumber ? 'docNumber를 찾을 수 없음' : undefined
+      }
+    })
 
-      // 기존 파일들과 새 파일들을 합침 (중복 파일명은 새 것으로 대체)
-      const existingFileNames = new Set(parsedFiles.map(pf => pf.file.name))
-      const newFiles = parsed.filter(pf => !existingFileNames.has(pf.file.name))
-      const combinedParsed = [...parsedFiles, ...newFiles]
-      const combinedFiles = [...parsedFiles.map(pf => pf.file), ...newFiles.map(pf => pf.file)]
+    // 기존 파일들과 새 파일들을 합침 (중복 파일명은 제외)
+    const existingFileNames = new Set(parsedFiles.map(pf => pf.file.name))
+    const newFiles = parsed.filter(pf => !existingFileNames.has(pf.file.name))
+    const combinedParsed = [...parsedFiles, ...newFiles]
+    const combinedFiles = [...parsedFiles.map(pf => pf.file), ...newFiles.map(pf => pf.file)]
 
-      setParsedFiles(combinedParsed)
-      form.setValue("files", combinedFiles)
-    }
+    setParsedFiles(combinedParsed)
+    form.setValue("files", combinedFiles)
   }
   
   // 파일 제거
@@ -296,6 +318,8 @@ export function BulkB4UploadDialog({
       setParsedFiles([])
       setIsDragging(false)
       setCurrentProjectId("")
+      setShowProjectChangeWarning(false)
+      setPendingProjectId("")
     }
   }, [open, form])
   
@@ -303,7 +327,26 @@ export function BulkB4UploadDialog({
   const ignoredFileCount = parsedFiles.filter(pf => !pf.docNumber).length
   
   return (
-    <Dialog open={open} onOpenChange={onOpenChange}>
+    <>
+      {/* 프로젝트 변경 경고 다이얼로그 */}
+      <AlertDialog open={showProjectChangeWarning} onOpenChange={setShowProjectChangeWarning}>
+        <AlertDialogContent>
+          <AlertDialogHeader>
+            <AlertDialogTitle>프로젝트 변경 확인</AlertDialogTitle>
+            <AlertDialogDescription>
+              프로젝트를 변경하면 현재 선택된 {parsedFiles.length}개의 파일이 모두 제거됩니다.
+              계속하시겠습니까?
+            </AlertDialogDescription>
+          </AlertDialogHeader>
+          <AlertDialogFooter>
+            <AlertDialogCancel onClick={cancelProjectChange}>취소</AlertDialogCancel>
+            <AlertDialogAction onClick={confirmProjectChange}>확인</AlertDialogAction>
+          </AlertDialogFooter>
+        </AlertDialogContent>
+      </AlertDialog>
+
+      {/* 메인 업로드 다이얼로그 */}
+      <Dialog open={open} onOpenChange={onOpenChange}>
       <DialogContent className="max-w-3xl">
         <DialogHeader>
           <DialogTitle>B4 Document Bulk Upload</DialogTitle>
@@ -324,7 +367,11 @@ export function BulkB4UploadDialog({
               render={({ field }) => (
                 <FormItem>
                   <FormLabel>Select Project *</FormLabel>
-                  <Select onValueChange={field.onChange} value={field.value}>
+                  <Select 
+                    onValueChange={handleProjectChange} 
+                    value={field.value}
+                    disabled={isUploading}
+                  >
                     <FormControl>
                       <SelectTrigger>
                         <SelectValue placeholder="Please select a project" />
@@ -347,14 +394,16 @@ export function BulkB4UploadDialog({
               <FormLabel>Select Files</FormLabel>
               <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'
+                  !currentProjectId || isUploading
+                    ? 'border-muted-foreground/20 opacity-50 cursor-not-allowed'
+                    : 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}
+                onDragEnter={!currentProjectId || isUploading ? undefined : handleDragEnter}
+                onDragLeave={!currentProjectId || isUploading ? undefined : handleDragLeave}
+                onDragOver={!currentProjectId || isUploading ? undefined : handleDragOver}
+                onDrop={!currentProjectId || isUploading ? undefined : handleDrop}
               >
                 <input
                   type="file"
@@ -363,12 +412,12 @@ export function BulkB4UploadDialog({
                   onChange={(e) => handleFilesChange(Array.from(e.target.files || []))}
                   className="hidden"
                   id="file-upload"
-                  disabled={isUploading}
+                  disabled={!currentProjectId || isUploading}
                 />
                 <label
                   htmlFor="file-upload"
                   className={`flex flex-col items-center justify-center ${
-                    isUploading ? 'cursor-not-allowed opacity-50' : 'cursor-pointer'
+                    !currentProjectId || isUploading ? 'cursor-not-allowed' : 'cursor-pointer'
                   }`}
                 >
                   <Upload className={`h-10 w-10 mb-2 transition-colors ${
@@ -377,7 +426,12 @@ export function BulkB4UploadDialog({
                   <p className={`text-sm transition-colors ${
                     isDragging ? 'text-primary font-medium' : 'text-muted-foreground'
                   }`}>
-                    {isDragging ? '파일을 여기에 놓으세요' : '클릭하거나 파일을 드래그하여 업로드'}
+                    {!currentProjectId 
+                      ? '먼저 프로젝트를 선택해주세요' 
+                      : isDragging 
+                        ? '파일을 여기에 놓으세요' 
+                        : '클릭하거나 파일을 드래그하여 업로드'
+                    }
                   </p>
                   <p className="text-xs text-muted-foreground mt-1">
                     PDF, DOC, DOCX, XLS, XLSX, DWG, DXF
@@ -498,5 +552,6 @@ export function BulkB4UploadDialog({
         </Form>
       </DialogContent>
     </Dialog>
+    </>
   )
 }
\ No newline at end of file
-- 
cgit v1.2.3

