summaryrefslogtreecommitdiff
path: root/components/vendor-data/vendor-data-container.tsx
diff options
context:
space:
mode:
authordujinkim <dujin.kim@dtsolution.co.kr>2025-04-28 02:13:30 +0000
committerdujinkim <dujin.kim@dtsolution.co.kr>2025-04-28 02:13:30 +0000
commitef4c533ebacc2cdc97e518f30e9a9350004fcdfb (patch)
tree345251a3ed0f4429716fa5edaa31024d8f4cb560 /components/vendor-data/vendor-data-container.tsx
parent9ceed79cf32c896f8a998399bf1b296506b2cd4a (diff)
~20250428 작업사항
Diffstat (limited to 'components/vendor-data/vendor-data-container.tsx')
-rw-r--r--components/vendor-data/vendor-data-container.tsx265
1 files changed, 216 insertions, 49 deletions
diff --git a/components/vendor-data/vendor-data-container.tsx b/components/vendor-data/vendor-data-container.tsx
index 11aa6f9d..77b36abf 100644
--- a/components/vendor-data/vendor-data-container.tsx
+++ b/components/vendor-data/vendor-data-container.tsx
@@ -6,9 +6,14 @@ import { ResizableHandle, ResizablePanel, ResizablePanelGroup } from "@/componen
import { cn } from "@/lib/utils"
import { ProjectSwitcher } from "./project-swicher"
import { Sidebar } from "./sidebar"
-import { usePathname, useRouter } from "next/navigation"
+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 { FormInput } from "lucide-react"
+import { Skeleton } from "@/components/ui/skeleton"
interface PackageData {
itemId: number
@@ -25,6 +30,7 @@ interface ProjectData {
projectId: number
projectCode: string
projectName: string
+ projectType: string
contracts: ContractData[]
}
@@ -58,45 +64,86 @@ export function VendorDataContainer({
children
}: VendorDataContainerProps) {
const pathname = usePathname()
+ const router = useRouter()
+ const searchParams = useSearchParams()
const tagIdNumber = getTagIdFromPathname(pathname)
-
- const [isCollapsed, setIsCollapsed] = React.useState(defaultCollapsed)
- // 폼 로드 요청 추적
- const lastRequestIdRef = React.useRef(0)
-
// 기본 상태
const [selectedProjectId, setSelectedProjectId] = React.useState(projects[0]?.projectId || 0)
+ const [isCollapsed, setIsCollapsed] = React.useState(defaultCollapsed)
const [selectedContractId, setSelectedContractId] = React.useState(
projects[0]?.contracts[0]?.contractId || 0
)
- // URL에서 들어온 tagIdNumber를 우선으로 설정하기 위해 초기에 null로 두고, 뒤에서 useEffect로 세팅
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]
- const isTagOrFormRoute = pathname ? (pathname.includes("/tag/") || pathname.includes("/form/")) : false
- const currentPackageName = isTagOrFormRoute
- ? currentContract?.packages.find((pkg) => pkg.itemId === selectedPackageId)?.itemName || "None"
- : "None"
+ // 프로젝트 타입 확인 - ship인 경우 항상 ENG 모드
+ const isShipProject = currentProject?.projectType === "ship"
+
+ // URL에서 모드 추출 (ship 프로젝트면 무조건 ENG로, 아니면 URL 또는 기본값)
+ const modeFromUrl = searchParams?.get('mode')
+ const initialMode = isShipProject
+ ? "ENG"
+ : (modeFromUrl === "ENG" || modeFromUrl === "IM") ? modeFromUrl : "IM"
+
+ // 모드 선택 상태 - 프로젝트 타입에 따라 초기값 결정
+ const [selectedMode, setSelectedMode] = React.useState<"IM" | "ENG">(initialMode)
+
+ 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(() => {
+ if (!isShipProject) {
+ const modeFromUrl = searchParams?.get('mode')
+ if (modeFromUrl === "ENG" || modeFromUrl === "IM") {
+ setSelectedMode(modeFromUrl)
+ }
+ }
+ }, [searchParams, isShipProject])
+
+ // 프로젝트 타입이 변경될 때 모드 업데이트
+ React.useEffect(() => {
+ if (isShipProject) {
+ setSelectedMode("ENG")
+
+ // URL 모드 파라미터도 업데이트
+ const url = new URL(window.location.href);
+ url.searchParams.set('mode', 'ENG');
+ router.replace(url.pathname + url.search);
+ }
+ }, [isShipProject, router])
+
// (1) 새로고침 시 URL 파라미터(tagIdNumber) → selectedPackageId 세팅
- // URL에 tagIdNumber가 있으면 그걸 우선으로, 아니면 기존 로직대로 '첫 번째 패키지' 사용
React.useEffect(() => {
if (!currentContract) return
@@ -121,17 +168,7 @@ export function VendorDataContainer({
}
}, [currentProject])
- // // (3) selectedPackageId 바뀔 때 URL도 같이 업데이트
- // React.useEffect(() => {
- // if (!selectedPackageId) return
- // const basePath = pathname.includes("/partners/")
- // ? "/partners/vendor-data/tag/"
- // : "/vendor-data/tag/"
-
- // router.push(`${basePath}${selectedPackageId}`)
- // }, [selectedPackageId, router, pathname])
-
- // (4) 패키지 ID가 정해질 때마다 폼 로딩
+ // (3) 패키지 ID와 모드가 변경될 때마다 폼 로딩
React.useEffect(() => {
const packageId = getTagIdFromPathname(pathname)
@@ -139,27 +176,30 @@ export function VendorDataContainer({
setSelectedPackageId(packageId)
// URL에서 패키지 ID를 얻었을 때 즉시 폼 로드
- loadFormsList(packageId);
+ loadFormsList(packageId, selectedMode);
} else if (currentContract?.packages?.length) {
- setSelectedPackageId(currentContract.packages[0].itemId)
+ const firstPackageId = currentContract.packages[0].itemId;
+ setSelectedPackageId(firstPackageId);
+ loadFormsList(firstPackageId, selectedMode);
}
- }, [pathname, currentContract])
+ }, [pathname, currentContract, selectedMode])
- // 폼 로드 함수를 컴포넌트 내부에 정의하고 재사용
- const loadFormsList = async (packageId: number) => {
+ // 모드에 따른 폼 로드 함수
+ const loadFormsList = async (packageId: number, mode: "IM" | "ENG") => {
if (!packageId) return;
setIsLoadingForms(true);
try {
- const result = await getFormsByContractItemId(packageId);
+ const result = await getFormsByContractItemId(packageId, mode);
setFormList(result.forms || []);
} catch (error) {
- console.error("폼 로딩 오류:", error);
+ console.error(`폼 로딩 오류 (${mode} 모드):`, error);
setFormList([]);
} finally {
setIsLoadingForms(false);
}
};
+
// 핸들러들
function handleSelectContract(projId: number, cId: number) {
setSelectedProjectId(projId)
@@ -177,6 +217,27 @@ export function VendorDataContainer({
}
}
+ // 모드 변경 핸들러
+ const handleModeChange = (mode: "IM" | "ENG") => {
+ // ship 프로젝트인 경우 모드 변경 금지
+ if (isShipProject && mode !== "ENG") return;
+
+ setSelectedMode(mode);
+
+ // 현재 URL에서 mode 파라미터 업데이트 (현재 경로 유지)
+ const url = new URL(window.location.href);
+ url.searchParams.set('mode', mode);
+ router.replace(url.pathname + url.search);
+
+ // 모드가 변경되면 현재 패키지의 폼 다시 로드
+ if (selectedPackageId) {
+ loadFormsList(selectedPackageId, mode);
+ } else if (currentContract?.packages?.length) {
+ const firstPackageId = currentContract.packages[0].itemId;
+ loadFormsList(firstPackageId, mode);
+ }
+ };
+
return (
<TooltipProvider delayDuration={0}>
<ResizablePanelGroup direction="horizontal" className="h-full">
@@ -204,21 +265,123 @@ export function VendorDataContainer({
/>
</div>
<Separator />
- <Sidebar
- isCollapsed={isCollapsed}
- packages={currentContract?.packages || []}
- selectedPackageId={selectedPackageId}
- onSelectPackage={handleSelectPackage}
- forms={formList}
- selectedForm={
- selectedFormCode
- ? formList.find((f) => f.formCode === selectedFormCode)?.formName || null
- : null
- }
- onSelectForm={handleSelectForm}
- isLoadingForms={isLoadingForms}
- className="hidden lg:block"
- />
+
+ {!isCollapsed ? (
+ isShipProject ? (
+ // 프로젝트 타입이 ship인 경우: 탭 없이 ENG 모드 사이드바만 바로 표시
+ <div className="mt-0">
+ <Sidebar
+ isCollapsed={isCollapsed}
+ packages={currentContract?.packages || []}
+ selectedPackageId={selectedPackageId}
+ 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"
+ />
+ </div>
+ ) : (
+ // 프로젝트 타입이 ship이 아닌 경우: 기존 탭 UI 표시
+ <Tabs
+ defaultValue={initialMode}
+ value={selectedMode}
+ onValueChange={(value) => handleModeChange(value as "IM" | "ENG")}
+ className="w-full"
+ >
+ <TabsList className="w-full">
+ <TabsTrigger value="IM" className="flex-1">IM</TabsTrigger>
+ <TabsTrigger value="ENG" className="flex-1">ENG</TabsTrigger>
+ </TabsList>
+
+ <TabsContent value="IM" className="mt-0">
+ <Sidebar
+ isCollapsed={isCollapsed}
+ packages={currentContract?.packages || []}
+ selectedPackageId={selectedPackageId}
+ 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"
+ />
+ </TabsContent>
+
+ <TabsContent value="ENG" className="mt-0">
+ <Sidebar
+ isCollapsed={isCollapsed}
+ packages={currentContract?.packages || []}
+ selectedPackageId={selectedPackageId}
+ 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"
+ />
+ </TabsContent>
+ </Tabs>
+ )
+ ) : (
+ // 접혀있을 때 UI
+ <>
+ {!isShipProject && (
+ // ship 프로젝트가 아닐 때만 모드 선택 버튼 표시
+ <div className="flex justify-center space-x-1 my-2">
+ <Button
+ variant={selectedMode === "IM" ? "default" : "ghost"}
+ size="sm"
+ className="h-8 px-2"
+ onClick={() => handleModeChange("IM")}
+ >
+ IM
+ </Button>
+ <Button
+ variant={selectedMode === "ENG" ? "default" : "ghost"}
+ size="sm"
+ className="h-8 px-2"
+ onClick={() => handleModeChange("ENG")}
+ >
+ ENG
+ </Button>
+ </div>
+ )}
+
+ <Sidebar
+ isCollapsed={isCollapsed}
+ packages={currentContract?.packages || []}
+ selectedPackageId={selectedPackageId}
+ 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"
+ />
+ </>
+ )}
</ResizablePanel>
<ResizableHandle withHandle />
@@ -226,7 +389,11 @@ export function VendorDataContainer({
<ResizablePanel defaultSize={defaultLayout[1]} minSize={40}>
<div className="p-4 h-full overflow-auto flex flex-col">
<div className="flex items-center justify-between mb-4">
- <h2 className="text-lg font-bold">Package: {currentPackageName}</h2>
+ <h2 className="text-lg font-bold">
+ {isShipProject || selectedMode === "ENG"
+ ? "Engineering Mode"
+ : `Package: ${currentPackageName}`}
+ </h2>
</div>
{children}
</div>