From 4ae6b1d5ea92f149429affa254270345972ac946 Mon Sep 17 00:00:00 2001 From: SkateSpots Date: Wed, 28 Oct 2026 22:43:52 +0700 Subject: [PATCH] feat: envelope-only DM unread in the bell --- src/components/NotificationBell.tsx | 26 +++++++++-- src/hooks/useDirectMessages.ts | 5 +++ src/hooks/useDmUnreadSummary.ts | 67 +++++++++++++++++++++++++++++ src/i18n/ca/batch2.ts | 1 + src/i18n/cs/drift.ts | 3 ++ src/i18n/de/drift.ts | 3 ++ src/i18n/el/drift.ts | 3 ++ src/i18n/en.ts | 1 + src/i18n/es.ts | 1 + src/i18n/eu/batch2.ts | 1 + src/i18n/fr/drift.ts | 3 ++ src/i18n/gl/batch2.ts | 1 + src/i18n/hi/batch2.ts | 1 + src/i18n/id/drift.ts | 3 ++ src/i18n/it/drift.ts | 3 ++ src/i18n/ja/drift.ts | 3 ++ src/i18n/ko/drift.ts | 3 ++ src/i18n/nl/drift.ts | 3 ++ src/i18n/pl/drift.ts | 3 ++ src/i18n/pt/drift.ts | 3 ++ src/i18n/ro/drift.ts | 3 ++ src/i18n/ru/drift.ts | 3 ++ src/i18n/sv/drift.ts | 3 ++ src/i18n/th/drift.ts | 3 ++ src/i18n/tr/drift.ts | 3 ++ src/i18n/uk/drift.ts | 3 ++ src/i18n/vi/drift.ts | 3 ++ src/i18n/zh-CN/drift.ts | 3 ++ src/i18n/zh-TW/drift.ts | 3 ++ src/lib/dmOwnWraps.ts | 31 +++++++++++++ src/pages/DirectMessagesPage.tsx | 8 +++- 31 files changed, 198 insertions(+), 5 deletions(-) create mode 100644 src/hooks/useDmUnreadSummary.ts create mode 100644 src/lib/dmOwnWraps.ts diff --git a/src/components/NotificationBell.tsx b/src/components/NotificationBell.tsx index b0c1934..04f9063 100644 --- a/src/components/NotificationBell.tsx +++ b/src/components/NotificationBell.tsx @@ -2,7 +2,7 @@ import { dateLocaleCode } from '@/lib/dateFnsI18n'; import { useEffect, useMemo, useState } from 'react'; import { Link } from 'react-router-dom'; import { nip19 } from 'nostr-tools'; -import { Bell, Users, Check, Loader2, EyeOff, Globe, CheckCheck, Heart, Radio, ArrowRight, Handshake } from 'lucide-react'; +import { Bell, Users, Check, Loader2, EyeOff, Globe, CheckCheck, Heart, Radio, ArrowRight, Handshake, MessageCircle } from 'lucide-react'; import { Button } from '@/components/ui/button'; import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover'; import { ScrollArea } from '@/components/ui/scroll-area'; @@ -18,6 +18,7 @@ import { ImageWithFallback } from '@/components/ImageWithFallback'; import { EmptyState as SharedEmptyState } from '@/components/EmptyState'; import { useCrewNotifications, useIsPendingMember } from '@/hooks/useCrewNotifications'; import { useCordnJoinNotifications } from '@/hooks/useCordnJoinNotifications'; +import { useDmUnreadSummary } from '@/hooks/useDmUnreadSummary'; import { useActivityNotifications } from '@/hooks/useActivityNotifications'; import { useTradeNotifications } from '@/hooks/useTradeNotifications'; import { useNotificationsRead } from '@/hooks/useNotificationsRead'; @@ -226,6 +227,7 @@ export function NotificationBell({ isLoading: cordnJoinLoading, dismiss: dismissCordnJoin, } = useCordnJoinNotifications(open); + const { unreadCount: unreadDms, markSeen: markDmEnvelopesSeen } = useDmUnreadSummary(!!user); const { lastRead, seenAt, markAllRead } = useNotificationsRead(); // Buying/selling steps: an offer on your listing, a counter it's your turn to @@ -285,7 +287,7 @@ export function NotificationBell({ ); // Badge = only UNACKNOWLEDGED items, so "Mark read" actually clears it. - const badgeTotal = unreadCrew + unreadActivity + unreadNewsletter + unreadTrades; + const badgeTotal = unreadCrew + unreadActivity + unreadNewsletter + unreadTrades + unreadDms; // Opening the bell marks social + crew as read (and newsletter, since the // News tab is right there). Newsletter read state also clears on the /newsletter page. @@ -359,7 +361,7 @@ export function NotificationBell({ {badgeTotal > 0 ? (