import { Skeleton } from '@/components/ui/skeleton' import { SEARCHABLE_RELAY_URLS } from '@/constants' import { useFetchEvent } from '@/hooks' import { cn } from '@/lib/utils' import client from '@/services/client.service' import { useTranslation } from 'react-i18next' import { useCallback, useEffect, useRef, useState } from 'react' import { Event } from 'nostr-tools' import ContentPreview from '../ContentPreview' import UserAvatar from '../UserAvatar' import logger from '@/lib/logger' export default function ParentNotePreview({ eventId, className, onClick, /** Inline hint without pill background (e.g. reply thread rows). */ appearance = 'default' }: { eventId: string className?: string onClick?: React.MouseEventHandler | undefined appearance?: 'default' | 'subtle' }) { const { t } = useTranslation() const { event, isFetching } = useFetchEvent(eventId) const [fallbackEvent, setFallbackEvent] = useState(undefined) const [isFetchingFallback, setIsFetchingFallback] = useState(false) /** One automatic searchable-relay attempt per eventId; without this, the effect re-fires forever after each 20s timeout. */ const autoSearchableAttemptedRef = useRef(false) // Helper function to fetch from searchable relays (hex, note1, nevent1, naddr1) const fetchFromSearchableRelays = useCallback(async () => { if (!eventId?.trim()) return setIsFetchingFallback(true) try { const foundEvent = await client.fetchEventWithExternalRelays(eventId, SEARCHABLE_RELAY_URLS) if (foundEvent) { client.addEventToCache(foundEvent) setFallbackEvent(foundEvent) } } catch (error) { logger.warn('Fallback fetch from searchable relays failed', error as Error) } finally { setIsFetchingFallback(false) } }, [eventId]) useEffect(() => { autoSearchableAttemptedRef.current = false }, [eventId]) // If the initial fetch fails, try searchable relays once (manual retry still works via onClick). useEffect(() => { if ( !isFetching && !event && !fallbackEvent && !isFetchingFallback && eventId && !autoSearchableAttemptedRef.current ) { autoSearchableAttemptedRef.current = true void fetchFromSearchableRelays() } }, [isFetching, event, eventId, fallbackEvent, isFetchingFallback, fetchFromSearchableRelays]) const finalEvent = event || fallbackEvent const finalIsFetching = isFetching || isFetchingFallback const shellClass = appearance === 'subtle' ? 'flex gap-1.5 items-center text-xs w-full max-w-full text-muted-foreground' : 'flex gap-1 items-center text-sm rounded-full px-2 bg-muted w-fit max-w-full text-muted-foreground' if (finalIsFetching) { return (
{t('reply to')}
) } // Handle click for retry when event not found const handleClick = (e: React.MouseEvent) => { if (finalEvent) { onClick?.(e) } else if (!finalEvent && !finalIsFetching && eventId) { // Retry fetch from searchable relays when clicking "Note not found" e.stopPropagation() fetchFromSearchableRelays() } } return (
{t('reply to')}
{finalEvent && }
) }