"use client"; import type { SidebarNavSection } from "@app/app/navigation"; import { OrgSelector } from "@app/components/OrgSelector"; import { SidebarNav } from "@app/components/SidebarNav"; import SupporterStatus from "@app/components/SupporterStatus"; import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@app/components/ui/tooltip"; import { useEnvContext } from "@app/hooks/useEnvContext"; import { useLicenseStatusContext } from "@app/hooks/useLicenseStatusContext"; import { useUserContext } from "@app/hooks/useUserContext"; import { cn } from "@app/lib/cn"; import { build } from "@server/build"; import { ListUserOrgsResponse } from "@server/routers/org"; import { ExternalLink, Server } from "lucide-react"; import { useTranslations } from "next-intl"; import dynamic from "next/dynamic"; import Link from "next/link"; import { usePathname } from "next/navigation"; import { useEffect, useState } from "react"; import { FaGithub } from "react-icons/fa"; import SidebarLicenseButton from "./SidebarLicenseButton"; import { SidebarSupportButton } from "./SidebarSupportButton"; const ProductUpdates = dynamic(() => import("./ProductUpdates"), { ssr: false }); interface LayoutSidebarProps { orgId?: string; orgs?: ListUserOrgsResponse["orgs"]; navItems: SidebarNavSection[]; defaultSidebarCollapsed: boolean; hasCookiePreference: boolean; } export function LayoutSidebar({ orgId, orgs = [], navItems, defaultSidebarCollapsed, hasCookiePreference }: LayoutSidebarProps) { const [isSidebarCollapsed, setIsSidebarCollapsed] = useState( defaultSidebarCollapsed ); const [hasManualToggle, setHasManualToggle] = useState(hasCookiePreference); const pathname = usePathname(); const isAdminPage = pathname?.startsWith("/admin"); const { user } = useUserContext(); const { isUnlocked } = useLicenseStatusContext(); const { env } = useEnvContext(); const t = useTranslations(); const setSidebarStateCookie = (collapsed: boolean) => { if (typeof window !== "undefined") { const isSecure = window.location.protocol === "https:"; document.cookie = `pangolin-sidebar-state=${collapsed ? "collapsed" : "expanded"}; path=/; max-age=${60 * 60 * 24 * 30}; samesite=lax${isSecure ? "; secure" : ""}`; } }; // Auto-collapse sidebar at 1650px or less, but only if no cookie preference exists useEffect(() => { if (hasManualToggle) { return; // Don't auto-collapse if user has manually toggled } const handleResize = () => { // print inner width if (typeof window !== "undefined") { const shouldCollapse = window.innerWidth <= 1650; setIsSidebarCollapsed(shouldCollapse); } }; // Set initial state based on window width handleResize(); window.addEventListener("resize", handleResize); return () => window.removeEventListener("resize", handleResize); }, [hasManualToggle]); function loadFooterLinks(): { text: string; href?: string }[] | undefined { if (!isUnlocked()) { return undefined; } if (env.branding.footer) { try { return JSON.parse(env.branding.footer); } catch (e) { console.error("Failed to parse BRANDING_FOOTER", e); } } } const currentOrg = orgs.find((org) => org.orgId === orgId); const canShowProductUpdates = user.serverAdmin || Boolean(currentOrg?.isOwner || currentOrg?.isAdmin); return (
{isSidebarCollapsed ? t("sidebarExpand") : t("sidebarCollapse")}