import { useCallback, useEffect, useMemo, useRef, useState } from "react"; import { useMutation, 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 { Badge } from "@/components/ui/badge"; 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 { cn, relativeTime } from "@/lib/utils"; import { documentAnnotationsApi } from "@/api/document-annotations"; import { MarkdownBody } from "./MarkdownBody"; import type { PendingAnchor } from "./DocumentAnnotationLayer"; import type { Agent } from "@paperclipai/shared"; import type { CompanyUserProfile } from "@/lib/company-members"; type AnnotationFilter = "open" | "resolved" | "stale" | "orphan"; const FILTERS: { id: AnnotationFilter; label: string }[] = [ { id: "open", label: "Open" }, { id: "resolved", label: "Resolved" }, { id: "stale", label: "Stale" }, { id: "orphan", label: "Orphaned" }, ]; export interface AnnotationPanelProps { open: boolean; onOpenChange: (open: boolean) => void; 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>; /** Resolve `` to a display name. */ userProfileMap?: ReadonlyMap; } export function DocumentAnnotationPanel(props: AnnotationPanelProps) { if (props.isMobile) { return ( Comments on {props.documentKey} revision {props.documentRevisionNumber}