diff options
Diffstat (limited to 'components/vendor-data/sidebar.tsx')
| -rw-r--r-- | components/vendor-data/sidebar.tsx | 235 |
1 files changed, 235 insertions, 0 deletions
diff --git a/components/vendor-data/sidebar.tsx b/components/vendor-data/sidebar.tsx new file mode 100644 index 00000000..b9e14b65 --- /dev/null +++ b/components/vendor-data/sidebar.tsx @@ -0,0 +1,235 @@ +"use client" + +import * as React from "react" +import { cn } from "@/lib/utils" +import { Button } from "@/components/ui/button" +import { ScrollArea } from "@/components/ui/scroll-area" +import { Separator } from "@/components/ui/separator" +import { + Tooltip, + TooltipTrigger, + TooltipContent, +} from "@/components/ui/tooltip" +import { Package2, FormInput } from "lucide-react" +import { useRouter, usePathname } from "next/navigation" +import { Skeleton } from "@/components/ui/skeleton" +import { type FormInfo } from "@/lib/forms/services" + +interface PackageData { + itemId: number + itemName: string +} + +interface SidebarProps extends React.HTMLAttributes<HTMLDivElement> { + isCollapsed: boolean + packages: PackageData[] + selectedPackageId: number | null + onSelectPackage: (itemId: number) => void + forms: FormInfo[] + selectedForm: string | null + onSelectForm: (formName: string) => void + isLoadingForms?: boolean +} + +export function Sidebar({ + className, + isCollapsed, + packages, + selectedPackageId, + onSelectPackage, + forms, + selectedForm, + onSelectForm, + isLoadingForms = false, +}: SidebarProps) { + const router = useRouter() + const pathname = usePathname() + + /** + * --------------------------- + * 1) URL에서 현재 패키지 / 폼 코드 추출 + * --------------------------- + */ + const segments = pathname.split("/").filter(Boolean) + // 예) "/partners/vendor-data/tag/123" => ["partners","vendor-data","tag","123"] + + let currentItemId: number | null = null + let currentFormCode: string | null = null + + const tagIndex = segments.indexOf("tag") + if (tagIndex !== -1 && segments[tagIndex + 1]) { + // tag 뒤에 오는 값이 패키지 itemId + currentItemId = parseInt(segments[tagIndex + 1], 10) + } + + const formIndex = segments.indexOf("form") + if (formIndex !== -1) { + // form 뒤 첫 파라미터 => itemId, 그 다음 파라미터 => formCode + const itemSegment = segments[formIndex + 1] + const codeSegment = segments[formIndex + 2] + + if (itemSegment) { + currentItemId = parseInt(itemSegment, 10) + } + if (codeSegment) { + currentFormCode = codeSegment + } + } + + /** + * --------------------------- + * 2) 패키지 클릭 핸들러 + * --------------------------- + */ + const handlePackageClick = (itemId: number) => { + // 상위 컴포넌트 상태 업데이트 + onSelectPackage(itemId) + + // 해당 태그 페이지로 라우팅 + // 예: /vendor-data/tag/123 + const baseSegments = segments.slice(0, segments.indexOf("vendor-data") + 1).join("/") + router.push(`/${baseSegments}/tag/${itemId}`) + } + + /** + * --------------------------- + * 3) 폼 클릭 핸들러 + * --------------------------- + */ + const handleFormClick = (form: FormInfo) => { + // 패키지가 선택되어 있을 때만 동작 + if (selectedPackageId === null) return + + // 상위 컴포넌트 상태 업데이트 + onSelectForm(form.formName) + + // 해당 폼 페이지로 라우팅 + // 예: /vendor-data/form/[packageId]/[formCode] + + const baseSegments = segments.slice(0, segments.indexOf("vendor-data") + 1).join("/") + + router.push(`/${baseSegments}/form/${selectedPackageId}/${form.formCode}`) + } + + return ( + <div className={cn("pb-12", className)}> + <div className="space-y-4 py-4"> + {/* ---------- 패키지(Items) 목록 ---------- */} + <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) => { + // URL 기준으로 active 여부 판단 + const isActive = pkg.itemId === currentItemId + + 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 /> + + {/* ---------- 폼 목록 ---------- */} + <div className="py-1"> + <h2 className="relative px-7 text-lg font-semibold tracking-tight"> + {isCollapsed ? "F" : "Form Lists"} + </h2> + <ScrollArea className="h-[300px] px-1"> + <div className="space-y-1 p-2"> + {isLoadingForms ? ( + // 로딩 중 스켈레톤 UI 표시 + Array.from({ length: 3 }).map((_, index) => ( + <div key={`form-skeleton-${index}`} className="px-2 py-1.5"> + <Skeleton className="h-8 w-full" /> + </div> + )) + ) : forms.length === 0 ? ( + <p className="text-sm text-muted-foreground px-2"> + (No forms loaded) + </p> + ) : ( + forms.map((form) => { + // URL 기준으로 active 여부 판단 + const isActive = 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={() => handleFormClick(form)} + disabled={currentItemId === null} + > + <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", + isActive && "bg-accent text-accent-foreground" + )} + onClick={() => handleFormClick(form)} + disabled={currentItemId === null} + > + <FormInput className="mr-2 h-4 w-4" /> + {form.formName} + </Button> + ) + }) + )} + </div> + </ScrollArea> + </div> + </div> + </div> + ) +}
\ No newline at end of file |
