Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 19 additions & 1 deletion apps/meteor/client/views/room/body/hooks/useUnreadMessages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ export const useHandleUnread = (
const getMessage = Messages.use((state) => state.get);
const findFirstMessage = Messages.use((state) => state.findFirst);
const filterMessages = Messages.use((state) => state.filter);
const messagesCount = Messages.use((state) => state.records.size);

if (!chat) {
throw new Error('No ChatContext provided');
Expand All @@ -73,8 +74,9 @@ export const useHandleUnread = (
return;
}
setMessageJumpQueryStringParameter(message?._id);
chat.readStateManager.markAsRead();

@abhinavkrin abhinavkrin Jun 30, 2025

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seemed to be a fix for me. While clicking on the banner, It would take me to message. But when page is refreshed, the banner would reapper.

setUnreadCount(0);
}, [room._id, setUnreadCount, findFirstMessage, unread?.since]);
}, [room._id, setUnreadCount, findFirstMessage, unread?.since, chat.readStateManager]);

const handleMarkAsReadButtonClick = useCallback(() => {
chat.readStateManager.markAsRead();
Expand Down Expand Up @@ -181,6 +183,22 @@ export const useHandleUnread = (
[getMessage, setUnreadCount],
);

useEffect(() => {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we find an alternative to this use effect? As it is, this is going to run every time the messagesCount prop changes (basically on every message). It seems costly for an operation that only needs to happen when the room is initialized.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually this will run only once. In first run, the lastMessageDate will be set and there is a check to return early when lastMessageDate is set.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, this is not expensive tasks. It is used only at one or two places all over the client. Plus it only runs once and loops around few messages. Next runs, it returns early. I dont think it is expensive.

// When a room is first opened, there’s no “off-screen” message yet, so we set
// an initial baseline timestamp (the newest message’s ts) as our anchor.
// This ensures our unread-count logic only starts counting messages that arrive
// after the initial load, rather than everything already in the DOM.
if (lastMessageDate === undefined && messagesCount > 0) {
const newest = findFirstMessage(
(r) => r.rid === room._id,
(a, b) => b.ts.getTime() - a.ts.getTime(),
);
if (newest) {
setLastMessageDate(newest.ts);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should avoid changing the value of a state that is in the dependency list

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same.

}
}
}, [messagesCount, lastMessageDate, findFirstMessage, room._id]);

return {
innerRef: ref,
wrapperRef: messagesBoxRef,
Expand Down
14 changes: 13 additions & 1 deletion apps/meteor/tests/e2e/threads.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Users } from './fixtures/userStates';
import { HomeChannel } from './page-objects';
import { createTargetChannel } from './utils';
import { createTargetChannel, deleteChannel } from './utils';
import { expect, test } from './utils/test';

test.use({ storageState: Users.admin.state });
Expand All @@ -15,6 +15,18 @@ test.describe.serial('Threads', () => {
await page.goto('/home');
await poHomeChannel.sidenav.openChat(targetChannel);
});

test.afterAll(async ({ api }) => deleteChannel(api, targetChannel));

test('expect no unread banner when replying to a thread in a fresh channel', async ({ page }) => {
await poHomeChannel.content.sendMessage('parent for unread-banner test');
await poHomeChannel.content.openReplyInThread();
await poHomeChannel.content.sendMessageInThread('first thread reply');

await page.waitForTimeout(200);
Comment thread
jessicaschelly marked this conversation as resolved.
await expect(page.getByTitle('Mark as read')).not.toBeVisible();
});

test('expect thread message preview if alsoSendToChannel checkbox is checked', async ({ page }) => {
await poHomeChannel.content.sendMessage('this is a message for reply');
await page.locator('[data-qa-type="message"]').last().hover();
Expand Down
Loading