feat: poll response notification
This commit is contained in:
@@ -6,18 +6,16 @@ import { useTranslation } from 'react-i18next'
|
|||||||
|
|
||||||
export default function CommunityDefinitionPreview({
|
export default function CommunityDefinitionPreview({
|
||||||
event,
|
event,
|
||||||
className,
|
className
|
||||||
onClick
|
|
||||||
}: {
|
}: {
|
||||||
event: Event
|
event: Event
|
||||||
className?: string
|
className?: string
|
||||||
onClick?: React.MouseEventHandler<HTMLDivElement> | undefined
|
|
||||||
}) {
|
}) {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const metadata = useMemo(() => getCommunityDefinitionFromEvent(event), [event])
|
const metadata = useMemo(() => getCommunityDefinitionFromEvent(event), [event])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={cn('pointer-events-none', className)} onClick={onClick}>
|
<div className={cn('pointer-events-none', className)}>
|
||||||
[{t('Community')}] <span className="italic pr-0.5">{metadata.name}</span>
|
[{t('Community')}] <span className="italic pr-0.5">{metadata.name}</span>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|||||||
63
src/components/ContentPreview/Content.tsx
Normal file
63
src/components/ContentPreview/Content.tsx
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
import {
|
||||||
|
EmbeddedEmojiParser,
|
||||||
|
EmbeddedEventParser,
|
||||||
|
EmbeddedImageParser,
|
||||||
|
EmbeddedMentionParser,
|
||||||
|
EmbeddedVideoParser,
|
||||||
|
parseContent
|
||||||
|
} from '@/lib/content-parser'
|
||||||
|
import { cn } from '@/lib/utils'
|
||||||
|
import { TEmoji } from '@/types'
|
||||||
|
import { useMemo } from 'react'
|
||||||
|
import { useTranslation } from 'react-i18next'
|
||||||
|
import { EmbeddedMentionText } from '../Embedded'
|
||||||
|
import Emoji from '../Emoji'
|
||||||
|
|
||||||
|
export default function Content({
|
||||||
|
content,
|
||||||
|
className,
|
||||||
|
emojiInfos
|
||||||
|
}: {
|
||||||
|
content: string
|
||||||
|
className?: string
|
||||||
|
emojiInfos?: TEmoji[]
|
||||||
|
}) {
|
||||||
|
const { t } = useTranslation()
|
||||||
|
const nodes = useMemo(() => {
|
||||||
|
return parseContent(content, [
|
||||||
|
EmbeddedImageParser,
|
||||||
|
EmbeddedVideoParser,
|
||||||
|
EmbeddedEventParser,
|
||||||
|
EmbeddedMentionParser,
|
||||||
|
EmbeddedEmojiParser
|
||||||
|
])
|
||||||
|
}, [content])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<span className={cn('pointer-events-none', className)}>
|
||||||
|
{nodes.map((node, index) => {
|
||||||
|
if (node.type === 'text') {
|
||||||
|
return node.data
|
||||||
|
}
|
||||||
|
if (node.type === 'image' || node.type === 'images') {
|
||||||
|
return index > 0 ? ` [${t('image')}]` : `[${t('image')}]`
|
||||||
|
}
|
||||||
|
if (node.type === 'video') {
|
||||||
|
return index > 0 ? ` [${t('video')}]` : `[${t('video')}]`
|
||||||
|
}
|
||||||
|
if (node.type === 'event') {
|
||||||
|
return index > 0 ? ` [${t('note')}]` : `[${t('note')}]`
|
||||||
|
}
|
||||||
|
if (node.type === 'mention') {
|
||||||
|
return <EmbeddedMentionText key={index} userId={node.data.split(':')[1]} />
|
||||||
|
}
|
||||||
|
if (node.type === 'emoji') {
|
||||||
|
const shortcode = node.data.split(':')[1]
|
||||||
|
const emoji = emojiInfos?.find((e) => e.shortcode === shortcode)
|
||||||
|
if (!emoji) return node.data
|
||||||
|
return <Emoji key={index} emoji={emoji} />
|
||||||
|
}
|
||||||
|
})}
|
||||||
|
</span>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -6,18 +6,16 @@ import { useTranslation } from 'react-i18next'
|
|||||||
|
|
||||||
export default function GroupMetadataPreview({
|
export default function GroupMetadataPreview({
|
||||||
event,
|
event,
|
||||||
className,
|
className
|
||||||
onClick
|
|
||||||
}: {
|
}: {
|
||||||
event: Event
|
event: Event
|
||||||
className?: string
|
className?: string
|
||||||
onClick?: React.MouseEventHandler<HTMLDivElement> | undefined
|
|
||||||
}) {
|
}) {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const metadata = useMemo(() => getGroupMetadataFromEvent(event), [event])
|
const metadata = useMemo(() => getGroupMetadataFromEvent(event), [event])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={cn('pointer-events-none', className)} onClick={onClick}>
|
<div className={cn('pointer-events-none', className)}>
|
||||||
[{t('Group')}] <span className="italic pr-0.5">{metadata.name}</span>
|
[{t('Group')}] <span className="italic pr-0.5">{metadata.name}</span>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|||||||
30
src/components/ContentPreview/HighlightPreview.tsx
Normal file
30
src/components/ContentPreview/HighlightPreview.tsx
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
import { useTranslatedEvent } from '@/hooks'
|
||||||
|
import { getEmojiInfosFromEmojiTags } from '@/lib/tag'
|
||||||
|
import { cn } from '@/lib/utils'
|
||||||
|
import { Event } from 'nostr-tools'
|
||||||
|
import { useMemo } from 'react'
|
||||||
|
import { useTranslation } from 'react-i18next'
|
||||||
|
import Content from './Content'
|
||||||
|
|
||||||
|
export default function HighlightPreview({
|
||||||
|
event,
|
||||||
|
className
|
||||||
|
}: {
|
||||||
|
event: Event
|
||||||
|
className?: string
|
||||||
|
}) {
|
||||||
|
const { t } = useTranslation()
|
||||||
|
const translatedEvent = useTranslatedEvent(event.id)
|
||||||
|
const emojiInfos = useMemo(() => getEmojiInfosFromEmojiTags(event.tags), [event])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={cn('pointer-events-none', className)}>
|
||||||
|
[{t('Highlight')}]{' '}
|
||||||
|
<Content
|
||||||
|
content={translatedEvent?.content ?? event.content}
|
||||||
|
emojiInfos={emojiInfos}
|
||||||
|
className="italic pr-0.5"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -6,18 +6,16 @@ import { useTranslation } from 'react-i18next'
|
|||||||
|
|
||||||
export default function LiveEventPreview({
|
export default function LiveEventPreview({
|
||||||
event,
|
event,
|
||||||
className,
|
className
|
||||||
onClick
|
|
||||||
}: {
|
}: {
|
||||||
event: Event
|
event: Event
|
||||||
className?: string
|
className?: string
|
||||||
onClick?: React.MouseEventHandler<HTMLDivElement> | undefined
|
|
||||||
}) {
|
}) {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const metadata = useMemo(() => getLiveEventMetadataFromEvent(event), [event])
|
const metadata = useMemo(() => getLiveEventMetadataFromEvent(event), [event])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={cn('pointer-events-none', className)} onClick={onClick}>
|
<div className={cn('pointer-events-none', className)}>
|
||||||
[{t('Live event')}] <span className="italic pr-0.5">{metadata.title}</span>
|
[{t('Live event')}] <span className="italic pr-0.5">{metadata.title}</span>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -6,18 +6,16 @@ import { useTranslation } from 'react-i18next'
|
|||||||
|
|
||||||
export default function LongFormArticlePreview({
|
export default function LongFormArticlePreview({
|
||||||
event,
|
event,
|
||||||
className,
|
className
|
||||||
onClick
|
|
||||||
}: {
|
}: {
|
||||||
event: Event
|
event: Event
|
||||||
className?: string
|
className?: string
|
||||||
onClick?: React.MouseEventHandler<HTMLDivElement> | undefined
|
|
||||||
}) {
|
}) {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const metadata = useMemo(() => getLongFormArticleMetadataFromEvent(event), [event])
|
const metadata = useMemo(() => getLongFormArticleMetadataFromEvent(event), [event])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={cn('pointer-events-none', className)} onClick={onClick}>
|
<div className={cn('pointer-events-none', className)}>
|
||||||
[{t('Article')}] <span className="italic pr-0.5">{metadata.title}</span>
|
[{t('Article')}] <span className="italic pr-0.5">{metadata.title}</span>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,68 +1,24 @@
|
|||||||
import { useTranslatedEvent } from '@/hooks'
|
import { useTranslatedEvent } from '@/hooks'
|
||||||
import {
|
|
||||||
EmbeddedEmojiParser,
|
|
||||||
EmbeddedEventParser,
|
|
||||||
EmbeddedImageParser,
|
|
||||||
EmbeddedMentionParser,
|
|
||||||
EmbeddedVideoParser,
|
|
||||||
parseContent
|
|
||||||
} from '@/lib/content-parser'
|
|
||||||
import { getEmojiInfosFromEmojiTags } from '@/lib/tag'
|
import { getEmojiInfosFromEmojiTags } from '@/lib/tag'
|
||||||
import { cn } from '@/lib/utils'
|
|
||||||
import { Event } from 'nostr-tools'
|
import { Event } from 'nostr-tools'
|
||||||
import { useMemo } from 'react'
|
import { useMemo } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import Content from './Content'
|
||||||
import { EmbeddedMentionText } from '../Embedded'
|
|
||||||
import Emoji from '../Emoji'
|
|
||||||
|
|
||||||
export default function NormalContentPreview({
|
export default function NormalContentPreview({
|
||||||
event,
|
event,
|
||||||
className,
|
className
|
||||||
onClick
|
|
||||||
}: {
|
}: {
|
||||||
event: Event
|
event: Event
|
||||||
className?: string
|
className?: string
|
||||||
onClick?: React.MouseEventHandler<HTMLDivElement> | undefined
|
|
||||||
}) {
|
}) {
|
||||||
const { t } = useTranslation()
|
|
||||||
const translatedEvent = useTranslatedEvent(event?.id)
|
const translatedEvent = useTranslatedEvent(event?.id)
|
||||||
const nodes = useMemo(() => {
|
const emojiInfos = useMemo(() => getEmojiInfosFromEmojiTags(event?.tags), [event])
|
||||||
return parseContent(event.content, [
|
|
||||||
EmbeddedImageParser,
|
|
||||||
EmbeddedVideoParser,
|
|
||||||
EmbeddedEventParser,
|
|
||||||
EmbeddedMentionParser,
|
|
||||||
EmbeddedEmojiParser
|
|
||||||
])
|
|
||||||
}, [event, translatedEvent])
|
|
||||||
|
|
||||||
const emojiInfos = getEmojiInfosFromEmojiTags(event?.tags)
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={cn('pointer-events-none', className)} onClick={onClick}>
|
<Content
|
||||||
{nodes.map((node, index) => {
|
content={translatedEvent?.content ?? event.content}
|
||||||
if (node.type === 'text') {
|
className={className}
|
||||||
return node.data
|
emojiInfos={emojiInfos}
|
||||||
}
|
/>
|
||||||
if (node.type === 'image' || node.type === 'images') {
|
|
||||||
return index > 0 ? ` [${t('image')}]` : `[${t('image')}]`
|
|
||||||
}
|
|
||||||
if (node.type === 'video') {
|
|
||||||
return index > 0 ? ` [${t('video')}]` : `[${t('video')}]`
|
|
||||||
}
|
|
||||||
if (node.type === 'event') {
|
|
||||||
return index > 0 ? ` [${t('note')}]` : `[${t('note')}]`
|
|
||||||
}
|
|
||||||
if (node.type === 'mention') {
|
|
||||||
return <EmbeddedMentionText key={index} userId={node.data.split(':')[1]} />
|
|
||||||
}
|
|
||||||
if (node.type === 'emoji') {
|
|
||||||
const shortcode = node.data.split(':')[1]
|
|
||||||
const emoji = emojiInfos.find((e) => e.shortcode === shortcode)
|
|
||||||
if (!emoji) return node.data
|
|
||||||
return <Emoji key={index} emoji={emoji} />
|
|
||||||
}
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
24
src/components/ContentPreview/PollPreview.tsx
Normal file
24
src/components/ContentPreview/PollPreview.tsx
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
import { useTranslatedEvent } from '@/hooks'
|
||||||
|
import { getEmojiInfosFromEmojiTags } from '@/lib/tag'
|
||||||
|
import { cn } from '@/lib/utils'
|
||||||
|
import { Event } from 'nostr-tools'
|
||||||
|
import { useMemo } from 'react'
|
||||||
|
import { useTranslation } from 'react-i18next'
|
||||||
|
import Content from './Content'
|
||||||
|
|
||||||
|
export default function PollPreview({ event, className }: { event: Event; className?: string }) {
|
||||||
|
const { t } = useTranslation()
|
||||||
|
const translatedEvent = useTranslatedEvent(event.id)
|
||||||
|
const emojiInfos = useMemo(() => getEmojiInfosFromEmojiTags(event.tags), [event])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={cn('pointer-events-none', className)}>
|
||||||
|
[{t('Poll')}]{' '}
|
||||||
|
<Content
|
||||||
|
content={translatedEvent?.content ?? event.content}
|
||||||
|
emojiInfos={emojiInfos}
|
||||||
|
className="italic pr-0.5"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -6,18 +6,18 @@ import { useMemo } from 'react'
|
|||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import CommunityDefinitionPreview from './CommunityDefinitionPreview'
|
import CommunityDefinitionPreview from './CommunityDefinitionPreview'
|
||||||
import GroupMetadataPreview from './GroupMetadataPreview'
|
import GroupMetadataPreview from './GroupMetadataPreview'
|
||||||
|
import HighlightPreview from './HighlightPreview'
|
||||||
import LiveEventPreview from './LiveEventPreview'
|
import LiveEventPreview from './LiveEventPreview'
|
||||||
import LongFormArticlePreview from './LongFormArticlePreview'
|
import LongFormArticlePreview from './LongFormArticlePreview'
|
||||||
import NormalContentPreview from './NormalContentPreview'
|
import NormalContentPreview from './NormalContentPreview'
|
||||||
|
import PollPreview from './PollPreview'
|
||||||
|
|
||||||
export default function ContentPreview({
|
export default function ContentPreview({
|
||||||
event,
|
event,
|
||||||
className,
|
className
|
||||||
onClick
|
|
||||||
}: {
|
}: {
|
||||||
event?: Event
|
event?: Event
|
||||||
className?: string
|
className?: string
|
||||||
onClick?: React.MouseEventHandler<HTMLDivElement> | undefined
|
|
||||||
}) {
|
}) {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const { mutePubkeys } = useMuteList()
|
const { mutePubkeys } = useMuteList()
|
||||||
@@ -37,39 +37,31 @@ export default function ContentPreview({
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ([kinds.ShortTextNote, ExtendedKind.COMMENT, ExtendedKind.PICTURE].includes(event.kind)) {
|
if ([kinds.ShortTextNote, ExtendedKind.COMMENT, ExtendedKind.PICTURE].includes(event.kind)) {
|
||||||
return <NormalContentPreview event={event} className={className} onClick={onClick} />
|
return <NormalContentPreview event={event} className={className} />
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event.kind === kinds.Highlights) {
|
if (event.kind === kinds.Highlights) {
|
||||||
return (
|
return <HighlightPreview event={event} className={className} />
|
||||||
<div className={cn('pointer-events-none', className)}>
|
|
||||||
[{t('Highlight')}] <span className="italic pr-0.5">{event.content}</span>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event.kind === ExtendedKind.POLL) {
|
if (event.kind === ExtendedKind.POLL) {
|
||||||
return (
|
return <PollPreview event={event} className={className} />
|
||||||
<div className={cn('pointer-events-none', className)}>
|
|
||||||
[{t('Poll')}] <span className="italic pr-0.5">{event.content}</span>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event.kind === kinds.LongFormArticle) {
|
if (event.kind === kinds.LongFormArticle) {
|
||||||
return <LongFormArticlePreview event={event} className={className} onClick={onClick} />
|
return <LongFormArticlePreview event={event} className={className} />
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event.kind === ExtendedKind.GROUP_METADATA) {
|
if (event.kind === ExtendedKind.GROUP_METADATA) {
|
||||||
return <GroupMetadataPreview event={event} className={className} onClick={onClick} />
|
return <GroupMetadataPreview event={event} className={className} />
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event.kind === kinds.CommunityDefinition) {
|
if (event.kind === kinds.CommunityDefinition) {
|
||||||
return <CommunityDefinitionPreview event={event} className={className} onClick={onClick} />
|
return <CommunityDefinitionPreview event={event} className={className} />
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event.kind === kinds.LiveEvent) {
|
if (event.kind === kinds.LiveEvent) {
|
||||||
return <LiveEventPreview event={event} className={className} onClick={onClick} />
|
return <LiveEventPreview event={event} className={className} />
|
||||||
}
|
}
|
||||||
|
|
||||||
return <div className={className}>[{t('Cannot handle event of kind k', { k: event.kind })}]</div>
|
return <div className={className}>[{t('Cannot handle event of kind k', { k: event.kind })}]</div>
|
||||||
|
|||||||
@@ -111,14 +111,15 @@ function HighlightSource({ event }: { event: Event }) {
|
|||||||
<div className="shrink-0">{t('From')}</div>
|
<div className="shrink-0">{t('From')}</div>
|
||||||
{pubkey && <UserAvatar userId={pubkey} size="xSmall" className="cursor-pointer" />}
|
{pubkey && <UserAvatar userId={pubkey} size="xSmall" className="cursor-pointer" />}
|
||||||
{referenceEvent ? (
|
{referenceEvent ? (
|
||||||
<ContentPreview
|
<div
|
||||||
className="truncate underline pointer-events-auto cursor-pointer hover:text-foreground"
|
className="truncate underline pointer-events-auto cursor-pointer hover:text-foreground"
|
||||||
event={referenceEvent}
|
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
push(toNote(referenceEvent))
|
push(toNote(referenceEvent))
|
||||||
}}
|
}}
|
||||||
/>
|
>
|
||||||
|
<ContentPreview event={referenceEvent} />
|
||||||
|
</div>
|
||||||
) : referenceEventId ? (
|
) : referenceEventId ? (
|
||||||
<div className="truncate text-muted-foreground">
|
<div className="truncate text-muted-foreground">
|
||||||
<a
|
<a
|
||||||
|
|||||||
@@ -0,0 +1,47 @@
|
|||||||
|
import { useFetchEvent } from '@/hooks'
|
||||||
|
import { toNote } from '@/lib/link'
|
||||||
|
import { generateBech32IdFromETag, tagNameEquals } from '@/lib/tag'
|
||||||
|
import { cn } from '@/lib/utils'
|
||||||
|
import { useSecondaryPage } from '@/PageManager'
|
||||||
|
import { Vote } from 'lucide-react'
|
||||||
|
import { Event } from 'nostr-tools'
|
||||||
|
import { useMemo } from 'react'
|
||||||
|
import ContentPreview from '../../ContentPreview'
|
||||||
|
import { FormattedTimestamp } from '../../FormattedTimestamp'
|
||||||
|
import UserAvatar from '../../UserAvatar'
|
||||||
|
|
||||||
|
export function PollResponseNotification({
|
||||||
|
notification,
|
||||||
|
isNew = false
|
||||||
|
}: {
|
||||||
|
notification: Event
|
||||||
|
isNew?: boolean
|
||||||
|
}) {
|
||||||
|
const { push } = useSecondaryPage()
|
||||||
|
const eventId = useMemo(() => {
|
||||||
|
const eTag = notification.tags.find(tagNameEquals('e'))
|
||||||
|
return eTag ? generateBech32IdFromETag(eTag) : undefined
|
||||||
|
}, [notification])
|
||||||
|
const { event: pollEvent } = useFetchEvent(eventId)
|
||||||
|
|
||||||
|
if (!pollEvent) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className="flex gap-2 items-center cursor-pointer py-2"
|
||||||
|
onClick={() => push(toNote(pollEvent))}
|
||||||
|
>
|
||||||
|
<UserAvatar userId={notification.pubkey} size="small" />
|
||||||
|
<Vote size={24} className="text-violet-400" />
|
||||||
|
<ContentPreview
|
||||||
|
className={cn('truncate flex-1 w-0', isNew ? 'font-semibold' : 'text-muted-foreground')}
|
||||||
|
event={pollEvent}
|
||||||
|
/>
|
||||||
|
<div className="text-muted-foreground">
|
||||||
|
<FormattedTimestamp timestamp={notification.created_at} short />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import Image from '@/components/Image'
|
import Image from '@/components/Image'
|
||||||
import { useFetchEvent } from '@/hooks'
|
import { useFetchEvent } from '@/hooks'
|
||||||
import { toNote } from '@/lib/link'
|
import { toNote } from '@/lib/link'
|
||||||
import { tagNameEquals } from '@/lib/tag'
|
import { generateBech32IdFromETag, tagNameEquals } from '@/lib/tag'
|
||||||
import { cn } from '@/lib/utils'
|
import { cn } from '@/lib/utils'
|
||||||
import { useSecondaryPage } from '@/PageManager'
|
import { useSecondaryPage } from '@/PageManager'
|
||||||
import { useNostr } from '@/providers/NostrProvider'
|
import { useNostr } from '@/providers/NostrProvider'
|
||||||
@@ -26,7 +26,7 @@ export function ReactionNotification({
|
|||||||
if (targetPubkey !== pubkey) return undefined
|
if (targetPubkey !== pubkey) return undefined
|
||||||
|
|
||||||
const eTag = notification.tags.findLast(tagNameEquals('e'))
|
const eTag = notification.tags.findLast(tagNameEquals('e'))
|
||||||
return eTag?.[1]
|
return eTag ? generateBech32IdFromETag(eTag) : undefined
|
||||||
}, [notification, pubkey])
|
}, [notification, pubkey])
|
||||||
const { event } = useFetchEvent(eventId)
|
const { event } = useFetchEvent(eventId)
|
||||||
const reaction = useMemo(() => {
|
const reaction = useMemo(() => {
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { ExtendedKind } from '@/constants'
|
|||||||
import { useMuteList } from '@/providers/MuteListProvider'
|
import { useMuteList } from '@/providers/MuteListProvider'
|
||||||
import { Event, kinds } from 'nostr-tools'
|
import { Event, kinds } from 'nostr-tools'
|
||||||
import { CommentNotification } from './CommentNotification'
|
import { CommentNotification } from './CommentNotification'
|
||||||
|
import { PollResponseNotification } from './PollResponseNotification'
|
||||||
import { ReactionNotification } from './ReactionNotification'
|
import { ReactionNotification } from './ReactionNotification'
|
||||||
import { ReplyNotification } from './ReplyNotification'
|
import { ReplyNotification } from './ReplyNotification'
|
||||||
import { RepostNotification } from './RepostNotification'
|
import { RepostNotification } from './RepostNotification'
|
||||||
@@ -33,5 +34,8 @@ export function NotificationItem({
|
|||||||
if (notification.kind === ExtendedKind.COMMENT) {
|
if (notification.kind === ExtendedKind.COMMENT) {
|
||||||
return <CommentNotification notification={notification} isNew={isNew} />
|
return <CommentNotification notification={notification} isNew={isNew} />
|
||||||
}
|
}
|
||||||
|
if (notification.kind === ExtendedKind.POLL_RESPONSE) {
|
||||||
|
return <PollResponseNotification notification={notification} isNew={isNew} />
|
||||||
|
}
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,11 +41,18 @@ const NotificationList = forwardRef((_, ref) => {
|
|||||||
case 'mentions':
|
case 'mentions':
|
||||||
return [kinds.ShortTextNote, ExtendedKind.COMMENT]
|
return [kinds.ShortTextNote, ExtendedKind.COMMENT]
|
||||||
case 'reactions':
|
case 'reactions':
|
||||||
return [kinds.Reaction, kinds.Repost]
|
return [kinds.Reaction, kinds.Repost, ExtendedKind.POLL_RESPONSE]
|
||||||
case 'zaps':
|
case 'zaps':
|
||||||
return [kinds.Zap]
|
return [kinds.Zap]
|
||||||
default:
|
default:
|
||||||
return [kinds.ShortTextNote, kinds.Repost, kinds.Reaction, kinds.Zap, ExtendedKind.COMMENT]
|
return [
|
||||||
|
kinds.ShortTextNote,
|
||||||
|
kinds.Repost,
|
||||||
|
kinds.Reaction,
|
||||||
|
kinds.Zap,
|
||||||
|
ExtendedKind.COMMENT,
|
||||||
|
ExtendedKind.POLL_RESPONSE
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}, [notificationType])
|
}, [notificationType])
|
||||||
useImperativeHandle(
|
useImperativeHandle(
|
||||||
|
|||||||
Reference in New Issue
Block a user