diff options
| author | joonhoekim <26rote@gmail.com> | 2025-11-27 17:53:34 +0900 |
|---|---|---|
| committer | joonhoekim <26rote@gmail.com> | 2025-11-27 17:53:34 +0900 |
| commit | 5870b73785715d1585531e655c06d8c068eb64ac (patch) | |
| tree | 1d19e1482f5210cc56e778158b51e810f9717c46 /components/vendor-data-plant/sidebar.tsx | |
| parent | 95984e67b8d57fbe1431fcfedf3bb682f28416b3 (diff) | |
(김준회) Revert "(대표님) EDP 작업사항"
태그 가져오기 실패 등 에러로 인한 Revert 처리
Diffstat (limited to 'components/vendor-data-plant/sidebar.tsx')
| -rw-r--r-- | components/vendor-data-plant/sidebar.tsx | 479 |
1 files changed, 259 insertions, 220 deletions
diff --git a/components/vendor-data-plant/sidebar.tsx b/components/vendor-data-plant/sidebar.tsx index b746e69d..31ee6dc7 100644 --- a/components/vendor-data-plant/sidebar.tsx +++ b/components/vendor-data-plant/sidebar.tsx @@ -10,265 +10,304 @@ import { TooltipTrigger, TooltipContent, } from "@/components/ui/tooltip" -import { List, FormInput, FileText } from "lucide-react" +import { Package2, FormInput } from "lucide-react" +import { useRouter, usePathname } from "next/navigation" import { Skeleton } from "@/components/ui/skeleton" -import { getEngineeringForms, getIMForms } from "@/lib/tags-plant/service" +import { type FormInfo } from "@/lib/forms/services" -interface FormInfo { - formCode: string - formName: string +interface PackageData { + itemId: number + itemName: string } interface SidebarProps extends React.HTMLAttributes<HTMLDivElement> { isCollapsed: boolean - selectedPackageCode: string | null - selectedFormCode: string | null - currentMode: "master" | "engineering" | "im" | null - projectCode: string // 추가 - onMasterTagListClick: () => void - onEngineeringFormClick: (formCode: string) => void - onIMFormClick: (formCode: string) => void + packages: PackageData[] + selectedPackageId: number | null + selectedProjectId: number | null + selectedContractId: number | null + onSelectPackage: (itemId: number) => void + forms?: FormInfo[] + onSelectForm: (formName: string) => void + isLoadingForms?: boolean + mode: "IM" | "ENG" } export function Sidebar({ className, isCollapsed, - selectedPackageCode, - selectedFormCode, - currentMode, - projectCode, // 추가 - onMasterTagListClick, - onEngineeringFormClick, - onIMFormClick, + packages, + selectedPackageId, + selectedProjectId, + selectedContractId, + onSelectPackage, + forms, + onSelectForm, + isLoadingForms = false, + mode = "IM", }: SidebarProps) { - const [engineeringForms, setEngineeringForms] = React.useState<FormInfo[]>([]) - const [imForms, setIMForms] = React.useState<FormInfo[]>([]) - const [isLoadingEngineering, setIsLoadingEngineering] = React.useState(false) - const [isLoadingIM, setIsLoadingIM] = React.useState(false) + const router = useRouter() + const rawPathname = usePathname() + const pathname = rawPathname ?? "" - // Engineering 폼 로드 - React.useEffect(() => { - if (!selectedPackageCode || !projectCode) { - setEngineeringForms([]) - return - } + /** + * --------------------------- + * 1) URL에서 현재 패키지 / 폼 코드 추출 + * --------------------------- + */ + const segments = pathname.split("/").filter(Boolean) - const loadEngineeringForms = async () => { - setIsLoadingEngineering(true) - try { - const result = await getEngineeringForms(projectCode, selectedPackageCode) - setEngineeringForms(result) - } catch (error) { - console.error("Engineering 폼 로딩 오류:", error) - setEngineeringForms([]) - } finally { - setIsLoadingEngineering(false) - } - } + let currentItemId: number | null = null + let currentFormCode: string | null = null - loadEngineeringForms() - }, [selectedPackageCode, projectCode]) + const tagIndex = segments.indexOf("tag") + if (tagIndex !== -1 && segments[tagIndex + 1]) { + currentItemId = parseInt(segments[tagIndex + 1], 10) + } - // IM 폼 로드 - React.useEffect(() => { - if (!selectedPackageCode || !projectCode) { - setIMForms([]) - return - } + const formIndex = segments.indexOf("form") + if (formIndex !== -1) { + const itemSegment = segments[formIndex + 1] + const codeSegment = segments[formIndex + 2] - const loadIMForms = async () => { - setIsLoadingIM(true) - try { - const result = await getIMForms(projectCode, selectedPackageCode) - setIMForms(result) - } catch (error) { - console.error("IM 폼 로딩 오류:", error) - setIMForms([]) - } finally { - setIsLoadingIM(false) - } + if (itemSegment) { + currentItemId = parseInt(itemSegment, 10) + } + if (codeSegment) { + currentFormCode = codeSegment } + } - loadIMForms() - }, [selectedPackageCode, projectCode]) + /** + * --------------------------- + * 2) 패키지 클릭 핸들러 (IM 모드) + * --------------------------- + */ + const handlePackageClick = (itemId: number) => { + // 상위 컴포넌트 상태 업데이트 + onSelectPackage(itemId) - const isMasterActive = currentMode === "master" - const isPackageSelected = selectedPackageCode !== null + // 해당 태그 페이지로 라우팅 + // 예: /vendor-data-plant/tag/123 + const baseSegments = segments.slice(0, segments.indexOf("vendor-data-plant") + 1).join("/") + router.push(`/${baseSegments}/tag/${itemId}`) + } + + /** + * --------------------------- + * 3) 폼 클릭 핸들러 (IM 모드만 사용) + * --------------------------- + */ + const handleFormClick = (form: FormInfo) => { + // IM 모드에서만 사용 + if (selectedPackageId === null) return; + + onSelectForm(form.formName) + + const baseSegments = segments.slice(0, segments.indexOf("vendor-data-plant") + 1).join("/") + router.push(`/${baseSegments}/form/${selectedPackageId}/${form.formCode}/${selectedProjectId}/${selectedContractId}?mode=${mode}`) + } + + /** + * --------------------------- + * 4) 패키지 클릭 핸들러 (ENG 모드) + * --------------------------- + */ + const handlePackageUnderFormClick = (form: FormInfo, pkg: PackageData) => { + onSelectForm(form.formName) + onSelectPackage(pkg.itemId) + + const baseSegments = segments.slice(0, segments.indexOf("vendor-data-plant") + 1).join("/") + router.push(`/${baseSegments}/form/${pkg.itemId}/${form.formCode}/${selectedProjectId}/${selectedContractId}?mode=${mode}`) + } return ( <div className={cn("pb-12", className)}> <div className="space-y-4 py-4"> - {/* Master Tag List */} - <div className="py-1"> - <h2 className="relative px-7 text-lg font-semibold tracking-tight"> - {isCollapsed ? "M" : "Master"} - </h2> - <div className="space-y-1 p-2"> - {isCollapsed ? ( - <Tooltip delayDuration={0}> - <TooltipTrigger asChild> - <Button - variant="ghost" - className={cn( - "w-full justify-start font-normal", - isMasterActive && "bg-accent text-accent-foreground" - )} - onClick={onMasterTagListClick} - disabled={!isPackageSelected} - > - <List className="h-4 w-4" /> - </Button> - </TooltipTrigger> - <TooltipContent side="right"> - Master Tag List - </TooltipContent> - </Tooltip> - ) : ( - <Button - variant="ghost" - className={cn( - "w-full justify-start font-normal", - isMasterActive && "bg-accent text-accent-foreground" - )} - onClick={onMasterTagListClick} - disabled={!isPackageSelected} - > - <List className="mr-2 h-4 w-4" /> - Master Tag List - </Button> - )} - </div> - </div> + {/* ---------- 패키지(Items) 목록 - IM 모드에서만 표시 ---------- */} + {mode === "IM" && ( + <> + <div className="py-1"> + <h2 className="relative px-7 text-lg font-semibold tracking-tight"> + {isCollapsed ? "P" : "Package Lists"} + </h2> + <ScrollArea className="h-[150px] px-1"> + <div className="space-y-1 p-2"> + {packages.map((pkg) => { + const isActive = pkg.itemId === currentItemId - <Separator /> + return ( + <div key={pkg.itemId}> + {isCollapsed ? ( + <Tooltip delayDuration={0}> + <TooltipTrigger asChild> + <Button + variant="ghost" + className={cn( + "w-full justify-start font-normal", + isActive && "bg-accent text-accent-foreground" + )} + onClick={() => handlePackageClick(pkg.itemId)} + > + <Package2 className="mr-2 h-4 w-4" /> + </Button> + </TooltipTrigger> + <TooltipContent side="right"> + {pkg.itemName} + </TooltipContent> + </Tooltip> + ) : ( + <Button + variant="ghost" + className={cn( + "w-full justify-start font-normal", + isActive && "bg-accent text-accent-foreground" + )} + onClick={() => handlePackageClick(pkg.itemId)} + > + <Package2 className="mr-2 h-4 w-4" /> + {pkg.itemName} + </Button> + )} + </div> + ) + })} + </div> + </ScrollArea> + </div> + <Separator /> + </> + )} - {/* Engineering Forms */} + {/* ---------- 폼 목록 (IM 모드) / 패키지와 폼 목록 (ENG 모드) ---------- */} <div className="py-1"> <h2 className="relative px-7 text-lg font-semibold tracking-tight"> - {isCollapsed ? "E" : "Engineering"} + {isCollapsed + ? (mode === "IM" ? "F" : "P") + : (mode === "IM" ? "Form Lists" : "Package Lists") + } </h2> - <ScrollArea className="h-[250px] px-1"> + <ScrollArea className={cn( + "px-1", + mode === "IM" ? "h-[300px]" : "h-[450px]" + )}> <div className="space-y-1 p-2"> - {isLoadingEngineering ? ( + {isLoadingForms ? ( Array.from({ length: 3 }).map((_, index) => ( - <div key={`eng-skeleton-${index}`} className="px-2 py-1.5"> + <div key={`form-skeleton-${index}`} className="px-2 py-1.5"> <Skeleton className="h-8 w-full" /> </div> )) - ) : !isPackageSelected ? ( - <p className="text-sm text-muted-foreground px-2"> - Select a package first - </p> - ) : engineeringForms.length === 0 ? ( - <p className="text-sm text-muted-foreground px-2"> - No forms available - </p> - ) : ( - engineeringForms.map((form) => { - const isActive = - currentMode === "engineering" && - form.formCode === selectedFormCode + ) : mode === "IM" ? ( + // =========== IM 모드: 폼만 표시 =========== + !forms || forms.length === 0 ? ( + <p className="text-sm text-muted-foreground px-2"> + (No forms loaded) + </p> + ) : ( + forms.map((form) => { + const isFormActive = form.formCode === currentFormCode + const isDisabled = currentItemId === null - return isCollapsed ? ( - <Tooltip key={form.formCode} delayDuration={0}> - <TooltipTrigger asChild> - <Button - variant="ghost" - className={cn( - "w-full justify-start font-normal", - isActive && "bg-accent text-accent-foreground" - )} - onClick={() => onEngineeringFormClick(form.formCode)} - > - <FormInput className="h-4 w-4" /> - </Button> - </TooltipTrigger> - <TooltipContent side="right"> + return isCollapsed ? ( + <Tooltip key={form.formCode} delayDuration={0}> + <TooltipTrigger asChild> + <Button + variant="ghost" + className={cn( + "w-full justify-start font-normal", + isFormActive && "bg-accent text-accent-foreground" + )} + onClick={() => handleFormClick(form)} + disabled={isDisabled} + > + <FormInput className="mr-2 h-4 w-4" /> + </Button> + </TooltipTrigger> + <TooltipContent side="right"> + {form.formName} + </TooltipContent> + </Tooltip> + ) : ( + <Button + key={form.formCode} + variant="ghost" + className={cn( + "w-full justify-start font-normal", + isFormActive && "bg-accent text-accent-foreground" + )} + onClick={() => handleFormClick(form)} + disabled={isDisabled} + > + <FormInput className="mr-2 h-4 w-4" /> {form.formName} - </TooltipContent> - </Tooltip> - ) : ( - <Button - key={form.formCode} - variant="ghost" - className={cn( - "w-full justify-start font-normal", - isActive && "bg-accent text-accent-foreground" - )} - onClick={() => onEngineeringFormClick(form.formCode)} - > - <FormInput className="mr-2 h-4 w-4" /> - {form.formName} - </Button> - ) - }) - )} - </div> - </ScrollArea> - </div> - - <Separator /> - - {/* IM Forms */} - <div className="py-1"> - <h2 className="relative px-7 text-lg font-semibold tracking-tight"> - {isCollapsed ? "I" : "IM"} - </h2> - <ScrollArea className="h-[250px] px-1"> - <div className="space-y-1 p-2"> - {isLoadingIM ? ( - Array.from({ length: 3 }).map((_, index) => ( - <div key={`im-skeleton-${index}`} className="px-2 py-1.5"> - <Skeleton className="h-8 w-full" /> - </div> - )) - ) : !isPackageSelected ? ( - <p className="text-sm text-muted-foreground px-2"> - Select a package first - </p> - ) : imForms.length === 0 ? ( - <p className="text-sm text-muted-foreground px-2"> - No forms available - </p> + </Button> + ) + }) + ) ) : ( - imForms.map((form) => { - const isActive = - currentMode === "im" && - form.formCode === selectedFormCode + // =========== ENG 모드: 패키지 > 폼 계층 구조 =========== + packages.length === 0 ? ( + <p className="text-sm text-muted-foreground px-2"> + (No packages loaded) + </p> + ) : ( + packages.map((pkg) => ( + <div key={pkg.itemId} className="space-y-1"> + {isCollapsed ? ( + <Tooltip delayDuration={0}> + <TooltipTrigger asChild> + <div className="px-2 py-1"> + <Package2 className="h-4 w-4" /> + </div> + </TooltipTrigger> + <TooltipContent side="right"> + {pkg.itemName} + </TooltipContent> + </Tooltip> + ) : ( + <> + {/* 패키지 이름 (클릭 불가능한 라벨) */} + <div className="flex items-center px-2 py-1 text-sm font-medium"> + <Package2 className="mr-2 h-4 w-4" /> + {pkg.itemName} + </div> + + {/* 폼 목록 바로 표시 */} + <div className="ml-6 space-y-1"> + {!forms || forms.length === 0 ? ( + <p className="text-xs text-muted-foreground px-2 py-1"> + No forms available + </p> + ) : ( + forms.map((form) => { + const isFormPackageActive = + pkg.itemId === currentItemId && + form.formCode === currentFormCode - return isCollapsed ? ( - <Tooltip key={form.formCode} delayDuration={0}> - <TooltipTrigger asChild> - <Button - variant="ghost" - className={cn( - "w-full justify-start font-normal", - isActive && "bg-accent text-accent-foreground" - )} - onClick={() => onIMFormClick(form.formCode)} - > - <FileText className="h-4 w-4" /> - </Button> - </TooltipTrigger> - <TooltipContent side="right"> - {form.formName} - </TooltipContent> - </Tooltip> - ) : ( - <Button - key={form.formCode} - variant="ghost" - className={cn( - "w-full justify-start font-normal", - isActive && "bg-accent text-accent-foreground" + return ( + <Button + key={`${pkg.itemId}-${form.formCode}`} + variant="ghost" + size="sm" + className={cn( + "w-full justify-start font-normal text-sm", + isFormPackageActive && "bg-accent text-accent-foreground" + )} + onClick={() => handlePackageUnderFormClick(form, pkg)} + > + <FormInput className="mr-2 h-3 w-3" /> + {form.formName} + </Button> + ) + }) + )} + </div> + </> )} - onClick={() => onIMFormClick(form.formCode)} - > - <FileText className="mr-2 h-4 w-4" /> - {form.formName} - </Button> - ) - }) + </div> + )) + ) )} </div> </ScrollArea> |
