diff options
| author | dujinkim <dujin.kim@dtsolution.co.kr> | 2025-12-01 00:58:23 +0000 |
|---|---|---|
| committer | dujinkim <dujin.kim@dtsolution.co.kr> | 2025-12-01 00:58:23 +0000 |
| commit | 8440ac29c7dcbef992039678ecc0fabff2fd04ec (patch) | |
| tree | 59092b8dcd22135009bf70d5863ffde444e5bed2 /components/vendor-data-plant/sidebar.tsx | |
| parent | 748f68bb7b5d02450664651ae5025c9a38fb71a5 (diff) | |
(대표님) S-EDP 관련 대표님 작업사항
Diffstat (limited to 'components/vendor-data-plant/sidebar.tsx')
| -rw-r--r-- | components/vendor-data-plant/sidebar.tsx | 479 |
1 files changed, 220 insertions, 259 deletions
diff --git a/components/vendor-data-plant/sidebar.tsx b/components/vendor-data-plant/sidebar.tsx index 31ee6dc7..b746e69d 100644 --- a/components/vendor-data-plant/sidebar.tsx +++ b/components/vendor-data-plant/sidebar.tsx @@ -10,304 +10,265 @@ import { TooltipTrigger, TooltipContent, } from "@/components/ui/tooltip" -import { Package2, FormInput } from "lucide-react" -import { useRouter, usePathname } from "next/navigation" +import { List, FormInput, FileText } from "lucide-react" import { Skeleton } from "@/components/ui/skeleton" -import { type FormInfo } from "@/lib/forms/services" +import { getEngineeringForms, getIMForms } from "@/lib/tags-plant/service" -interface PackageData { - itemId: number - itemName: string +interface FormInfo { + formCode: string + formName: string } interface SidebarProps extends React.HTMLAttributes<HTMLDivElement> { isCollapsed: boolean - 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" + selectedPackageCode: string | null + selectedFormCode: string | null + currentMode: "master" | "engineering" | "im" | null + projectCode: string // 추가 + onMasterTagListClick: () => void + onEngineeringFormClick: (formCode: string) => void + onIMFormClick: (formCode: string) => void } export function Sidebar({ className, isCollapsed, - packages, - selectedPackageId, - selectedProjectId, - selectedContractId, - onSelectPackage, - forms, - onSelectForm, - isLoadingForms = false, - mode = "IM", + selectedPackageCode, + selectedFormCode, + currentMode, + projectCode, // 추가 + onMasterTagListClick, + onEngineeringFormClick, + onIMFormClick, }: SidebarProps) { - const router = useRouter() - const rawPathname = usePathname() - const pathname = rawPathname ?? "" + const [engineeringForms, setEngineeringForms] = React.useState<FormInfo[]>([]) + const [imForms, setIMForms] = React.useState<FormInfo[]>([]) + const [isLoadingEngineering, setIsLoadingEngineering] = React.useState(false) + const [isLoadingIM, setIsLoadingIM] = React.useState(false) - /** - * --------------------------- - * 1) URL에서 현재 패키지 / 폼 코드 추출 - * --------------------------- - */ - const segments = pathname.split("/").filter(Boolean) - - let currentItemId: number | null = null - let currentFormCode: string | null = null + // Engineering 폼 로드 + React.useEffect(() => { + if (!selectedPackageCode || !projectCode) { + setEngineeringForms([]) + return + } - const tagIndex = segments.indexOf("tag") - if (tagIndex !== -1 && segments[tagIndex + 1]) { - currentItemId = parseInt(segments[tagIndex + 1], 10) - } + const loadEngineeringForms = async () => { + setIsLoadingEngineering(true) + try { + const result = await getEngineeringForms(projectCode, selectedPackageCode) + setEngineeringForms(result) + } catch (error) { + console.error("Engineering 폼 로딩 오류:", error) + setEngineeringForms([]) + } finally { + setIsLoadingEngineering(false) + } + } - const formIndex = segments.indexOf("form") - if (formIndex !== -1) { - const itemSegment = segments[formIndex + 1] - const codeSegment = segments[formIndex + 2] + loadEngineeringForms() + }, [selectedPackageCode, projectCode]) - if (itemSegment) { - currentItemId = parseInt(itemSegment, 10) - } - if (codeSegment) { - currentFormCode = codeSegment + // IM 폼 로드 + React.useEffect(() => { + if (!selectedPackageCode || !projectCode) { + setIMForms([]) + return } - } - /** - * --------------------------- - * 2) 패키지 클릭 핸들러 (IM 모드) - * --------------------------- - */ - const handlePackageClick = (itemId: number) => { - // 상위 컴포넌트 상태 업데이트 - onSelectPackage(itemId) - - // 해당 태그 페이지로 라우팅 - // 예: /vendor-data-plant/tag/123 - const baseSegments = segments.slice(0, segments.indexOf("vendor-data-plant") + 1).join("/") - router.push(`/${baseSegments}/tag/${itemId}`) - } + const loadIMForms = async () => { + setIsLoadingIM(true) + try { + const result = await getIMForms(projectCode, selectedPackageCode) + setIMForms(result) + } catch (error) { + console.error("IM 폼 로딩 오류:", error) + setIMForms([]) + } finally { + setIsLoadingIM(false) + } + } - /** - * --------------------------- - * 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}`) - } + loadIMForms() + }, [selectedPackageCode, projectCode]) - /** - * --------------------------- - * 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}`) - } + const isMasterActive = currentMode === "master" + const isPackageSelected = selectedPackageCode !== null return ( <div className={cn("pb-12", className)}> <div className="space-y-4 py-4"> - {/* ---------- 패키지(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 + {/* 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> - 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 /> - </> - )} + <Separator /> - {/* ---------- 폼 목록 (IM 모드) / 패키지와 폼 목록 (ENG 모드) ---------- */} + {/* Engineering Forms */} <div className="py-1"> <h2 className="relative px-7 text-lg font-semibold tracking-tight"> - {isCollapsed - ? (mode === "IM" ? "F" : "P") - : (mode === "IM" ? "Form Lists" : "Package Lists") - } + {isCollapsed ? "E" : "Engineering"} </h2> - <ScrollArea className={cn( - "px-1", - mode === "IM" ? "h-[300px]" : "h-[450px]" - )}> + <ScrollArea className="h-[250px] px-1"> <div className="space-y-1 p-2"> - {isLoadingForms ? ( + {isLoadingEngineering ? ( Array.from({ length: 3 }).map((_, index) => ( - <div key={`form-skeleton-${index}`} className="px-2 py-1.5"> + <div key={`eng-skeleton-${index}`} className="px-2 py-1.5"> <Skeleton className="h-8 w-full" /> </div> )) - ) : 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 + ) : !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 - 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" /> + 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"> {form.formName} - </Button> - ) - }) - ) + </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> ) : ( - // =========== 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 + imForms.map((form) => { + const isActive = + currentMode === "im" && + form.formCode === selectedFormCode - 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> - </> + 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" )} - </div> - )) - ) + onClick={() => onIMFormClick(form.formCode)} + > + <FileText className="mr-2 h-4 w-4" /> + {form.formName} + </Button> + ) + }) )} </div> </ScrollArea> |
