"use client"; import { ChevronDown, ChevronUp, ExternalLink, Loader2 } from "lucide-react"; import type React from "react"; import { type ReactNode, useEffect, useRef, useState } from "react"; import { MarkdownViewer } from "@/components/markdown-viewer"; import { Button } from "@/components/ui/button"; import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "@/components/ui/collapsible"; import { ScrollArea } from "@/components/ui/scroll-area"; import { Sheet, SheetContent, SheetDescription, SheetHeader, SheetTitle, } from "@/components/ui/sheet"; import { getConnectorIcon } from "@/contracts/enums/connectorIcons"; import { useDocumentByChunk } from "@/hooks/use-document-by-chunk"; import { cn } from "@/lib/utils"; interface SourceDetailSheetProps { open: boolean; onOpenChange: (open: boolean) => void; chunkId: number; sourceType: string; title: string; description?: string; url?: string; children?: ReactNode; } const formatDocumentType = (type: string) => { return type .split("_") .map((word) => word.charAt(0) + word.slice(1).toLowerCase()) .join(" "); }; export function SourceDetailSheet({ open, onOpenChange, chunkId, sourceType, title, description, url, children, }: SourceDetailSheetProps) { const { document, loading, error, fetchDocumentByChunk, clearDocument } = useDocumentByChunk(); const chunksContainerRef = useRef(null); const highlightedChunkRef = useRef(null); const [summaryOpen, setSummaryOpen] = useState(false); // Check if this is a source type that should render directly from node const isDirectRenderSource = sourceType === "TAVILY_API" || sourceType === "LINKUP_API"; useEffect(() => { if (open && chunkId && !isDirectRenderSource) { fetchDocumentByChunk(chunkId); } else if (!open && !isDirectRenderSource) { clearDocument(); } }, [open, chunkId, isDirectRenderSource, fetchDocumentByChunk, clearDocument]); useEffect(() => { // Scroll to highlighted chunk when document loads if (document && highlightedChunkRef.current && chunksContainerRef.current) { setTimeout(() => { highlightedChunkRef.current?.scrollIntoView({ behavior: "smooth", block: "start", }); }, 100); } }, [document]); const handleUrlClick = (e: React.MouseEvent, clickUrl: string) => { e.preventDefault(); e.stopPropagation(); window.open(clickUrl, "_blank", "noopener,noreferrer"); }; return ( {children} {getConnectorIcon(sourceType)} {document?.title || title} {document ? formatDocumentType(document.document_type) : sourceType && formatDocumentType(sourceType)} {!isDirectRenderSource && loading && (
)} {!isDirectRenderSource && error && (

{error}

)} {/* Direct render for TAVILY_API and LINKUP_API */} {isDirectRenderSource && (
{/* External Link */} {url && (
)} {/* Source Information */}

Source Information

{title || "Untitled"}
{description || "No content available"}
)} {/* API-fetched document content */} {!isDirectRenderSource && document && (
{/* Document Metadata */} {document.document_metadata && Object.keys(document.document_metadata).length > 0 && (

Document Information

{Object.entries(document.document_metadata).map(([key, value]) => (
{key.replace(/_/g, " ")}:
{String(value)}
))}
)} {/* External Link */} {url && (
)} {/* Chunks */}
{/* Header row: header and button side by side */}

Document Content

{document.content && ( Summary {summaryOpen ? ( ) : ( )} )}
{/* Expanded summary content: always full width, below the row */} {document.content && (
)}
{document.chunks.map((chunk, idx) => (
Chunk {idx + 1} of {document.chunks.length} {chunk.id === chunkId && ( Referenced Chunk )}
))}
)}
); }