From 4940f1212f1cbf95d036216691be5bdea9979042 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A5=D0=B0=D0=BB=D0=B8=D0=BC=D0=BE=D0=B2=20=D0=A0=D1=83?= =?UTF-8?q?=D1=81=D1=82=D0=B0=D0=BC?= Date: Mon, 20 Apr 2026 23:20:39 +0300 Subject: [PATCH] Fix read receipts: mark visible messages as read immediately --- .../presentation/components/ChatView.tsx | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/client-web/src/modules/chats/presentation/components/ChatView.tsx b/client-web/src/modules/chats/presentation/components/ChatView.tsx index 861d295..5c95b42 100644 --- a/client-web/src/modules/chats/presentation/components/ChatView.tsx +++ b/client-web/src/modules/chats/presentation/components/ChatView.tsx @@ -573,6 +573,7 @@ export default function ChatView({ onStartCall, onStartGroupCall }: { onStartCal { root: scrollContainerRef.current, threshold: 0.1, + rootMargin: '0px', } ); @@ -584,7 +585,26 @@ export default function ChatView({ onStartCall, onStartGroupCall }: { onStartCal unreadElements.forEach((el: Element) => { const id = el.getAttribute('data-message-id'); if (id && !sentReadIdsRef.current.has(id)) { - observer.observe(el); + // Check if element is already visible + const rect = el.getBoundingClientRect(); + const containerRect = scrollContainerRef.current!.getBoundingClientRect(); + const isVisible = rect.top >= containerRect.top && rect.bottom <= containerRect.bottom; + + if (isVisible) { + // Mark as read immediately without waiting for intersection + const seqId = parseInt(el.getAttribute('data-sequence-id') || '0', 10); + if (seqId > 0) { + socket.emit('read_messages', { + chatId: activeChat, + lastReadMessageId: id, + lastReadSequenceId: seqId, + }); + useChatStore.getState().markRead(activeChat, user.id, seqId); + sentReadIdsRef.current.add(id); + } + } else { + observer.observe(el); + } } }); };