From a50784129265514981e6a67f845d819d69df7066 Mon Sep 17 00:00:00 2001 From: Jure <44338+hoornet@users.noreply.github.com> Date: Mon, 30 Mar 2026 08:27:26 +0200 Subject: [PATCH] Hide follower events from notifications list, fix article bookmark tab Follower notifications (kind 3) now only appear in the Follows badge, not in the Notifications list where they were confusing since clicking them shows a contact list, not a note. Articles bookmarked via e-tag (pre-fix) now correctly appear under the Articles tab instead of Notes. --- src/components/bookmark/BookmarkView.tsx | 31 +++++++++++++++---- .../notifications/NotificationsView.tsx | 2 +- src/stores/notifications.ts | 6 ++-- 3 files changed, 29 insertions(+), 10 deletions(-) diff --git a/src/components/bookmark/BookmarkView.tsx b/src/components/bookmark/BookmarkView.tsx index 6f86ed8..c50535a 100644 --- a/src/components/bookmark/BookmarkView.tsx +++ b/src/components/bookmark/BookmarkView.tsx @@ -65,12 +65,21 @@ export function BookmarkView() { const events = cached .map((raw) => { try { return new NDKEvent(ndk, JSON.parse(raw)); } catch { return null; } }) .filter((e): e is NDKEvent => e !== null) - .filter((e) => bookmarkedIds.includes(e.id)) + .filter((e) => bookmarkedIds.includes(e.id)); + const cachedNotes = events.filter((e) => e.kind !== 30023) .sort((a, b) => (b.created_at ?? 0) - (a.created_at ?? 0)); - if (events.length > 0) { - setNotes(events); + const cachedArticles = events.filter((e) => e.kind === 30023); + if (cachedNotes.length > 0) { + setNotes(cachedNotes); setLoadingNotes(false); } + if (cachedArticles.length > 0) { + setArticles((prev) => { + const existingIds = new Set(prev.map((e) => e.id)); + return [...prev, ...cachedArticles.filter((e) => !existingIds.has(e.id))] + .sort((a, b) => (b.created_at ?? 0) - (a.created_at ?? 0)); + }); + } } } @@ -80,10 +89,20 @@ export function BookmarkView() { bookmarkedIds.map((id) => fetchNoteById(id)) ); if (!cancelled) { - const fetched = results - .filter((e): e is NDKEvent => e !== null) + const fetched = results.filter((e): e is NDKEvent => e !== null); + // Separate articles (kind 30023) bookmarked via e-tag from notes + const notesOnly = fetched.filter((e) => e.kind !== 30023) .sort((a, b) => (b.created_at ?? 0) - (a.created_at ?? 0)); - setNotes(fetched); + const articlesFromETag = fetched.filter((e) => e.kind === 30023); + setNotes(notesOnly); + // Merge any articles found via e-tag into the articles list + if (articlesFromETag.length > 0) { + setArticles((prev) => { + const existingIds = new Set(prev.map((e) => e.id)); + const merged = [...prev, ...articlesFromETag.filter((e) => !existingIds.has(e.id))]; + return merged.sort((a, b) => (b.created_at ?? 0) - (a.created_at ?? 0)); + }); + } // Save to DB for next time if (pubkey && fetched.length > 0) { dbSaveBookmarkedNotes(fetched.map((e) => JSON.stringify(e.rawEvent())), pubkey); diff --git a/src/components/notifications/NotificationsView.tsx b/src/components/notifications/NotificationsView.tsx index bc832d6..4b54162 100644 --- a/src/components/notifications/NotificationsView.tsx +++ b/src/components/notifications/NotificationsView.tsx @@ -18,7 +18,7 @@ export function NotificationsView() { } = useNotificationsStore(); const { mutedPubkeys, contentMatchesMutedKeyword } = useMuteStore(); const filteredNotifications = notifications.filter( - (e) => e.pubkey !== pubkey && !mutedPubkeys.includes(e.pubkey) && !contentMatchesMutedKeyword(e.content) + (e) => e.kind !== 3 && e.pubkey !== pubkey && !mutedPubkeys.includes(e.pubkey) && !contentMatchesMutedKeyword(e.content) ); useEffect(() => { diff --git a/src/stores/notifications.ts b/src/stores/notifications.ts index ec2403a..aeab823 100644 --- a/src/stores/notifications.ts +++ b/src/stores/notifications.ts @@ -104,7 +104,7 @@ export const useNotificationsStore = create((set, get) => ({ // Dedup kind 3 (follower) events by pubkey — keep only newest per person const dedupedEvents = dedupFollowers(events); - const unreadCount = dedupedEvents.filter((e) => !readIds.has(e.id!)).length; + const unreadCount = dedupedEvents.filter((e) => e.kind !== 3 && !readIds.has(e.id!)).length; debug.log("notif:db loaded", dedupedEvents.length, "notifications,", unreadCount, "unread"); set({ notifications: dedupedEvents, readIds, unreadCount, loading: false }); @@ -156,7 +156,7 @@ export const useNotificationsStore = create((set, get) => ({ .sort((a, b) => (b.created_at ?? 0) - (a.created_at ?? 0)) .slice(0, MAX_NOTIFICATIONS); - const unreadCount = merged.filter((e) => !readIds.has(e.id!)).length; + const unreadCount = merged.filter((e) => e.kind !== 3 && !readIds.has(e.id!)).length; debug.log("notif:set", merged.length, "notifications,", unreadCount, "unread"); set({ notifications: merged, unreadCount }); } catch { @@ -172,7 +172,7 @@ export const useNotificationsStore = create((set, get) => ({ const updated = new Set(readIds); updated.add(eventId); dbMarkNotificationRead([eventId]); - const unreadCount = notifications.filter((e) => !updated.has(e.id!)).length; + const unreadCount = notifications.filter((e) => e.kind !== 3 && !updated.has(e.id!)).length; set({ readIds: updated, unreadCount }); },