import { useFetchEvent } from '@/hooks' import { usePaymentAttestationStatus } from '@/hooks/usePaymentAttestationStatus' import { getZapInfoFromEvent } from '@/lib/event-metadata' import { shouldHideInteractions } from '@/lib/event-filtering' import { formatAmount } from '@/lib/lightning' import { openNoteFromFetchOrCache } from '@/lib/navigation-related-events' import { relayHintsFromEventTags } from '@/lib/relay-list-builder' import { getSuperchatPaytoType } from '@/lib/superchat' import { superchatChromePaymentChipClass, superchatChromePaymentIconClass, superchatChromeRowClass, superchatTitleClass } from '@/lib/superchat-ui' import { toProfile } from '@/lib/link' import { cn } from '@/lib/utils' import { Event } from 'nostr-tools' import { Zap as ZapIcon } from 'lucide-react' import { useMemo, type MouseEvent } from 'react' import { useTranslation } from 'react-i18next' import { useSmartNoteNavigationOptional, useSecondaryPageOptional } from '@/PageManager' import Username from '../Username' import SuperchatPaymentMethodLabel from './SuperchatPaymentMethodLabel' import SuperchatMessageArea from './SuperchatMessageArea' import TurnIntoSuperchatButton from '../TurnIntoSuperchatButton' import UserAvatar from '../UserAvatar' import type { SuperchatLayoutVariant } from './Superchat' export default function Zap({ event, className, variant = 'thread' }: { event: Event className?: string /** @deprecated Attestation button is shown automatically for payment recipients. */ showAttestationAction?: boolean variant?: SuperchatLayoutVariant }) { const { t } = useTranslation() const zapInfo = useMemo(() => getZapInfoFromEvent(event), [event]) const zapRelayHints = useMemo(() => relayHintsFromEventTags(event), [event]) const zapFetchOpts = useMemo( () => (zapRelayHints.length ? { relayHints: zapRelayHints } : undefined), [zapRelayHints] ) const { event: targetEvent } = useFetchEvent(zapInfo?.eventId, undefined, zapFetchOpts) const isEventZap = Boolean(targetEvent || zapInfo?.eventId) const isProfileZap = Boolean(!isEventZap && zapInfo?.recipientPubkey) const actualRecipientPubkey = useMemo(() => { if (isEventZap && targetEvent) { return targetEvent.pubkey } if (isProfileZap) { return zapInfo?.recipientPubkey } return undefined }, [isEventZap, isProfileZap, targetEvent, zapInfo?.recipientPubkey]) const paytoType = useMemo(() => getSuperchatPaytoType(event), [event]) const { navigateToNote } = useSmartNoteNavigationOptional() const secondaryPage = useSecondaryPageOptional() const push = secondaryPage?.push ?? ((url: string) => { window.location.href = url }) const inQuietMode = targetEvent ? shouldHideInteractions(targetEvent) : false if (inQuietMode) { return null } if (!zapInfo || !zapInfo.senderPubkey) { return (
[{t('Invalid zap receipt')}]
) } const { senderPubkey, recipientPubkey, amount, comment } = zapInfo const attestationRecipientPubkey = actualRecipientPubkey ?? recipientPubkey ?? null const { attested } = usePaymentAttestationStatus(event, attestationRecipientPubkey) const openZapTarget = (e: MouseEvent) => { e.stopPropagation() if (isEventZap && zapInfo?.eventId) { openNoteFromFetchOrCache(navigateToNote, zapInfo.eventId, targetEvent) } else if (isProfileZap && actualRecipientPubkey) { push(toProfile(actualRecipientPubkey)) } } const isNotification = variant === 'notification' const isProfileWall = variant === 'profileWall' const showAmount = isNotification && amount != null && amount > 0 const showAsSuperchat = isProfileWall || attested const hasMetaLine = isProfileWall || (isNotification && ((recipientPubkey && recipientPubkey !== senderPubkey) || isEventZap || isProfileZap)) return (
{hasMetaLine ? (
{isProfileWall ? (
) : ( <> {recipientPubkey && recipientPubkey !== senderPubkey && ( {t('zapped')}{' '} )} {(isNotification && (isEventZap || isProfileZap)) && ( )} )}
) : null} {!isProfileWall ? (
{showAsSuperchat ? ( <> {t('Superchat')} {showAmount ? ( {formatAmount(amount)} {t('sats')} ) : null} ) : ( <> {t('Zap')} {showAmount ? ( {formatAmount(amount)} {t('sats')} ) : null} )}
) : null}
{isNotification ? (
) : null}
) }