"use client"; import type { ComponentType } from "react"; import { CalendarDays, MessageCircle, ClipboardList, FileText, Home, LayoutGrid, MoreHorizontal, Presentation, Radar, Sparkles, UserPlus, Users, } from "lucide-react"; import { useParams, usePathname, useRouter } from "next/navigation"; import { Tooltip, TooltipContent, TooltipTrigger, } from "@/components/ui/tooltip"; import { useWorkspaceStore } from "@/lib/stores/workspace-store"; import { cn } from "@/lib/utils"; import { api } from "@/lib/trpc"; import { chatBadge } from "@/components/chat/chat-utils"; export interface IconRailProps { className?: string; } type NavItem = { id: string; label: string; segment: string; icon: ComponentType<{ className?: string }>; }; const NAV_ITEMS: NavItem[] = [ { id: "home", label: "Home", segment: "", icon: Home }, { id: "spaces", label: "Spaces", segment: "", icon: LayoutGrid }, { id: "planner", label: "Planner", segment: "planner", icon: CalendarDays }, { id: "mission-control", label: "Mission control", segment: "mission-control", icon: Radar, }, { id: "ai", label: "AI", segment: "ai", icon: Sparkles }, { id: "chat", label: "Chat", segment: "chat", icon: MessageCircle }, { id: "teams", label: "Teams", segment: "teams", icon: Users }, { id: "docs", label: "Docs", segment: "docs", icon: FileText }, { id: "whiteboards", label: "Whiteboards", segment: "whiteboards", icon: Presentation, }, { id: "forms", label: "Forms", segment: "forms", icon: ClipboardList }, ]; function workspaceHref(workspaceSegment: string, segment: string) { return segment ? `/${workspaceSegment}/${segment}` : `/${workspaceSegment}`; } const RESERVED_ROOT_SEGMENTS = new Set([ "planner", "mission-control", "ai", "chat", "teams", "docs", "whiteboards", "forms", ]); function isAtWorkspaceHome(pathname: string, prefix: string): boolean { const rest = pathname.slice(prefix.length).replace(/^\//, ""); const first = rest.split("/")[0] ?? ""; if (!first) return true; return !RESERVED_ROOT_SEGMENTS.has(first); } function isNavItemActive( pathname: string, workspaceSegment: string | undefined, item: NavItem, ): boolean { if (!workspaceSegment) return false; const prefix = `/${workspaceSegment}`; if (!pathname.startsWith(prefix)) return false; if (item.segment) { const next = pathname[prefix.length] === "/" ? pathname.slice(prefix.length + 1) : ""; const first = next.split("/")[0] ?? ""; return first === item.segment; } if (item.id === "home") { return isAtWorkspaceHome(pathname, prefix); } // Spaces uses the same URL as home for now; keep inactive here to avoid double highlight if (item.id === "spaces") { return false; } return false; } export function IconRail({ className }: IconRailProps) { const pathname = usePathname(); const router = useRouter(); const params = useParams(); const currentWorkspace = useWorkspaceStore((s) => s.currentWorkspace); const slugParam = typeof params?.workspaceSlug === "string" ? params.workspaceSlug : ""; const workspaceSegment = currentWorkspace?.slug || currentWorkspace?.id || slugParam || undefined; const workspaceName = currentWorkspace?.name ?? ""; const unread = api.chat.unreadSummary.useQuery( { workspace: workspaceSegment ?? "" }, { enabled: !!workspaceSegment, refetchInterval: 15000 }, ); const visibleChannels = api.chat.listChannels.useQuery( { workspace: workspaceSegment ?? "" }, { enabled: !!workspaceSegment, refetchInterval: 15000 }, ); const directIds = new Set( visibleChannels.data ?.filter((channel) => channel.kind === "direct") .map((channel) => channel.id), ); const badge = chatBadge({ unreadCount: unread.data?.channels.reduce( (total, channel) => total + channel.unreadCount, 0, ) ?? 0, mentionCount: unread.data?.channels.reduce( (total, channel) => total + channel.mentionCount, 0, ) ?? 0, directUnreadCount: unread.data?.channels.reduce( (total, channel) => total + (directIds.has(channel.channelId) ? channel.unreadCount : 0), 0, ) ?? 0, }); const initials = workspaceName.trim().slice(0, 2).toUpperCase() || "—"; const push = (segment: string) => { if (!workspaceSegment) return; router.push(workspaceHref(workspaceSegment, segment)); }; return ( ); }