ReactionNotification.tsx raw

   1  import Image from '@/components/Image'
   2  import { useFetchEvent } from '@/hooks'
   3  import { generateBech32IdFromATag, generateBech32IdFromETag, tagNameEquals } from '@/lib/tag'
   4  import { useNostr } from '@/providers/NostrProvider'
   5  import { Heart } from 'lucide-react'
   6  import { Event } from 'nostr-tools'
   7  import { useMemo } from 'react'
   8  import { useTranslation } from 'react-i18next'
   9  import Notification from './Notification'
  10  
  11  export function ReactionNotification({
  12    notification,
  13    isNew = false,
  14    navIndex
  15  }: {
  16    notification: Event
  17    isNew?: boolean
  18    navIndex?: number
  19  }) {
  20    const { t } = useTranslation()
  21    const { pubkey } = useNostr()
  22    const eventId = useMemo(() => {
  23      const aTag = notification.tags.findLast(tagNameEquals('a'))
  24      if (aTag) {
  25        return generateBech32IdFromATag(aTag)
  26      }
  27      const eTag = notification.tags.findLast(tagNameEquals('e'))
  28      return eTag ? generateBech32IdFromETag(eTag) : undefined
  29    }, [notification, pubkey])
  30    const { event } = useFetchEvent(eventId)
  31    const reaction = useMemo(() => {
  32      if (!notification.content || notification.content === '+') {
  33        return <Heart size={24} className="text-red-400" />
  34      }
  35  
  36      const emojiName = /^:([^:]+):$/.exec(notification.content)?.[1]
  37      if (emojiName) {
  38        const emojiTag = notification.tags.find((tag) => tag[0] === 'emoji' && tag[1] === emojiName)
  39        const emojiUrl = emojiTag?.[2]
  40        if (emojiUrl) {
  41          return (
  42            <Image
  43              image={{ url: emojiUrl, pubkey: notification.pubkey }}
  44              alt={emojiName}
  45              className="w-6 h-6"
  46              classNames={{ errorPlaceholder: 'bg-transparent', wrapper: 'rounded-md' }}
  47              errorPlaceholder={<Heart size={24} className="text-red-400" />}
  48            />
  49          )
  50        }
  51      }
  52      if (notification.content.length > 4) {
  53        return null
  54      }
  55      return notification.content
  56    }, [notification])
  57  
  58    if (!event || !eventId || !reaction) {
  59      return null
  60    }
  61  
  62    return (
  63      <Notification
  64        notificationId={notification.id}
  65        icon={<div className="text-xl min-w-6 text-center">{reaction}</div>}
  66        sender={notification.pubkey}
  67        sentAt={notification.created_at}
  68        targetEvent={event}
  69        description={t('reacted to your note')}
  70        isNew={isNew}
  71        navIndex={navIndex}
  72      />
  73    )
  74  }
  75