"use client" import { useAuth } from "@lib/auth-context" import { cn } from "@lib/utils" import { Button } from "@ui/components/button" import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuTrigger, } from "@ui/components/dropdown-menu" import { Tooltip, TooltipContent, TooltipTrigger } from "@ui/components/tooltip" import { useIsMobile } from "@hooks/use-mobile" import { useQuery } from "@tanstack/react-query" import { Building2, Code2, ExternalLink, Home, LifeBuoy, LayoutGrid, MenuIcon, Plus, SearchIcon, Settings, Settings2, UserPlus, ChevronRight, Sun, } from "lucide-react" import Link from "next/link" import { useQueryState } from "nuqs" import { useCallback } from "react" import { DomainLogo } from "@/components/onboarding-brain/step-about" import { FeedbackModal } from "@/components/feedback-modal" import { OrgPlanBadge, resolveOrgPlan } from "@/components/org-plan-badge" import { SlackMark } from "@/components/brain-connector-icons" import { BrainTrialPill } from "@/components/brain-trial-pill" import { GraphIcon } from "@/components/integration-icons" import { SpaceSelector } from "@/components/space-selector" import { UserProfileMenu } from "@/components/user-profile-menu" import { useTokenUsage } from "@/hooks/use-token-usage" import { useOrgSummaries } from "@/hooks/use-org-summaries" import { getBrainWorkspaceDomain } from "@/lib/billing-utils" import { dmSansClassName } from "@/lib/fonts" import { useViewMode } from "@/lib/view-mode-context" import { feedbackParam } from "@/lib/search-params" import { useSettingsModal } from "@/components/settings/settings-modal" import { useProject } from "@/stores" import { useCustomer } from "autumn-js/react" const BACKEND = process.env.NEXT_PUBLIC_BACKEND_URL ?? "https://api.supermemory.ai" type SlackStatus = { connected: boolean; teamName: string | null } interface CompanyBrainHeaderProps { onAddMemory?: () => void onOpenSearch?: () => void } const brainItemClass = (active: boolean) => cn( "gap-2.5 rounded-lg px-2 py-1.5 text-sm font-medium cursor-pointer transition-colors", "hover:bg-white/[0.06] focus:bg-white/[0.06] focus:text-white", active ? "bg-white/[0.06] text-white" : "text-white/85", ) const brainTileClass = (active: boolean) => cn( "flex size-7 shrink-0 items-center justify-center rounded-lg border text-[11px] font-semibold", active ? "border-[#2261CA66] bg-[#0B2A57] text-[#7EB0FF]" : "border-white/[0.08] bg-white/[0.04] text-white/70", ) const menuItemClass = "gap-2.5 rounded-lg px-2.5 py-2 text-sm font-medium text-white/85 hover:bg-white/[0.06] focus:bg-white/[0.06] focus:text-white cursor-pointer" const circleNavClass = (active: boolean) => cn( "flex size-10 shrink-0 cursor-pointer items-center justify-center rounded-full border transition-colors", active ? "border-[#2261CA33] bg-[#00173C] text-white" : "border-[#161F2C] bg-muted text-muted-foreground hover:bg-white/5", dmSansClassName(), ) const tabClass = (active: boolean) => cn( "inline-flex h-[calc(100%-1px)] min-h-0 cursor-pointer snap-start items-center justify-center gap-1 rounded-full border border-transparent px-2.5 text-xs font-medium whitespace-nowrap transition-colors sm:gap-1.5 sm:px-3 sm:text-sm", active ? "border-[#2261CA33] bg-[#00173C] text-white" : "text-foreground hover:bg-white/5", dmSansClassName(), ) function useSlackStatus() { return useQuery({ queryKey: ["brain-slack-status"], queryFn: async (): Promise => { const res = await fetch(`${BACKEND}/brain/slack/status`, { credentials: "include", }) if (!res.ok) return { connected: false, teamName: null } return (await res.json()) as SlackStatus }, staleTime: 30_000, }) } export function CompanyBrainHeader({ onAddMemory, onOpenSearch, }: CompanyBrainHeaderProps) { const { user, org, organizations, setActiveOrg } = useAuth() const autumn = useCustomer() const { currentPlan } = useTokenUsage(autumn) const { data: orgSummaries } = useOrgSummaries() const { viewMode, setViewMode } = useViewMode() const { selectedProjects, setSelectedProjects } = useProject() const { openSettings } = useSettingsModal() const isMobile = useIsMobile() const [feedbackOpen, setFeedbackOpen] = useQueryState( "feedback", feedbackParam, ) const [, setInvite] = useQueryState("invite") const { data: slackStatus } = useSlackStatus() const planByOrgId = new Map( (orgSummaries ?? []).map((s) => [s.orgId, s.plan] as const), ) const orgLabel = org?.name.replace(/\s*organizations?\s*$/i, "").trim() const brandLabel = orgLabel || "Workspace" const domain = getBrainWorkspaceDomain( org?.metadata as Record | string | null | undefined, ) const hasOrgs = (organizations?.length ?? 0) > 0 const memberRole = org?.members ?.find((m) => m.userId === user?.id) ?.role?.toLowerCase() const canInvite = memberRole === "owner" || memberRole === "admin" const isOverview = viewMode === "dashboard" const isGraph = viewMode === "graph" const isMemories = viewMode === "list" const isConfigure = viewMode === "configure" const slackConnected = slackStatus?.connected ?? false const selectOrg = useCallback( (slug: string, isActive: boolean) => { if (isActive) return void setActiveOrg(slug).then(() => window.location.reload()) }, [setActiveOrg], ) const goOverview = useCallback(() => { void setViewMode("dashboard") }, [setViewMode]) const goGraph = useCallback(() => { void setViewMode("graph") }, [setViewMode]) const goMemories = useCallback(() => { void setViewMode("list") }, [setViewMode]) const goConfigure = useCallback(() => { void setViewMode("configure") }, [setViewMode]) const goIntegrations = useCallback(() => { void setViewMode("integrations") }, [setViewMode]) const handleInvite = useCallback(() => { setInvite("1") openSettings("account") }, [openSettings, setInvite]) const handleFeedback = useCallback(() => { void setFeedbackOpen(true) }, [setFeedbackOpen]) return (
{hasOrgs && ( <>

Switch brain

{organizations?.map((o) => { const active = org?.id === o.id const plan = resolveOrgPlan( o.id, active, currentPlan, planByOrgId, ) return ( selectOrg(o.slug, active)} className={cn(brainItemClass(active))} > {o.name?.trim().charAt(0).toUpperCase() || "?"} {o.name} ) })}
)} Home Configure Integrations openSettings()} className={menuItemClass} > Settings Developer console supermemory.ai
{!isMobile && ( <> )}
{!isMobile && (
Overview
)}
{isMobile ? ( <> {onAddMemory && ( <> Add memory )} Overview Graph Memories Configure Integrations {slackConnected ? ( Slack connected ) : ( Add to Slack )} {canInvite && ( Invite teammates )} Search Feedback openSettings()} className={menuItemClass} > Settings ) : ( <> {onAddMemory && ( Add memory (C) )} {canInvite && ( Invite teammates )} Search (⌘K) )}
setFeedbackOpen(false)} />
) } function SlackNavButton({ connected, teamName, active, onManage, }: { connected: boolean teamName: string | null active: boolean onManage: () => void }) { const label = connected ? `Slack${teamName ? ` · ${teamName}` : ""}` : "Add to Slack" if (!connected) { return ( Add to Slack ) } return ( {label} ) }