import { useCallback, useEffect, useMemo, useRef, useState } from "react"; import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import type { DocumentAnnotationComment, DocumentAnnotationThreadStatus, DocumentAnnotationThreadWithComments, } from "@paperclipai/shared"; import { Check, Copy, MoreHorizontal, RotateCcw, X, } from "lucide-react"; import { Button } from "@/components/ui/button"; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, } from "@/components/ui/dropdown-menu"; import { Sheet, SheetContent, SheetTitle } from "@/components/ui/sheet"; import { Textarea } from "@/components/ui/textarea"; import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"; import { cn, relativeTime } from "@/lib/utils"; import { documentAnnotationsApi, type DocumentAnnotationTarget } from "@/api/document-annotations"; import { authApi } from "@/api/auth"; import { queryKeys } from "@/lib/queryKeys"; import { AgentIcon } from "./AgentIconPicker"; import { deriveInitials } from "./Identity"; import { MarkdownBody } from "./MarkdownBody"; import type { PendingAnchor } from "./DocumentAnnotationLayer"; import type { Agent } from "@paperclipai/shared"; import type { CompanyUserProfile } from "@/lib/company-members"; export interface AnnotationPanelProps { open: boolean; onOpenChange: (open: boolean) => void; target?: DocumentAnnotationTarget; issueId?: string; documentKey: string; documentRevisionNumber: number; baseRevisionId: string | null; baseRevisionNumber: number; threads: DocumentAnnotationThreadWithComments[]; focusedThreadId: string | null; onFocusThread: (threadId: string | null) => void; focusedCommentId: string | null; /** External pending anchor captured from the layer for the composer. */ pendingAnchor: PendingAnchor | null; onClearPendingAnchor: () => void; /** Request the body layer to start a comment from the current text selection (⌘⇧M). */ onRequestCommentFromSelection?: () => void; newCommentDisabled?: boolean; newCommentDisabledReason?: string | null; /** When mobile is true, render via shadcn Sheet at the bottom instead of side panel. */ isMobile?: boolean; /** Desktop panel width calculated by the document frame. */ desktopWidth?: number; className?: string; /** Resolve `` to a display name. */ agentMap?: ReadonlyMap & Partial>>; /** Resolve `` to a display name. */ userProfileMap?: ReadonlyMap; } export function DocumentAnnotationPanel(props: AnnotationPanelProps) { if (props.isMobile) { return ( Comments on {props.documentKey} revision {props.documentRevisionNumber}