"use client"; import { useEffect, useState } from "react"; import { Modal } from "../Modal"; import { ToggleGroup } from "../ToggleGroup"; import { SpeedyLink } from "../SpeedyLink"; import { DotLoader } from "../utils/DotLoader"; import { DocumentProvider } from "contexts/DocumentContext"; import { LeafletContentProvider } from "contexts/LeafletContentContext"; import { CommentsDrawerContent } from "app/(app)/lish/[did]/[publication]/[rkey]/Interactions/Comments"; import { DiscussionDrawerContent } from "app/(app)/lish/[did]/[publication]/[rkey]/Interactions/Quotes"; import { decodeQuotePosition } from "app/(app)/lish/[did]/[publication]/[rkey]/quotePosition"; import { useDocumentDiscussionData } from "app/(app)/lish/[did]/[publication]/[rkey]/Interactions/useDocumentDiscussionData"; import { GoToArrow } from "../Icons/GoToArrow"; import { ButtonPrimary } from "../Buttons"; import { StandardSitePostItem } from "../Blocks/StandardSitePostBlock/StandardSitePostItem"; import { MobileSheet } from "../MobileSheet"; import { useIsMobile } from "src/hooks/isMobile"; // A self-contained modal that renders a post's comments and Bluesky mentions // with a toggle between them. Used from post listings, the reader feed, and // page-link blocks where the full post page (and its interaction drawer) isn't // mounted. It fetches everything it needs from get_document_interactions and // provides the Document/LeafletContent contexts that the shared drawer content // expects, so the post page's own drawer (#3) can stay untouched. export function DiscussionModal(props: { open: boolean; onOpenChange: (open: boolean) => void; document_uri: string; postUrl: string; title?: string; commentsCount: number; quotesCount: number; showComments: boolean; showMentions: boolean; pageId?: string; }) { const commentsAvailable = props.showComments && props.commentsCount > 0; const mentionsAvailable = props.showMentions && props.quotesCount > 0; const bothAvailable = commentsAvailable && mentionsAvailable; const [tab, setTab] = useState<"comments" | "quotes">( commentsAvailable ? "comments" : "quotes", ); // Reset to the most relevant tab each time the modal is opened. useEffect(() => { if (props.open) setTab(commentsAvailable ? "comments" : "quotes"); }, [props.open]); const { isLoading, data, did, pages, documentContextValue, comments } = useDocumentDiscussionData(props.document_uri, props.open); // On mobile this renders in the slide-up sheet (like the interaction drawer) // instead of a centered modal. const isMobile = useIsMobile(); // Restrict mentions to the page this modal is about (mirrors InteractionDrawer). const quotesAndMentions = (data?.quotesAndMentions ?? []).filter((q) => { if (!q.link) return !props.pageId; const url = new URL(q.link); const quoteParam = url.pathname.split("/l-quote/")[1]; if (!quoteParam) return !props.pageId; const quotePosition = decodeQuotePosition(quoteParam); return quotePosition?.pageId === props.pageId; }); const content = ( <>
{/* bg matches the surface it scrolls over: plain bg-page in the mobile sheet, the bg-light tint in the desktop modal (sm: aligns with the useIsMobile breakpoint). */}
{bothAvailable ? ( setTab(value)} options={[ { value: "comments", label: props.commentsCount > 0 ? `Comments (${props.commentsCount})` : "Comments", }, { value: "quotes", label: (
Bluesky Mentions{" "} {props.quotesCount > 0 && `(${props.quotesCount})`}
), }, ]} /> ) : (
{commentsAvailable ? `Comments (${props.commentsCount})` : `Bluesky Mentions (${props.quotesCount})`}
)}{" "} Full Post

{!data && isLoading ? (
loading
) : documentContextValue ? ( {tab === "comments" ? ( ) : ( )} ) : null}
); if (isMobile) { return ( {content} ); } return ( {content} ); }