"use client"; import Link from "next/link"; import { usePathname } from "next/navigation"; import type { ReactNode } from "react"; import { Activity, BarChart3, Bot, Boxes, Building2, CheckCircle2, CircleDot, FolderGit, LayoutGrid, Network, Settings, Store, TerminalSquare, } from "lucide-react"; import { ApiError } from "@/api/mutator"; import { type healthzHealthzGetResponse, useHealthzHealthzGet, } from "@/api/generated/default/default"; import { useAuth } from "@/auth/clerk"; import { useOrganizationMembership } from "@/lib/use-organization-membership"; import { cn } from "@/lib/utils"; type NavTone = "blue" | "cyan" | "emerald" | "violet" | "amber" | "rose"; const iconToneClass: Record = { blue: "bg-blue-500/15 text-blue-300 ring-blue-400/20", cyan: "bg-cyan-500/15 text-cyan-300 ring-cyan-400/20", emerald: "bg-emerald-500/15 text-emerald-300 ring-emerald-400/20", violet: "bg-violet-500/15 text-violet-300 ring-violet-400/20", amber: "bg-amber-500/15 text-amber-300 ring-amber-400/20", rose: "bg-rose-500/15 text-rose-300 ring-rose-400/20", }; const sectionHeaderClass = "px-3 text-[13px] font-bold uppercase tracking-[0.18em] text-[color:var(--text)]"; const navItemClass = (active: boolean) => cn( "group relative flex items-center gap-3 rounded-lg px-3 py-2.5 text-[15px] font-semibold text-[color:var(--text-muted)] transition duration-200", "before:absolute before:inset-y-2 before:left-0 before:w-1 before:rounded-full before:bg-transparent before:transition", active ? "bg-[color:var(--accent-soft)] text-[color:var(--text)] shadow-sm before:bg-[color:var(--accent)]" : "hover:bg-[color:var(--surface-muted)] hover:text-[color:var(--text)] hover:before:bg-[color:var(--border-strong)]", "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[color:var(--accent)] focus-visible:ring-offset-2 focus-visible:ring-offset-[color:var(--surface)]", ); const iconClass = (active: boolean, tone: NavTone) => cn( "flex h-8 w-8 shrink-0 items-center justify-center rounded-md ring-1 transition duration-200", iconToneClass[tone], active && "bg-[color:var(--accent)] text-[color:var(--primary-foreground)] ring-[color:var(--accent)]", !active && "group-hover:scale-105 group-hover:ring-[color:var(--accent)]", ); function isNavActive(pathname: string, href: string) { if (href === "/boards") { return ( pathname === href || pathname.startsWith("/boards/") || pathname.startsWith("/board-groups") ); } if (href === "/git-projects") { return ( pathname === href || pathname.startsWith("/git-projects/connections") || pathname.startsWith("/git-projects/repositories") ); } if (href === "/settings") { return ( pathname === href || pathname.startsWith("/settings/") || pathname.startsWith("/tags") || pathname.startsWith("/custom-fields") ); } return pathname === href || pathname.startsWith(`${href}/`); } function NavItem({ href, label, icon, tone, active, }: { href: string; label: string; icon: ReactNode; tone: NavTone; active: boolean; }) { return ( {icon} {label} ); } export function DashboardSidebar() { const pathname = usePathname(); const { isSignedIn } = useAuth(); const { isAdmin } = useOrganizationMembership(isSignedIn); const healthQuery = useHealthzHealthzGet( { query: { refetchInterval: 30_000, refetchOnMount: "always", retry: false, }, request: { cache: "no-store" }, }, ); const okValue = healthQuery.data?.data?.ok; const systemStatus: "unknown" | "operational" | "degraded" = okValue === true ? "operational" : okValue === false ? "degraded" : healthQuery.isError ? "degraded" : "unknown"; const statusLabel = systemStatus === "operational" ? "All systems operational" : systemStatus === "unknown" ? "System status unavailable" : "System degraded"; const isActive = (href: string) => isNavActive(pathname, href); return ( ); }