From 02b1cf005cf3e1df64183d20ba42930eb2767a9f Mon Sep 17 00:00:00 2001
From: dujinkim <dujin.kim@dtsolution.co.kr>
Date: Thu, 21 Aug 2025 06:57:36 +0000
Subject: (대표님, 최겸) 설계메뉴추가, 작업사항 업데이트 설계메뉴 - 문서관리
 설계메뉴 - 벤더 데이터 gtc 메뉴 업데이트 정보시스템 - 메뉴리스트 및 정보
 업데이트 파일 라우트 업데이트 엑셀임포트 개선 기본계약 개선 벤더 가입과정
 변경 및 개선 벤더 기본정보 - pq 돌체 오류 수정 및 개선 벤더 로그인 과정
 이메일 오류 수정
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 components/vendor-data/vendor-data-container.tsx | 333 +++++++++++++++++------
 1 file changed, 252 insertions(+), 81 deletions(-)

(limited to 'components/vendor-data/vendor-data-container.tsx')

diff --git a/components/vendor-data/vendor-data-container.tsx b/components/vendor-data/vendor-data-container.tsx
index 3974b791..207abcf1 100644
--- a/components/vendor-data/vendor-data-container.tsx
+++ b/components/vendor-data/vendor-data-container.tsx
@@ -1,42 +1,63 @@
 "use client"
 
 import * as React from "react"
-import { usePathname, useRouter, useSearchParams, useParams } from "next/navigation"
-import { useAtom } from "jotai"
-import { selectedModeAtom } from "@/atoms"
-import { Sidebar } from "./sidebar"
-import { ProjectSwitcher } from "./project-swicher"
+import { TooltipProvider } from "@/components/ui/tooltip"
 import { ResizableHandle, ResizablePanel, ResizablePanelGroup } from "@/components/ui/resizable"
 import { cn } from "@/lib/utils"
+import { ProjectSwitcher } from "./project-swicher"
+import { Sidebar } from "./sidebar"
+import { usePathname, useRouter, useSearchParams } from "next/navigation"
+import { getFormsByContractItemId, type FormInfo } from "@/lib/forms/services"
 import { Separator } from "@/components/ui/separator"
 import { Tabs, TabsList, TabsTrigger, TabsContent } from "@/components/ui/tabs"
+import { ScrollArea } from "@/components/ui/scroll-area"
 import { Button } from "@/components/ui/button"
-import { TooltipProvider } from "@/components/ui/tooltip"
+import { FormInput } from "lucide-react"
+import { Skeleton } from "@/components/ui/skeleton"
+import { selectedModeAtom } from '@/atoms'
+import { useAtom } from 'jotai'
 
 interface PackageData {
   itemId: number
   itemName: string
 }
 
+interface ContractData {
+  contractId: number
+  contractName: string
+  packages: PackageData[]
+}
+
+interface ProjectData {
+  projectId: number
+  projectCode: string
+  projectName: string
+  projectType: string
+  contracts: ContractData[]
+}
+
 interface VendorDataContainerProps {
-  projects: {
-    projectId: number
-    projectCode: string
-    projectName: string
-    projectType: string
-    contracts: {
-      contractId: number
-      contractNo: string
-      contractName: string
-      packages: PackageData[]
-    }[]
-  }[]
+  projects: ProjectData[]
   defaultLayout?: number[]
   defaultCollapsed?: boolean
-  navCollapsedSize?: number
+  navCollapsedSize: number
   children: React.ReactNode
 }
 
+function getTagIdFromPathname(path: string | null): number | null {
+  if (!path) return null;
+  
+  // 태그 패턴 검사 (/tag/123)
+  const tagMatch = path.match(/\/tag\/(\d+)/)
+  if (tagMatch) return parseInt(tagMatch[1], 10)
+  
+  // 폼 패턴 검사 (/form/123/...)
+  const formMatch = path.match(/\/form\/(\d+)/)
+  if (formMatch) return parseInt(formMatch[1], 10)
+  
+  return null
+}
+
 export function VendorDataContainer({
   projects,
   defaultLayout = [20, 80],
@@ -47,8 +68,8 @@ export function VendorDataContainer({
   const pathname = usePathname()
   const router = useRouter()
   const searchParams = useSearchParams()
-  const params = useParams()
-  const currentLng = params?.lng as string || 'en'
+
+  const tagIdNumber = getTagIdFromPathname(pathname)
 
   // 기본 상태
   const [selectedProjectId, setSelectedProjectId] = React.useState(projects[0]?.projectId || 0)
@@ -57,12 +78,15 @@ export function VendorDataContainer({
     projects[0]?.contracts[0]?.contractId || 0
   )
   const [selectedPackageId, setSelectedPackageId] = React.useState<number | null>(null)
+  const [formList, setFormList] = React.useState<FormInfo[]>([])
+  const [selectedFormCode, setSelectedFormCode] = React.useState<string | null>(null)
+  const [isLoadingForms, setIsLoadingForms] = React.useState(false)
 
   // 현재 선택된 프로젝트/계약/패키지
   const currentProject = projects.find((p) => p.projectId === selectedProjectId) ?? projects[0]
   const currentContract = currentProject?.contracts.find((c) => c.contractId === selectedContractId)
     ?? currentProject?.contracts[0]
-    
+
   // 프로젝트 타입 확인 - ship인 경우 항상 ENG 모드
   const isShipProject = currentProject?.projectType === "ship"
   
@@ -78,6 +102,30 @@ export function VendorDataContainer({
   React.useEffect(() => {
     setSelectedMode(initialMode as "IM" | "ENG")
   }, [initialMode, setSelectedMode])
+  
+  const isTagOrFormRoute = pathname ? (pathname.includes("/tag/") || pathname.includes("/form/")) : false
+  const currentPackageName = isTagOrFormRoute
+    ? currentContract?.packages.find((pkg) => pkg.itemId === selectedPackageId)?.itemName || "None"
+    : "None"
+  
+  // 폼 목록에서 고유한 폼 이름만 추출
+  const formNames = React.useMemo(() => {
+    return [...new Set(formList.map((form) => form.formName))]
+  }, [formList])
+
+  // URL에서 현재 폼 코드 추출
+  const getCurrentFormCode = (path: string): string | null => {
+    const segments = path.split("/").filter(Boolean)
+    const formIndex = segments.indexOf("form")
+    if (formIndex !== -1 && segments[formIndex + 2]) {
+      return segments[formIndex + 2]
+    }
+    return null
+  }
+
+  const currentFormCode = React.useMemo(() => {
+    return pathname ? getCurrentFormCode(pathname) : null
+  }, [pathname])
 
   // URL에서 모드가 변경되면 상태도 업데이트 (ship 프로젝트가 아닐 때만)
   React.useEffect(() => {
@@ -101,89 +149,184 @@ export function VendorDataContainer({
     }
   }, [isShipProject, router])
 
-  // (1) 프로젝트 변경 시 계약 초기화
+  // (1) 새로고침 시 URL 파라미터(tagIdNumber) → selectedPackageId 세팅
   React.useEffect(() => {
-    if (currentProject?.contracts.length) {
-      setSelectedContractId(currentProject.contracts[0].contractId)
+    if (!currentContract) return
+
+    if (tagIdNumber) {
+      setSelectedPackageId(tagIdNumber)
     } else {
-      setSelectedContractId(0)
+      // tagIdNumber가 없으면, 현재 계약의 첫 번째 패키지로
+      if (currentContract.packages?.length) {
+        setSelectedPackageId(currentContract.packages[0].itemId)
+      } else {
+        setSelectedPackageId(null)
+      }
     }
-  }, [currentProject])
+  }, [tagIdNumber, currentContract])
 
-  // 핸들러들
-  function handleSelectContract(projId: number, cId: number) {
-    setSelectedProjectId(projId)
-    setSelectedContractId(cId)
-  }
+  // (2) 프로젝트 변경 시 계약 초기화
+  // React.useEffect(() => {
+  //   if (currentProject?.contracts.length) {
+  //     setSelectedContractId(currentProject.contracts[0].contractId)
+  //   } else {
+  //     setSelectedContractId(0)
+  //   }
+  // }, [currentProject])
 
-  function handleSelectPackage(itemId: number) {
-    setSelectedPackageId(itemId)
+  // (3) 패키지 ID와 모드가 변경될 때마다 폼 로딩
+  React.useEffect(() => {
+    const packageId = getTagIdFromPathname(pathname)
     
-    // partners와 동일하게: 패키지 선택 시 해당 페이지로 이동
-    if (itemId && pathname) {
-      // 더 안전한 URL 생성 로직
-      let baseSegments: string;
-      const vendorDataIndex = pathname.split("/").filter(Boolean).indexOf("vendor-data");
+    if (packageId) {
+      setSelectedPackageId(packageId)
       
-      if (vendorDataIndex !== -1) {
-        baseSegments = pathname.split("/").filter(Boolean).slice(0, vendorDataIndex + 1).join("/");
+      // URL에서 패키지 ID를 얻었을 때 즉시 폼 로드
+      loadFormsList(packageId, selectedMode);
+    } else if (currentContract?.packages?.length) {
+      const firstPackageId = currentContract.packages[0].itemId;
+      setSelectedPackageId(firstPackageId);
+      loadFormsList(firstPackageId, selectedMode);
+    }
+  }, [pathname, currentContract, selectedMode])
+  
+  // 모드에 따른 폼 로드 함수
+  const loadFormsList = async (packageId: number, mode: "IM" | "ENG") => {
+    if (!packageId) return;
+    
+    setIsLoadingForms(true);
+    try {
+      const result = await getFormsByContractItemId(packageId, mode);
+      setFormList(result.forms || []);
+    } catch (error) {
+      console.error(`폼 로딩 오류 (${mode} 모드):`, error);
+      setFormList([]);
+    } finally {
+      setIsLoadingForms(false);
+    }
+  };
+
+  // 핸들러들
+// 수정된 handleSelectContract 함수
+async function handleSelectContract(projId: number, cId: number) {
+  setSelectedProjectId(projId)
+  setSelectedContractId(cId)
+  
+  // 선택된 계약의 첫 번째 패키지 찾기
+  const selectedProject = projects.find(p => p.projectId === projId)
+  const selectedContract = selectedProject?.contracts.find(c => c.contractId === cId)
+  
+  if (selectedContract?.packages?.length) {
+    const firstPackageId = selectedContract.packages[0].itemId
+    setSelectedPackageId(firstPackageId)
+    
+    // ENG 모드로 폼 목록 로드
+    setIsLoadingForms(true)
+    try {
+      const result = await getFormsByContractItemId(firstPackageId, "ENG")
+      setFormList(result.forms || [])
+      
+      // 첫 번째 폼이 있으면 자동 선택 및 네비게이션
+      if (result.forms && result.forms.length > 0) {
+        const firstForm = result.forms[0]
+        setSelectedFormCode(firstForm.formCode)
+        
+        // ENG 모드로 설정
+        setSelectedMode("ENG")
+        
+        // 첫 번째 폼으로 네비게이션
+        const baseSegments = pathname?.split("/").filter(Boolean).slice(0, pathname.split("/").filter(Boolean).indexOf("vendor-data") + 1).join("/")
+        router.push(`/${baseSegments}/form/0/${firstForm.formCode}/${projId}/${cId}?mode=ENG`)
       } else {
-        // vendor-data가 없으면 기본 경로 사용
-        baseSegments = `${currentLng}/evcp/vendor-data`;
+        // 폼이 없는 경우에도 ENG 모드로 설정
+        setSelectedMode("ENG")
+        setSelectedFormCode(null)
+        
+        const baseSegments = pathname?.split("/").filter(Boolean).slice(0, pathname.split("/").filter(Boolean).indexOf("vendor-data") + 1).join("/")
+        router.push(`/${baseSegments}/form/0/0/${projId}/${cId}?mode=ENG`)
       }
+    } catch (error) {
+      console.error("폼 로딩 오류:", error)
+      setFormList([])
+      setSelectedFormCode(null)
       
-      const targetUrl = `/${baseSegments}/tag/${itemId}?mode=${selectedMode}`;
-      router.push(targetUrl);
+      // 오류 발생 시에도 ENG 모드로 설정
+      setSelectedMode("ENG")
+    } finally {
+      setIsLoadingForms(false)
     }
+  } else {
+    // 패키지가 없는 경우
+    setSelectedPackageId(null)
+    setFormList([])
+    setSelectedFormCode(null)
+    setSelectedMode("ENG")
+  }
+}
+
+  function handleSelectPackage(itemId: number) {
+    setSelectedPackageId(itemId)
   }
 
   function handleSelectForm(formName: string) {
-    // partners와 동일하게: 폼 선택 시 해당 페이지로 이동
-    if (selectedPackageId && pathname) {
-      // 더 안전한 URL 생성 로직
-      let baseSegments: string;
-      const vendorDataIndex = pathname.split("/").filter(Boolean).indexOf("vendor-data");
-      
-      if (vendorDataIndex !== -1) {
-        baseSegments = pathname.split("/").filter(Boolean).slice(0, vendorDataIndex + 1).join("/");
-      } else {
-        // vendor-data가 없으면 기본 경로 사용
-        baseSegments = `${currentLng}/evcp/vendor-data`;
-      }
-      
-      const targetUrl = `/${baseSegments}/form/${selectedPackageId}/${formName}/${selectedProjectId}/${selectedContractId}?mode=${selectedMode}`;
-      router.push(targetUrl);
+    const form = formList.find((f) => f.formName === formName)
+    if (form) {
+      setSelectedFormCode(form.formCode)
     }
   }
 
   // 모드 변경 핸들러
-  const handleModeChange = async (mode: "IM" | "ENG") => {
-    // ship 프로젝트인 경우 모드 변경 금지
-    if (isShipProject && mode !== "ENG") return;
-    
-    setSelectedMode(mode);
+// 모드 변경 핸들러
+const handleModeChange = async (mode: "IM" | "ENG") => {
+  // ship 프로젝트인 경우 모드 변경 금지
+  if (isShipProject && mode !== "ENG") return;
+  
+  setSelectedMode(mode);
+  
+  // 모드가 변경될 때 자동 네비게이션
+  if (currentContract?.packages?.length) {
+    const firstPackageId = currentContract.packages[0].itemId;
     
-    // 모드가 변경될 때 자동 네비게이션
-    if (currentContract?.packages?.length) {
-      const firstPackageId = currentContract.packages[0].itemId;
-      
-      if (pathname) {
-        // 더 안전한 URL 생성 로직
-        let baseSegments: string;
-        const vendorDataIndex = pathname.split("/").filter(Boolean).indexOf("vendor-data");
+    if (mode === "IM") {
+      // IM 모드: 첫 번째 패키지로 이동
+      const baseSegments = pathname?.split("/").filter(Boolean).slice(0, pathname.split("/").filter(Boolean).indexOf("vendor-data") + 1).join("/");
+      router.push(`/${baseSegments}/tag/${firstPackageId}?mode=${mode}`);
+    } else {
+      // ENG 모드: 폼 목록을 먼저 로드
+      setIsLoadingForms(true);
+      try {
+        const result = await getFormsByContractItemId(firstPackageId, mode);
+        setFormList(result.forms || []);
         
-        if (vendorDataIndex !== -1) {
-          baseSegments = pathname.split("/").filter(Boolean).slice(0, vendorDataIndex + 1).join("/");
+        // 폼이 있으면 첫 번째 폼으로 이동
+        if (result.forms && result.forms.length > 0) {
+          const firstForm = result.forms[0];
+          setSelectedFormCode(firstForm.formCode);
+          
+          const baseSegments = pathname?.split("/").filter(Boolean).slice(0, pathname.split("/").filter(Boolean).indexOf("vendor-data") + 1).join("/");
+          router.push(`/${baseSegments}/form/0/${firstForm.formCode}/${selectedProjectId}/${selectedContractId}?mode=${mode}`);
         } else {
-          // vendor-data가 없으면 기본 경로 사용
-          baseSegments = `${currentLng}/evcp/vendor-data`;
+          // 폼이 없으면 모드만 변경
+          const baseSegments = pathname?.split("/").filter(Boolean).slice(0, pathname.split("/").filter(Boolean).indexOf("vendor-data") + 1).join("/");
+          router.push(`/${baseSegments}/form/0/0/${selectedProjectId}/${selectedContractId}?mode=${mode}`);
         }
-        
-        const targetUrl = `/${baseSegments}/tag/${firstPackageId}?mode=${mode}`;
-        router.push(targetUrl);
+      } catch (error) {
+        console.error(`폼 로딩 오류 (${mode} 모드):`, error);
+        // 오류 발생 시 모드만 변경
+        const url = new URL(window.location.href);
+        url.searchParams.set('mode', mode);
+        router.replace(url.pathname + url.search);
+      } finally {
+        setIsLoadingForms(false);
       }
     }
+  } else {
+    // 패키지가 없는 경우, 모드만 변경
+    const url = new URL(window.location.href);
+    url.searchParams.set('mode', mode);
+    router.replace(url.pathname + url.search);
   }
+};
 
   return (
     <TooltipProvider delayDuration={0}>
@@ -224,7 +367,14 @@ export function VendorDataContainer({
                   selectedProjectId={selectedProjectId}
                   selectedContractId={selectedContractId}
                   onSelectPackage={handleSelectPackage}
+                  forms={formList}
+                  selectedForm={
+                    selectedFormCode
+                      ? formList.find((f) => f.formCode === selectedFormCode)?.formName || null
+                      : null
+                  }
                   onSelectForm={handleSelectForm}
+                  isLoadingForms={isLoadingForms}
                   mode="ENG"
                   className="hidden lg:block"
                 />
@@ -250,7 +400,14 @@ export function VendorDataContainer({
                     selectedContractId={selectedContractId}
                     selectedProjectId={selectedProjectId}
                     onSelectPackage={handleSelectPackage}
+                    forms={formList}
+                    selectedForm={
+                      selectedFormCode
+                        ? formList.find((f) => f.formCode === selectedFormCode)?.formName || null
+                        : null
+                    }
                     onSelectForm={handleSelectForm}
+                    isLoadingForms={isLoadingForms}
                     mode="IM"
                     className="hidden lg:block"
                   />
@@ -264,7 +421,14 @@ export function VendorDataContainer({
                     selectedContractId={selectedContractId}
                     selectedProjectId={selectedProjectId}
                     onSelectPackage={handleSelectPackage}
+                    forms={formList}
+                    selectedForm={
+                      selectedFormCode
+                        ? formList.find((f) => f.formCode === selectedFormCode)?.formName || null
+                        : null
+                    }
                     onSelectForm={handleSelectForm}
+                    isLoadingForms={isLoadingForms}
                     mode="ENG"
                     className="hidden lg:block"
                   />
@@ -303,7 +467,14 @@ export function VendorDataContainer({
                 selectedProjectId={selectedProjectId}
                 selectedContractId={selectedContractId}
                 onSelectPackage={handleSelectPackage}
+                forms={formList}
+                selectedForm={
+                  selectedFormCode
+                    ? formList.find((f) => f.formCode === selectedFormCode)?.formName || null
+                    : null
+                }
                 onSelectForm={handleSelectForm}
+                isLoadingForms={isLoadingForms}
                 mode={isShipProject ? "ENG" : selectedMode}
                 className="hidden lg:block"
               />
@@ -319,7 +490,7 @@ export function VendorDataContainer({
               <h2 className="text-lg font-bold">
                 {isShipProject || selectedMode === "ENG" 
                   ? "Engineering Mode" 
-                  : `Package: ${currentContract?.packages.find((pkg) => pkg.itemId === selectedPackageId)?.itemName || "None"}`}
+                  : `Package: ${currentPackageName}`}
               </h2>
             </div>
             {children}
-- 
cgit v1.2.3

