"use client"; import type { Team } from "@stackframe/stack"; import { Brain, ChevronLeft, ChevronRight, CircleDollarSign, Database, FileText, Home, Key, LogOut, Megaphone, MessageSquare, Phone, Settings, Star, TrendingUp, Workflow, Wrench, Zap, } from "lucide-react"; import Link from "next/link"; import { usePathname, useRouter } from "next/navigation"; import React, { useRef } from "react"; import ThemeToggle from "@/components/ThemeSwitcher"; import { Button } from "@/components/ui/button"; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger, } from "@/components/ui/dropdown-menu"; import { Sidebar, SidebarContent, SidebarFooter, SidebarGroup, SidebarGroupLabel, SidebarHeader, SidebarMenu, SidebarMenuButton, SidebarMenuItem, SidebarRail, SidebarTrigger, useSidebar, } from "@/components/ui/sidebar"; import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, } from "@/components/ui/tooltip"; import { useAppConfig } from "@/context/AppConfigContext"; import type { LocalUser } from "@/lib/auth"; import { useAuth } from "@/lib/auth"; import { cn } from "@/lib/utils"; // Lazy load SelectedTeamSwitcher - we'll pass selectedTeam from our context const StackTeamSwitcher = React.lazy(() => import("@stackframe/stack").then((mod) => ({ default: mod.SelectedTeamSwitcher, })) ); export function AppSidebar() { const pathname = usePathname(); const router = useRouter(); const { state, isMobile, setOpenMobile } = useSidebar(); const { provider, getSelectedTeam, logout, user } = useAuth(); const { config } = useAppConfig(); // Get selected team for Stack auth (cast to Team type from Stack) // Stabilize the reference so SelectedTeamSwitcher only sees a change when the team ID changes, // preventing unnecessary PATCH calls to Stack Auth on every route navigation. const selectedTeamRef = useRef(null); const rawSelectedTeam = provider === "stack" && getSelectedTeam ? getSelectedTeam() as Team | null : null; if (rawSelectedTeam?.id !== selectedTeamRef.current?.id) { selectedTeamRef.current = rawSelectedTeam; } const selectedTeam = selectedTeamRef.current; // Version info from app config context const versionInfo = config ? { ui: config.uiVersion, api: config.apiVersion } : null; const isActive = (path: string) => { return pathname.startsWith(path); }; // Organize navigation into sections const overviewSection = [ { title: "Overview", url: "/overview", icon: Home, }, ]; const buildSection = [ { title: "Voice Agents", url: "/workflow", icon: Workflow, }, { title: "Campaigns", url: "/campaigns", icon: Megaphone, }, { title: "Automation", url: "/automation", icon: Zap, }, { title: "Models", url: "/model-configurations", icon: Brain, }, { title: "Telephony", url: "/telephony-configurations", icon: Phone, }, { title: "Tools", url: "/tools", icon: Wrench, }, { title: "Files", url: "/files", icon: Database, }, // { // title: "Integrations", // url: "/integrations", // icon: Plug, // }, { title: "Developers", url: "/api-keys", icon: Key, }, ]; const observeSection = [ { title: "Usage", url: "/usage", icon: TrendingUp, }, { title: "Reports", url: "/reports", icon: FileText, }, { title: "LoopTalk", url: "/looptalk", icon: MessageSquare, }, ]; const handleMobileNavClick = () => { if (isMobile) { setOpenMobile(false); } }; const SidebarLink = ({ item }: { item: typeof overviewSection[0] }) => { const isItemActive = isActive(item.url); const Icon = item.icon; if (state === "collapsed") { return ( {item.title}

{item.title}

); } return ( {item.title} ); }; return (
{/* Logo - only show when expanded */} {state === "expanded" && ( Dograh {versionInfo && ( v{versionInfo.ui} )} )} {/* Toggle button - center it when collapsed */} {state === "expanded" ? ( ) : ( )}
{/* Team Switcher for Stack Auth - at the top */} {provider === "stack" && state === "expanded" && (
} > { router.refresh(); }} />
)} {/* Star us on GitHub for OSS mode - at the top */} {provider !== "stack" && (
{state === "collapsed" ? (

Star us on GitHub

) : ( )}
)}
{/* Overview Section */} {overviewSection.map((item) => ( ))} {/* BUILD Section */} {buildSection.length > 0 && ( {state === "expanded" && ( BUILD )} {buildSection.map((item) => ( ))} )} {/* OBSERVE Section */} {state === "expanded" && ( OBSERVE )} {observeSection.map((item) => ( ))} {/* Bottom Actions */}
{/* User Button - for local/OSS mode */} {provider !== "stack" && (
{(user as LocalUser | undefined)?.email && (

{(user as LocalUser).email}

)}
logout()} className="cursor-pointer"> Sign out
)} {/* User Button - for Stack auth */} {provider === "stack" && (
{user?.displayName && (

{user.displayName}

)} {(user as { primaryEmail?: string })?.primaryEmail && (

{(user as { primaryEmail?: string }).primaryEmail}

)}
router.push("/handler/account-settings")} className="cursor-pointer"> Account settings router.push("/usage")} className="cursor-pointer"> Usage logout()} className="cursor-pointer"> Sign out
)} {/* Theme Toggle - at the very bottom */}
{state === "collapsed" ? (

Toggle theme

) : ( )}
); }