From c1b6e9d3283517b5452af74e47b8b80c25f349c0 Mon Sep 17 00:00:00 2001 From: martincupela Date: Mon, 27 Jan 2025 17:37:19 +0100 Subject: [PATCH 1/3] fix: mark channel read for all incoming unread messages --- src/components/MessageList/MessageList.tsx | 1 - .../MessageList/VirtualizedMessageList.tsx | 1 - .../hooks/__tests__/useMarkRead.test.js | 399 ++++++++++++------ .../MessageList/hooks/useMarkRead.ts | 43 +- 4 files changed, 299 insertions(+), 145 deletions(-) diff --git a/src/components/MessageList/MessageList.tsx b/src/components/MessageList/MessageList.tsx index 21a9fcd884..ddeb86d192 100644 --- a/src/components/MessageList/MessageList.tsx +++ b/src/components/MessageList/MessageList.tsx @@ -131,7 +131,6 @@ const MessageListWithContext = < useMarkRead({ isMessageListScrolledToBottom, messageListIsThread: threadList, - unreadCount: channelUnreadUiState?.unread_messages ?? 0, wasMarkedUnread: !!channelUnreadUiState?.first_unread_message_id, }); diff --git a/src/components/MessageList/VirtualizedMessageList.tsx b/src/components/MessageList/VirtualizedMessageList.tsx index 897819525d..c87ddeb89f 100644 --- a/src/components/MessageList/VirtualizedMessageList.tsx +++ b/src/components/MessageList/VirtualizedMessageList.tsx @@ -344,7 +344,6 @@ const VirtualizedMessageListWithContext = < useMarkRead({ isMessageListScrolledToBottom, messageListIsThread: !!threadList, - unreadCount: channelUnreadUiState?.unread_messages ?? 0, wasMarkedUnread: !!channelUnreadUiState?.first_unread_message_id, }); diff --git a/src/components/MessageList/hooks/__tests__/useMarkRead.test.js b/src/components/MessageList/hooks/__tests__/useMarkRead.test.js index 11fb40889d..913d233065 100644 --- a/src/components/MessageList/hooks/__tests__/useMarkRead.test.js +++ b/src/components/MessageList/hooks/__tests__/useMarkRead.test.js @@ -29,153 +29,210 @@ const render = ({ channel, client, params }) => { return result.current; }; +const unreadLastMessageChannelData = () => { + const user = generateUser(); + const messages = [ + generateMessage({ created_at: new Date(1) }), + generateMessage({ created_at: new Date(2) }), + ]; + return { + messages, + read: [ + { + last_read: new Date(1).toISOString(), + last_read_message_id: messages[0].id, + unread_messages: 1, + user, + }, + ], + }; +}; + +const readLastMessageChannelData = () => { + const user = generateUser(); + const messages = [ + generateMessage({ created_at: new Date(1) }), + generateMessage({ created_at: new Date(2) }), + ]; + return { + messages, + read: [ + { + last_read: new Date(2).toISOString(), + last_read_message_id: messages[1].id, + unread_messages: 0, + user, + }, + ], + }; +}; + +const emptyChannelData = () => { + const user = generateUser(); + return { + messages: [], + read: [ + { + last_read: undefined, + last_read_message_id: undefined, + unread_messages: 0, + user, + }, + ], + }; +}; + describe('useMarkRead', () => { const shouldMarkReadParams = { isMessageListScrolledToBottom: true, markReadOnScrolledToBottom: true, messageListIsThread: false, - unreadCount: 1, wasMarkedUnread: false, }; beforeEach(jest.clearAllMocks); - describe.each([[visibilityChangeScenario], ['render'], ['message.new']])('on %s', (scenario) => { - it('should not mark channel read from thread message list', async () => { + describe.each([[visibilityChangeScenario], ['render']])('on %s', (scenario) => { + it('should mark channel read from non-thread message list scrolled to the bottom not previously marked unread with unread messages', async () => { + const channelData = unreadLastMessageChannelData(); const { channels: [channel], client, - } = await initClientWithChannels(); + } = await initClientWithChannels({ + channelsData: [channelData], + customUser: channelData.read[0].user, + }); - render({ + await render({ channel, client, - params: { - ...shouldMarkReadParams, - messageListIsThread: true, - }, + params: shouldMarkReadParams, }); if (scenario === visibilityChangeScenario) { - document.dispatchEvent(new Event('visibilitychange')); - } else if (scenario === 'message.new') { await act(() => { - dispatchMessageNewEvent(client, generateMessage(), channel); + document.dispatchEvent(new Event('visibilitychange')); }); - expect(setChannelUnreadUiState).not.toHaveBeenCalled(); + expect(markRead).toHaveBeenCalledTimes(2); + } else { + expect(markRead).toHaveBeenCalledTimes(1); } - expect(markRead).not.toHaveBeenCalled(); }); - it('should not mark channel read from message list not scrolled to the bottom', async () => { + it('should not mark channel read from non-thread message list scrolled to the bottom previously marked unread with unread messages', async () => { + const channelData = unreadLastMessageChannelData(); const { channels: [channel], client, - } = await initClientWithChannels(); + } = await initClientWithChannels({ + channelsData: [channelData], + customUser: channelData.read[0].user, + }); await render({ channel, client, - params: { - ...shouldMarkReadParams, - isMessageListScrolledToBottom: false, - }, + params: { ...shouldMarkReadParams, wasMarkedUnread: true }, + }); + expect(markRead).toHaveBeenCalledTimes(0); + }); + + it('should not mark channel read from non-thread message list scrolled to the bottom not previously marked unread with 0 unread messages', async () => { + const channelData = readLastMessageChannelData(); + const { + channels: [channel], + client, + } = await initClientWithChannels({ + channelsData: [channelData], + customUser: channelData.read[0].user, }); + await render({ + channel, + client, + params: shouldMarkReadParams, + }); if (scenario === visibilityChangeScenario) { - document.dispatchEvent(new Event('visibilitychange')); - } else if (scenario === 'message.new') { - let channelUnreadUiStateCb; - setChannelUnreadUiState.mockImplementationOnce((cb) => (channelUnreadUiStateCb = cb)); await act(() => { - dispatchMessageNewEvent(client, generateMessage(), channel); + document.dispatchEvent(new Event('visibilitychange')); }); - expect(setChannelUnreadUiState).toHaveBeenCalledTimes(1); - const channelUnreadUiState = channelUnreadUiStateCb(); - expect(channelUnreadUiState.unread_messages).toBe(1); } - expect(markRead).not.toHaveBeenCalled(); + expect(markRead).toHaveBeenCalledTimes(0); }); - it('should not mark channel read from message list in channel with 0 unread messages', async () => { + it('should not mark empty channel read', async () => { + const channelData = emptyChannelData(); const { channels: [channel], client, - } = await initClientWithChannels(); + } = await initClientWithChannels({ + channelsData: [channelData], + customUser: channelData.read[0].user, + }); - const countUnread = jest.spyOn(channel, 'countUnread').mockReturnValueOnce(0); + await render({ + channel, + client, + params: shouldMarkReadParams, + }); + if (scenario === visibilityChangeScenario) { + await act(() => { + document.dispatchEvent(new Event('visibilitychange')); + }); + } + expect(markRead).toHaveBeenCalledTimes(0); + }); + + it('should not mark channel read from message list not scrolled to the bottom', async () => { + const { + channels: [channel], + client, + } = await initClientWithChannels(); await render({ channel, client, params: { ...shouldMarkReadParams, - unreadCount: 0, + isMessageListScrolledToBottom: false, }, }); if (scenario === visibilityChangeScenario) { document.dispatchEvent(new Event('visibilitychange')); - } else if (scenario === 'message.new') { - await act(() => { - dispatchMessageNewEvent(client, generateMessage(), channel); - }); - expect(setChannelUnreadUiState).not.toHaveBeenCalled(); } - expect(markRead).not.toHaveBeenCalled(); - countUnread.mockRestore(); }); - it('should not mark channel read from non-thread message list scrolled to the bottom previously marked unread', async () => { + it('should not mark channel read from thread message list', async () => { const { channels: [channel], client, } = await initClientWithChannels(); - await render({ + render({ channel, client, params: { - shouldMarkReadParams, - wasMarkedUnread: true, + ...shouldMarkReadParams, + messageListIsThread: true, }, }); if (scenario === visibilityChangeScenario) { document.dispatchEvent(new Event('visibilitychange')); - } else if (scenario === 'message.new') { - let channelUnreadUiStateCb; - setChannelUnreadUiState.mockImplementationOnce((cb) => (channelUnreadUiStateCb = cb)); - await act(() => { - dispatchMessageNewEvent(client, generateMessage(), channel); - }); - expect(setChannelUnreadUiState).toHaveBeenCalledTimes(1); - const channelUnreadUiState = channelUnreadUiStateCb(); - expect(channelUnreadUiState.unread_messages).toBe(1); } - expect(markRead).not.toHaveBeenCalled(); }); + }); - it('should mark channel read from non-thread message list scrolled to the bottom not previously marked unread', async () => { - const user = generateUser(); - const messages = [generateMessage(), generateMessage()]; + describe('on message.new', () => { + it('should mark channel read from non-thread message list scrolled to the bottom not previously marked unread with unread messages', async () => { + const channelData = unreadLastMessageChannelData(); const { channels: [channel], client, } = await initClientWithChannels({ - channelsData: [ - { - messages, - read: [ - { - last_read: new Date(1).toISOString(), - unread_messages: messages.length, - user, - }, - ], - }, - ], - customUser: user, + channelsData: [channelData], + customUser: channelData.read[0].user, }); await render({ @@ -183,54 +240,126 @@ describe('useMarkRead', () => { client, params: shouldMarkReadParams, }); - if (scenario === visibilityChangeScenario) { - await act(() => { - document.dispatchEvent(new Event('visibilitychange')); - }); - expect(markRead).toHaveBeenCalledTimes(1); - } else if (scenario === 'message.new') { - await act(() => { - dispatchMessageNewEvent(client, generateMessage(), channel); - }); - expect(markRead).toHaveBeenCalledTimes(1); - expect(setChannelUnreadUiState).not.toHaveBeenCalled(); - } else { - expect(markRead).toHaveBeenCalledTimes(0); - } + + await act(() => { + dispatchMessageNewEvent(client, generateMessage(), channel); + }); + expect(markRead).toHaveBeenCalledTimes(2); + expect(setChannelUnreadUiState).not.toHaveBeenCalled(); }); - }); - describe('on message.new', () => { - it('should not mark channel read for messages incoming to other channels', async () => { + it('should mark channel read for own messages when scrolled to bottom in main message list', async () => { + const channelData = readLastMessageChannelData(); const { - channels: [activeChannel, otherChannel], + channels: [channel], client, - } = await initClientWithChannels({ channelsData: [generateChannel(), generateChannel()] }); + } = await initClientWithChannels({ + channelsData: [channelData], + customUser: channelData.read[0].user, + }); await render({ - channel: activeChannel, + channel, + client, + params: shouldMarkReadParams, + }); + + await act(() => { + dispatchMessageNewEvent( + client, + generateMessage({ user: channelData.read[0].user }), + channel, + ); + }); + + expect(markRead).toHaveBeenCalledTimes(1); + expect(setChannelUnreadUiState).not.toHaveBeenCalled(); + }); + + it('should mark channel read from non-thread message list scrolled to the bottom not previously marked unread with originally 0 unread messages', async () => { + const channelData = readLastMessageChannelData(); + const { + channels: [channel], + client, + } = await initClientWithChannels({ + channelsData: [channelData], + customUser: channelData.read[0].user, + }); + + await render({ + channel, + client, + params: shouldMarkReadParams, + }); + + await act(() => { + dispatchMessageNewEvent(client, generateMessage(), channel); + }); + expect(markRead).toHaveBeenCalledTimes(1); + expect(setChannelUnreadUiState).not.toHaveBeenCalled(); + }); + + it('should mark originally empty channel read', async () => { + const channelData = emptyChannelData(); + const { + channels: [channel], + client, + } = await initClientWithChannels({ + channelsData: [channelData], + customUser: channelData.read[0].user, + }); + + await render({ + channel, + client, + params: shouldMarkReadParams, + }); + + await act(() => { + dispatchMessageNewEvent(client, generateMessage(), channel); + }); + expect(markRead).toHaveBeenCalledTimes(1); + expect(setChannelUnreadUiState).not.toHaveBeenCalled(); + }); + + it('should not mark channel read from non-thread message list scrolled to the bottom previously marked unread', async () => { + const channelData = unreadLastMessageChannelData(); + const { + channels: [channel], + client, + } = await initClientWithChannels({ + channelsData: [channelData], + customUser: channelData.read[0].user, + }); + + await render({ + channel, client, params: { ...shouldMarkReadParams, - unreadCount: 0, + wasMarkedUnread: true, }, }); + let channelUnreadUiStateCb; + setChannelUnreadUiState.mockImplementationOnce((cb) => (channelUnreadUiStateCb = cb)); await act(() => { - dispatchMessageNewEvent(client, generateMessage(), otherChannel); + dispatchMessageNewEvent(client, generateMessage(), channel); }); - + expect(setChannelUnreadUiState).toHaveBeenCalledTimes(1); + const channelUnreadUiState = channelUnreadUiStateCb(); + expect(channelUnreadUiState.unread_messages).toBe(1); expect(markRead).not.toHaveBeenCalled(); - expect(setChannelUnreadUiState).not.toHaveBeenCalled(); }); - it('should not mark channel read for own messages', async () => { - const user = generateUser(); + it('should mark channel read from message list not scrolled to the bottom', async () => { + const channelData = readLastMessageChannelData(); const { channels: [channel], client, } = await initClientWithChannels({ - customUser: user, + channelsData: [channelData], + customUser: channelData.read[0].user, }); await render({ @@ -238,42 +367,71 @@ describe('useMarkRead', () => { client, params: { ...shouldMarkReadParams, - unreadCount: 0, + isMessageListScrolledToBottom: false, }, }); + let channelUnreadUiStateCb; + setChannelUnreadUiState.mockImplementationOnce((cb) => (channelUnreadUiStateCb = cb)); await act(() => { - dispatchMessageNewEvent(client, generateMessage({ user }), channel); + dispatchMessageNewEvent(client, generateMessage(), channel); }); - + expect(setChannelUnreadUiState).toHaveBeenCalledTimes(1); + const channelUnreadUiState = channelUnreadUiStateCb(); + expect(channelUnreadUiState.unread_messages).toBe(1); expect(markRead).not.toHaveBeenCalled(); - expect(setChannelUnreadUiState).not.toHaveBeenCalled(); }); - it('should not mark channel read for thread messages', async () => { + it('should not mark channel read from thread message list', async () => { + const channelData = readLastMessageChannelData(); const { channels: [channel], client, - } = await initClientWithChannels(); + } = await initClientWithChannels({ + channelsData: [channelData], + customUser: channelData.read[0].user, + }); - await render({ + render({ channel, client, params: { ...shouldMarkReadParams, - unreadCount: 0, + messageListIsThread: true, }, }); + await act(() => { + dispatchMessageNewEvent(client, generateMessage(), channel); + }); + expect(setChannelUnreadUiState).not.toHaveBeenCalled(); + expect(markRead).not.toHaveBeenCalled(); + }); + + it('should not mark channel read for messages incoming to other channels', async () => { + const channelData = readLastMessageChannelData(); + const { + channels: [activeChannel, otherChannel], + client, + } = await initClientWithChannels({ + channelsData: [channelData, generateChannel()], + customUser: channelData.read[0].user, + }); + + await render({ + channel: activeChannel, + client, + params: shouldMarkReadParams, + }); await act(() => { - dispatchMessageNewEvent(client, generateMessage({ parent_id: 'X' }), channel); + dispatchMessageNewEvent(client, generateMessage(), otherChannel); }); expect(markRead).not.toHaveBeenCalled(); expect(setChannelUnreadUiState).not.toHaveBeenCalled(); }); - it('should mark channel read for thread messages with event.show_in_channel enabled', async () => { + it('should not mark channel read for thread messages', async () => { const { channels: [channel], client, @@ -282,25 +440,18 @@ describe('useMarkRead', () => { await render({ channel, client, - params: { - ...shouldMarkReadParams, - unreadCount: 0, - }, + params: shouldMarkReadParams, }); await act(() => { - dispatchMessageNewEvent( - client, - generateMessage({ parent_id: 'X', show_in_channel: true }), - channel, - ); + dispatchMessageNewEvent(client, generateMessage({ parent_id: 'X' }), channel); }); - expect(markRead).toHaveBeenCalledTimes(1); + expect(markRead).not.toHaveBeenCalled(); expect(setChannelUnreadUiState).not.toHaveBeenCalled(); }); - it('should mark channel read for not-own messages when scrolled to bottom in main message list', async () => { + it('should mark channel read for thread messages with event.show_in_channel enabled', async () => { const { channels: [channel], client, @@ -309,14 +460,15 @@ describe('useMarkRead', () => { await render({ channel, client, - params: { - ...shouldMarkReadParams, - unreadCount: 0, - }, + params: shouldMarkReadParams, }); await act(() => { - dispatchMessageNewEvent(client, generateMessage(), channel); + dispatchMessageNewEvent( + client, + generateMessage({ parent_id: 'X', show_in_channel: true }), + channel, + ); }); expect(markRead).toHaveBeenCalledTimes(1); @@ -375,6 +527,7 @@ describe('useMarkRead', () => { const channelUnreadUiState = channelUnreadUiStateCb(); expect(channelUnreadUiState.unread_messages).toBe(1); }); + it('should be performed when document is hidden and is scrolled to the bottom', async () => { let channelUnreadUiStateCb; setChannelUnreadUiState.mockImplementationOnce((cb) => (channelUnreadUiStateCb = cb)); diff --git a/src/components/MessageList/hooks/useMarkRead.ts b/src/components/MessageList/hooks/useMarkRead.ts index 06a1bcf18e..c46ba42e13 100644 --- a/src/components/MessageList/hooks/useMarkRead.ts +++ b/src/components/MessageList/hooks/useMarkRead.ts @@ -1,17 +1,27 @@ -import { useEffect, useRef } from 'react'; +import { useEffect } from 'react'; import { StreamMessage, useChannelActionContext, useChannelStateContext, useChatContext, } from '../../../context'; -import { Event, MessageResponse } from 'stream-chat'; -import { DefaultStreamChatGenerics } from '../../../types'; +import type { Channel, Event, MessageResponse } from 'stream-chat'; +import type { DefaultStreamChatGenerics } from '../../../types'; + +const hasReadLastMessage = < + StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics +>( + channel: Channel, + userId: string, +) => { + const lastMessageIdInCurrentMessageSet = channel.state.messages.slice(-1)[0]?.id; + const lastReadMessageIdServer = channel.state.read[userId]?.last_read_message_id; + return lastMessageIdInCurrentMessageSet === lastReadMessageIdServer; +}; type UseMarkReadParams = { isMessageListScrolledToBottom: boolean; messageListIsThread: boolean; - unreadCount: number; wasMarkedUnread?: boolean; }; @@ -22,7 +32,6 @@ type UseMarkReadParams = { * 3. the channel was not marked unread by the user * @param isMessageListScrolledToBottom * @param messageListIsThread - * @param unreadCount * @param wasChannelMarkedUnread */ export const useMarkRead = < @@ -30,30 +39,28 @@ export const useMarkRead = < >({ isMessageListScrolledToBottom, messageListIsThread, - unreadCount, wasMarkedUnread, }: UseMarkReadParams) => { const { client } = useChatContext('useMarkRead'); const { markRead, setChannelUnreadUiState } = useChannelActionContext('useMarkRead'); const { channel } = useChannelStateContext('useMarkRead'); - const previousRenderMessageListScrolledToBottom = useRef(isMessageListScrolledToBottom); useEffect(() => { - const shouldMarkRead = (unreadMessages: number) => + const shouldMarkRead = () => !document.hidden && !wasMarkedUnread && !messageListIsThread && isMessageListScrolledToBottom && - unreadMessages > 0; + client.user?.id && + !hasReadLastMessage(channel, client.user.id); const onVisibilityChange = () => { - if (shouldMarkRead(channel.countUnread())) markRead(); + if (shouldMarkRead()) markRead(); }; const handleMessageNew = (event: Event) => { - const isOwnMessage = event.user?.id && event.user.id === client.user?.id; const mainChannelUpdated = !event.message?.parent_id || event.message?.show_in_channel; - if (isOwnMessage) return; + if (!isMessageListScrolledToBottom || wasMarkedUnread || document.hidden) { setChannelUnreadUiState((prev) => { const previousUnreadCount = prev?.unread_messages ?? 0; @@ -71,7 +78,7 @@ export const useMarkRead = < unread_messages: previousUnreadCount + 1, }; }); - } else if (mainChannelUpdated && shouldMarkRead(channel.countUnread())) { + } else if (mainChannelUpdated && shouldMarkRead()) { markRead(); } }; @@ -79,12 +86,9 @@ export const useMarkRead = < channel.on('message.new', handleMessageNew); document.addEventListener('visibilitychange', onVisibilityChange); - const hasScrolledToBottom = - previousRenderMessageListScrolledToBottom.current !== isMessageListScrolledToBottom && - isMessageListScrolledToBottom; - - if (hasScrolledToBottom && shouldMarkRead(channel.countUnread())) markRead(); - previousRenderMessageListScrolledToBottom.current = isMessageListScrolledToBottom; + if (shouldMarkRead()) { + markRead(); + } return () => { channel.off('message.new', handleMessageNew); @@ -97,7 +101,6 @@ export const useMarkRead = < markRead, messageListIsThread, setChannelUnreadUiState, - unreadCount, wasMarkedUnread, ]); }; From e654e89bb82c9d11cf9d7f2b06a17bb660549145 Mon Sep 17 00:00:00 2001 From: martincupela Date: Mon, 27 Jan 2025 18:03:08 +0100 Subject: [PATCH 2/3] test: remove tests that do not update the channel read state --- .../MessageList/__tests__/MessageList.test.js | 88 ------------------- 1 file changed, 88 deletions(-) diff --git a/src/components/MessageList/__tests__/MessageList.test.js b/src/components/MessageList/__tests__/MessageList.test.js index 8cf6deaa26..c92a33d458 100644 --- a/src/components/MessageList/__tests__/MessageList.test.js +++ b/src/components/MessageList/__tests__/MessageList.test.js @@ -370,94 +370,6 @@ describe('MessageList', () => { afterEach(jest.clearAllMocks); afterAll(jest.restoreAllMocks); - it('should keep displaying the unread messages separator when an unread channel is marked read on mount', async () => { - const user = generateUser(); - const last_read_message_id = 'X'; - const lastReadMessage = generateMessage({ id: last_read_message_id }); - const messages = [lastReadMessage, generateMessage(), generateMessage()]; - const { - channels: [channel], - client: chatClient, - } = await initClientWithChannels({ - channelsData: [ - { - messages, - read: [ - { - last_read: lastReadMessage.created_at.toISOString(), - last_read_message_id, - unread_messages: 2, - user, - }, - ], - }, - ], - customUser: user, - }); - - const markReadMock = jest - .spyOn(channel, 'markRead') - .mockReturnValueOnce(markReadApi(channel)); - - await act(() => { - renderComponent({ - channelProps: { channel }, - chatClient, - msgListProps: { messages }, - }); - }); - - expect(markReadMock).toHaveBeenCalledTimes(1); - expect(screen.queryByText(separatorText)).toBeInTheDocument(); - }); - - it('should display unread messages separator before the first message', async () => { - const user = generateUser(); - const messages = [generateMessage(), generateMessage()]; - const { - channels: [channel], - client: chatClient, - } = await initClientWithChannels({ - channelsData: [ - { - messages, - read: [ - { - last_read: new Date(1).toISOString(), - unread_messages: messages.length, - user, - }, - ], - }, - ], - customUser: user, - }); - - const markReadMock = jest.spyOn(channel, 'markRead').mockReturnValue(markReadApi(channel)); - const Message = () =>
; - let container; - - await act(() => { - const result = renderComponent({ - channelProps: { channel, Message }, - chatClient, - msgListProps: { messages }, - }); - container = result.container; - }); - const listItems = container.querySelectorAll('.str-chat__ul > *'); - expect(listItems).toHaveLength(4); - expect(listItems[1].firstChild).toMatchInlineSnapshot(` -
- Unread messages -
- `); - markReadMock.mockRestore(); - }); - it('should display unread messages separator when a channel is marked unread and remove it when marked read by markRead()', async () => { jest.useFakeTimers(); const markReadBtnTestId = 'test-mark-read'; From 1f8d7867a3c140c8d9bae58be1ae41d5f55333f6 Mon Sep 17 00:00:00 2001 From: martincupela Date: Tue, 28 Jan 2025 10:58:47 +0100 Subject: [PATCH 3/3] fix: determine last read message from the latest message list --- src/components/MessageList/hooks/useMarkRead.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/MessageList/hooks/useMarkRead.ts b/src/components/MessageList/hooks/useMarkRead.ts index c46ba42e13..b1bd357d36 100644 --- a/src/components/MessageList/hooks/useMarkRead.ts +++ b/src/components/MessageList/hooks/useMarkRead.ts @@ -14,9 +14,9 @@ const hasReadLastMessage = < channel: Channel, userId: string, ) => { - const lastMessageIdInCurrentMessageSet = channel.state.messages.slice(-1)[0]?.id; + const latestMessageIdInChannel = channel.state.latestMessages.slice(-1)[0]?.id; const lastReadMessageIdServer = channel.state.read[userId]?.last_read_message_id; - return lastMessageIdInCurrentMessageSet === lastReadMessageIdServer; + return latestMessageIdInChannel === lastReadMessageIdServer; }; type UseMarkReadParams = {