From 63869ef3b768b773ce39257b10306ba6dd4184d1 Mon Sep 17 00:00:00 2001 From: codytseng Date: Wed, 10 Sep 2025 22:15:31 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=F0=9F=92=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../NotificationItem/ReactionNotification.tsx | 9 ++--- .../NotificationItem/index.tsx | 32 +++++++++++------ src/components/NotificationList/index.tsx | 11 ++---- src/lib/notification.ts | 35 +++++++++++++++++++ src/providers/NotificationProvider.tsx | 13 ++++--- 5 files changed, 72 insertions(+), 28 deletions(-) create mode 100644 src/lib/notification.ts diff --git a/src/components/NotificationList/NotificationItem/ReactionNotification.tsx b/src/components/NotificationList/NotificationItem/ReactionNotification.tsx index 3e1d1544..13218be6 100644 --- a/src/components/NotificationList/NotificationItem/ReactionNotification.tsx +++ b/src/components/NotificationList/NotificationItem/ReactionNotification.tsx @@ -1,6 +1,6 @@ import Image from '@/components/Image' import { useFetchEvent } from '@/hooks' -import { generateBech32IdFromETag, tagNameEquals } from '@/lib/tag' +import { generateBech32IdFromATag, generateBech32IdFromETag, tagNameEquals } from '@/lib/tag' import { useNostr } from '@/providers/NostrProvider' import { Heart } from 'lucide-react' import { Event } from 'nostr-tools' @@ -18,9 +18,10 @@ export function ReactionNotification({ const { t } = useTranslation() const { pubkey } = useNostr() const eventId = useMemo(() => { - const targetPubkey = notification.tags.findLast(tagNameEquals('p'))?.[1] - if (targetPubkey !== pubkey) return undefined - + const aTag = notification.tags.findLast(tagNameEquals('a')) + if (aTag) { + return generateBech32IdFromATag(aTag) + } const eTag = notification.tags.findLast(tagNameEquals('e')) return eTag ? generateBech32IdFromETag(eTag) : undefined }, [notification, pubkey]) diff --git a/src/components/NotificationList/NotificationItem/index.tsx b/src/components/NotificationList/NotificationItem/index.tsx index d0caf42c..b3d33ec5 100644 --- a/src/components/NotificationList/NotificationItem/index.tsx +++ b/src/components/NotificationList/NotificationItem/index.tsx @@ -1,7 +1,9 @@ import { ExtendedKind } from '@/constants' -import { isMentioningMutedUsers } from '@/lib/event' +import { notificationFilter } from '@/lib/notification' import { useContentPolicy } from '@/providers/ContentPolicyProvider' import { useMuteList } from '@/providers/MuteListProvider' +import { useNostr } from '@/providers/NostrProvider' +import { useUserTrust } from '@/providers/UserTrustProvider' import { Event, kinds } from 'nostr-tools' import { useMemo } from 'react' import { MentionNotification } from './MentionNotification' @@ -17,18 +19,26 @@ export function NotificationItem({ notification: Event isNew?: boolean }) { + const { pubkey } = useNostr() const { mutePubkeySet } = useMuteList() const { hideContentMentioningMutedUsers } = useContentPolicy() - const shouldHide = useMemo(() => { - if (mutePubkeySet.has(notification.pubkey)) { - return true - } - if (hideContentMentioningMutedUsers && isMentioningMutedUsers(notification, mutePubkeySet)) { - return true - } - return false - }, []) - if (shouldHide) return null + const { hideUntrustedNotifications, isUserTrusted } = useUserTrust() + const canShow = useMemo(() => { + return notificationFilter(notification, { + pubkey, + mutePubkeySet, + hideContentMentioningMutedUsers, + hideUntrustedNotifications, + isUserTrusted + }) + }, [ + notification, + mutePubkeySet, + hideContentMentioningMutedUsers, + hideUntrustedNotifications, + isUserTrusted + ]) + if (!canShow) return null if (notification.kind === kinds.Reaction) { return diff --git a/src/components/NotificationList/index.tsx b/src/components/NotificationList/index.tsx index 93d5e4bc..216a8840 100644 --- a/src/components/NotificationList/index.tsx +++ b/src/components/NotificationList/index.tsx @@ -4,7 +4,6 @@ import { usePrimaryPage } from '@/PageManager' import { useNostr } from '@/providers/NostrProvider' import { useNotification } from '@/providers/NotificationProvider' import { useUserPreferences } from '@/providers/UserPreferencesProvider' -import { useUserTrust } from '@/providers/UserTrustProvider' import client from '@/services/client.service' import noteStatsService from '@/services/note-stats.service' import { TNotificationType } from '@/types' @@ -33,7 +32,6 @@ const NotificationList = forwardRef((_, ref) => { const { current, display } = usePrimaryPage() const active = useMemo(() => current === 'notifications' && display, [current, display]) const { pubkey } = useNostr() - const { hideUntrustedNotifications, isUserTrusted } = useUserTrust() const { getNotificationsSeenAt } = useNotification() const { notificationListStyle } = useUserPreferences() const [notificationType, setNotificationType] = useState('all') @@ -180,13 +178,8 @@ const NotificationList = forwardRef((_, ref) => { }, [pubkey, active, filterKinds, handleNewEvent]) useEffect(() => { - let visibleNotifications = notifications.slice(0, showCount) - if (hideUntrustedNotifications) { - visibleNotifications = visibleNotifications.filter((event) => isUserTrusted(event.pubkey)) - } - - setVisibleNotifications(visibleNotifications) - }, [notifications, showCount, hideUntrustedNotifications, isUserTrusted]) + setVisibleNotifications(notifications.slice(0, showCount)) + }, [notifications, showCount]) useEffect(() => { const options = { diff --git a/src/lib/notification.ts b/src/lib/notification.ts new file mode 100644 index 00000000..024d5e1d --- /dev/null +++ b/src/lib/notification.ts @@ -0,0 +1,35 @@ +import { kinds, NostrEvent } from 'nostr-tools' +import { isMentioningMutedUsers } from './event' +import { tagNameEquals } from './tag' + +export function notificationFilter( + event: NostrEvent, + { + pubkey, + mutePubkeySet, + hideContentMentioningMutedUsers, + hideUntrustedNotifications, + isUserTrusted + }: { + pubkey?: string | null + mutePubkeySet: Set + hideContentMentioningMutedUsers?: boolean + hideUntrustedNotifications?: boolean + isUserTrusted: (pubkey: string) => boolean + } +): boolean { + if ( + mutePubkeySet.has(event.pubkey) || + (hideContentMentioningMutedUsers && isMentioningMutedUsers(event, mutePubkeySet)) || + (hideUntrustedNotifications && !isUserTrusted(event.pubkey)) + ) { + return false + } + + if (pubkey && event.kind === kinds.Reaction) { + const targetPubkey = event.tags.findLast(tagNameEquals('p'))?.[1] + if (targetPubkey !== pubkey) return false + } + + return true +} diff --git a/src/providers/NotificationProvider.tsx b/src/providers/NotificationProvider.tsx index 0b37500d..6463c6bb 100644 --- a/src/providers/NotificationProvider.tsx +++ b/src/providers/NotificationProvider.tsx @@ -1,5 +1,6 @@ import { BIG_RELAY_URLS, ExtendedKind } from '@/constants' -import { compareEvents, isMentioningMutedUsers } from '@/lib/event' +import { compareEvents } from '@/lib/event' +import { notificationFilter } from '@/lib/notification' import { usePrimaryPage } from '@/PageManager' import client from '@/services/client.service' import storage from '@/services/local-storage.service' @@ -47,9 +48,13 @@ export function NotificationProvider({ children }: { children: React.ReactNode } break } if ( - mutePubkeySet.has(notification.pubkey) || - (hideContentMentioningMutedUsers && isMentioningMutedUsers(notification, mutePubkeySet)) || - (hideUntrustedNotifications && !isUserTrusted(notification.pubkey)) + !notificationFilter(notification, { + pubkey, + mutePubkeySet, + hideContentMentioningMutedUsers, + hideUntrustedNotifications, + isUserTrusted + }) ) { continue }