"use client"; import React, { useState } from "react"; import Link from "next/link"; import { useParams, usePathname } from "next/navigation"; import { cn } from "@app/lib/cn"; import { Badge } from "@app/components/ui/badge"; import { useLicenseStatusContext } from "@app/hooks/useLicenseStatusContext"; import { useTranslations } from "next-intl"; export type TabItem = { title: string; href: string; icon?: React.ReactNode; showProfessional?: boolean; exact?: boolean; }; interface HorizontalTabsProps { children: React.ReactNode; items: TabItem[]; disabled?: boolean; clientSide?: boolean; defaultTab?: number; } export function HorizontalTabs({ children, items, disabled = false, clientSide = false, defaultTab = 0 }: HorizontalTabsProps) { const pathname = usePathname(); const params = useParams(); const { licenseStatus, isUnlocked } = useLicenseStatusContext(); const t = useTranslations(); const [activeClientTab, setActiveClientTab] = useState(defaultTab); function hydrateHref(href: string) { return href .replace("{orgId}", params.orgId as string) .replace("{resourceId}", params.resourceId as string) .replace("{niceId}", params.niceId as string) .replace("{userId}", params.userId as string) .replace("{clientId}", params.clientId as string) .replace("{apiKeyId}", params.apiKeyId as string) .replace("{remoteExitNodeId}", params.remoteExitNodeId as string); } // Client-side mode: render tabs as buttons with state management if (clientSide) { const childrenArray = React.Children.toArray(children); const activeChild = childrenArray[activeClientTab] || null; return (
{items.map((item, index) => { const isActive = activeClientTab === index; const isProfessional = item.showProfessional && !isUnlocked(); const isDisabled = disabled || (isProfessional && !isUnlocked()); return ( ); })}
{activeChild}
); } // Server-side mode: original behavior with routing return (
{items.map((item) => { const hydratedHref = hydrateHref(item.href); const isActive = (item.exact ? pathname === hydratedHref : pathname.startsWith(hydratedHref)) && !pathname.includes("create"); const isProfessional = item.showProfessional && !isUnlocked(); const isDisabled = disabled || (isProfessional && !isUnlocked()); return ( { if (isDisabled) { e.preventDefault(); } }} tabIndex={isDisabled ? -1 : undefined} aria-disabled={isDisabled} >
{item.icon && item.icon} {item.title} {isProfessional && ( {t("licenseBadge")} )}
); })}
{children}
); }