From 7f0524978c6cb9f0b2b21909b819191007a0c2c3 Mon Sep 17 00:00:00 2001 From: SkateSpots Date: Wed, 28 Oct 2026 18:31:45 +0700 Subject: [PATCH] feat: track unread NIP-17 group conversations --- src/pages/DirectMessagesPage.tsx | 8 +++++++- src/pages/GroupConversationPage.tsx | 12 +++++++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/pages/DirectMessagesPage.tsx b/src/pages/DirectMessagesPage.tsx index 3785211..771339b 100644 --- a/src/pages/DirectMessagesPage.tsx +++ b/src/pages/DirectMessagesPage.tsx @@ -80,8 +80,10 @@ function GroupPreview({ conversation }: { conversation: Conversation }) { const { t } = useTranslation(); const participants = conversation.participants ?? []; const { user } = useCurrentUser(); + const { getLastRead } = useDMRead(); const last = conversation.lastMessage; const isFromMe = last?.pubkey === user?.pubkey; + const unread = !!last && !isFromMe && last.createdAt > getLastRead(conversation.pubkey); const timeAgo = last ? formatDistanceToNow(new Date(last.createdAt * 1000), { addSuffix: true }) : ''; @@ -90,6 +92,7 @@ function GroupPreview({ conversation }: { conversation: Conversation }) { @@ -99,7 +102,10 @@ function GroupPreview({ conversation }: { conversation: Conversation }) {
-

{t('socialUi.dms.peopleCount', { count: participants.length })}

+

+ {t('socialUi.dms.peopleCount', { count: participants.length })} + {unread && } +

{timeAgo}

diff --git a/src/pages/GroupConversationPage.tsx b/src/pages/GroupConversationPage.tsx index 78cbee7..04fb38b 100644 --- a/src/pages/GroupConversationPage.tsx +++ b/src/pages/GroupConversationPage.tsx @@ -11,7 +11,8 @@ import { useTranslation } from '@/contexts/language'; import { useToast } from '@/hooks/useToast'; import { useNostrLogin } from '@nostrify/react/login'; import { hasNip44 as checkNip44 } from '@/lib/signerCapabilities'; -import { useGroupConversation, useSendDirectMessage } from '@/hooks/useDirectMessages'; +import { useGroupConversation, useSendDirectMessage, getGroupId } from '@/hooks/useDirectMessages'; +import { useDMRead } from '@/hooks/useDMRead'; import { useAuthor } from '@/hooks/useAuthor'; import { genUserName } from '@/lib/genUserName'; import { formatDistanceToNow } from '@/lib/dateFnsI18n'; @@ -54,11 +55,20 @@ export default function GroupConversationPage() { useSeoMeta({ title: t('socialUi.groupConversation.seoTitle') }); const { data: messages, isLoading, refetch, isRefetching } = useGroupConversation(allParticipants); + const { markRead } = useDMRead(); + const groupId = useMemo(() => getGroupId(allParticipants), [allParticipants]); useEffect(() => { messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' }); }, [messages]); + // Opening a group marks it read up to its newest message, same as 1:1 DMs. + useEffect(() => { + if (!messages || messages.length === 0) return; + const newest = messages.reduce((max, message) => Math.max(max, message.createdAt), 0); + markRead(groupId, newest); + }, [groupId, markRead, messages]); + if (!participantsParam || otherPubkeys.length === 0) { return ( <>