import { useEffect, useLayoutEffect, useState, useRef, useCallback, useMemo, } from "react"; import { useQuery, useQueryClient } from "@tanstack/react-query"; import { useCompany } from "../context/CompanyContext"; import { useBreadcrumbs } from "../context/BreadcrumbContext"; import { useDialogState } from "../context/DialogContext"; import { agentsApi } from "../api/agents"; import { issuesApi } from "../api/issues"; import { goalsApi } from "../api/goals"; import { queryKeys } from "../lib/queryKeys"; import { MarkdownBody } from "../components/MarkdownBody"; import { Button } from "@/components/ui/button"; import { Avatar, AvatarFallback } from "@/components/ui/avatar"; import { Tooltip, TooltipContent, TooltipTrigger, } from "@/components/ui/tooltip"; import { Activity, ArrowDown, History, MessageSquarePlus, X } from "lucide-react"; import { ActivityFeed } from "../components/ActivityFeed"; import { ChatComposer, type ChatComposerHandle } from "../components/ChatComposer"; import { AgentBubbleActionRow, agentBubbleDateLabel, } from "../components/AgentBubbleActionRow"; import { AgentIcon } from "../components/AgentIconPicker"; import { cn, formatDateTime } from "../lib/utils"; import type { FeedbackVoteValue } from "@paperclipai/shared"; import { Sheet, SheetContent, SheetTrigger } from "@/components/ui/sheet"; /** * Board Concierge Chat — a chat interface powered by the board-member skill. * Uses /board/chat/stream to invoke Claude with the board skill as system prompt. * The user manages their Paperclip company through natural conversation. */ /** Hit zone to the right of the 1px line (line sits on chat pane’s right edge). */ const SPLIT_DIVIDER_PX = 12; const SPLIT_MIN_PANE_PX = 280; /** Chat pane share of width below the divider (agent feed gets the rest). */ const DEFAULT_CHAT_FRACTION = 2 / 3; /** Wrapped markdown in bubbles; pre/table scroll horizontally when needed. */ const BOARD_CHAT_MARKDOWN_CLASS = "max-w-full overflow-visible [&>*:first-child]:mt-0 [&>*:last-child]:mb-0 [&_pre]:max-w-full [&_pre]:overflow-x-auto [&_table]:block [&_table]:max-w-full [&_table]:overflow-x-auto"; const boardChatBubbleShell = "min-w-0 max-w-[85%] break-words px-3 py-2 text-sm overflow-x-auto overflow-y-visible"; /** First-letter(s) fallback for an agent with no icon. */ function agentInitials(name: string): string { const parts = name.trim().split(/\s+/); return (((parts[0]?.[0] ?? "") + (parts[1]?.[0] ?? "")).toUpperCase()) || "A"; } /** * Icon-adjacent-to-name header rendered directly above an agent bubble — * the shared `[agent icon][agent name]` convention (PAP-105 / PAP-97). */ function AgentBubbleHeader({ name, icon }: { name: string; icon: string | null }) { return (
Select a company to start chatting with your board concierge.
{selectedCompany?.name ?? "Your company"}