import { useState } from "react"; import { ChevronDown, ChevronRight, Radio, FileText, Wifi, Filter as FilterIcon, Circle, } from "lucide-react"; import { useReqTimeline } from "@/hooks/useReqTimeline"; import { useGrimoire } from "@/core/state"; import { FeedEvent } from "./nostr/Feed"; import { KindBadge } from "./KindBadge"; import type { NostrFilter } from "@/types/nostr"; interface ReqViewerProps { filter: NostrFilter; relays?: string[]; closeOnEose?: boolean; nip05Authors?: string[]; nip05PTags?: string[]; } export default function ReqViewer({ filter, relays, closeOnEose = false, nip05Authors, nip05PTags, }: ReqViewerProps) { const { state } = useGrimoire(); // NIP-05 resolution already happened in argParser before window creation // The filter prop already contains resolved pubkeys // We just display the NIP-05 identifiers for user reference // Use inbox relays if logged in and no relays specified const defaultRelays = relays || (state.activeAccount?.relays?.inbox.length ? state.activeAccount.relays.inbox.map((r) => r.url) : ["wss://theforest.nostr1.com"]); // Streaming is the default behavior, closeOnEose inverts it const stream = !closeOnEose; const { events, loading, error, eoseReceived } = useReqTimeline( `req-${JSON.stringify(filter)}-${closeOnEose}`, filter, defaultRelays, { limit: filter.limit || 50, stream }, ); const [showRelays, setShowRelays] = useState(false); const [showQuery, setShowQuery] = useState(false); return (
{/* Compact Header */}
{/* Left: Status Indicator */}
{loading && !eoseReceived ? "LOADING" : loading && eoseReceived && stream ? "LIVE" : !loading && eoseReceived ? "CLOSED" : "CONNECTING"}
{/* Right: Stats */}
{/* Event Count */}
{events.length}
{/* Relay Count (Clickable) */} {/* Query (Clickable) */}
{/* Expandable Relays */} {showRelays && (
{defaultRelays.map((relay) => (
{relay}
))}
)} {/* Expandable Query */} {showQuery && (
{/* Kind Badges */} {filter.kinds && filter.kinds.length > 0 && (
Kinds: {filter.kinds.map((kind) => ( ))}
)} {/* Authors with NIP-05 info */} {filter.authors && filter.authors.length > 0 && (
Authors: {filter.authors.length} {nip05Authors && nip05Authors.length > 0 && (
{nip05Authors.map((nip05) => (
→ {nip05}
))}
)}
)} {/* #p Tags with NIP-05 info */} {filter["#p"] && filter["#p"].length > 0 && (
#p Tags: {filter["#p"].length} {nip05PTags && nip05PTags.length > 0 && (
{nip05PTags.map((nip05) => (
→ {nip05}
))}
)}
)} {/* Limit */} {filter.limit && (
Limit: {filter.limit}
)} {/* Stream Mode */} {stream && (
● Streaming mode enabled
)} {/* Raw Query */}
Query Filter
              {JSON.stringify(filter, null, 2)}
            
)} {/* Error Display */} {error && (
Error: {error.message}
)} {/* Results */}
{loading && events.length === 0 && (
Loading events...
)} {!loading && !stream && events.length === 0 && !error && (
No events found matching filter
)} {stream && events.length === 0 && !loading && (
Waiting for events...
)} {events.map((event) => ( ))}
); }