fix(notifications/threads): Wave-1 audit fixes (🔴 + web 🟠)
- T1 (🔴): markThreadAsRead no longer receipts the thread ROOT (a 2nd instance of the read-marker-corruption regression — opening a thread whose root is old re-lit the whole room). Extracted to a pure threadReceipt.ts + 5 regression tests. - N1 (🔴): favicon/tab-title unread count now sums only leaf rooms (was double- counting every ancestor-space aggregate in roomToUnread). - N2 (🔴): notifications/sounds dedupe on the event id, not the unread count — fixes "read a DM, next message never notifies again". - T4 (🟠): the thread notification path no longer re-gates on the room count, so an explicit per-thread "All replies" override in a Mentions-only room fires. - N3 (🟠): getUnreadInfos skips phantom {0,0} entries (muted-thread-only rooms no longer light the nav row / pollute unread filters). - N4 (🟠): the Receipt handler recomputes unread instead of blanket-DELETE, so a threaded receipt can't wipe a room's valid main-timeline badge. - T2 (🟠): thread "Jump to Latest" re-anchors the virtual window (was landing on a stale mid/old event). Gates: tsc/eslint/prettier clean, build OK, 678 tests. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -24,6 +24,7 @@ import {
|
||||
getUnreadInfo,
|
||||
getUnreadInfos,
|
||||
isNotificationEvent,
|
||||
roomHaveUnread,
|
||||
} from '../../utils/room';
|
||||
import { roomToParentsAtom } from './roomToParents';
|
||||
import { useStateEventCallback } from '../../hooks/useStateEventCallback';
|
||||
@@ -253,7 +254,20 @@ export const useBindRoomToUnreadAtom = (mx: MatrixClient, unreadAtom: typeof roo
|
||||
),
|
||||
);
|
||||
if (isMyReceipt) {
|
||||
setUnreadAtom({ type: 'DELETE', roomId: room.roomId });
|
||||
// Don't blanket-DELETE the room's unread on any receipt: a THREADED
|
||||
// receipt (reading one thread) would wipe the room's still-valid
|
||||
// main-timeline badge, and if the room was already read no
|
||||
// UnreadNotifications PUT follows to restore it. Recompute instead —
|
||||
// DELETE only when the room is genuinely fully read.
|
||||
const info = getUnreadInfo(
|
||||
room,
|
||||
getMutedThreads(threadNotificationsRef.current, room.roomId),
|
||||
);
|
||||
if (info.total === 0 && info.highlight === 0 && !roomHaveUnread(mx, room)) {
|
||||
setUnreadAtom({ type: 'DELETE', roomId: room.roomId });
|
||||
} else {
|
||||
setUnreadAtom({ type: 'PUT', unreadInfo: info });
|
||||
}
|
||||
}
|
||||
};
|
||||
mx.on(RoomEvent.Receipt, handleReceipt);
|
||||
|
||||
Reference in New Issue
Block a user