From bd49723afcd48e2a73df0f41e03f682db2db0665 Mon Sep 17 00:00:00 2001 From: Taylor Ho Date: Sun, 23 Aug 2026 20:52:06 -0700 Subject: [PATCH] fix(desktop): preserve read state in activity windows Co-authored-by: Rizz <302abe414ca6e3134763d2539bfcf145aea2a63fe5f8455204ed602fd40cf381@buzz.block.builderlab.xyz> Signed-off-by: Taylor Ho --- .../features/channels/ui/ChannelScreen.tsx | 1 + .../ui/useChannelOpenReadState.test.mjs | 24 ++++++++++++++++++- .../channels/ui/useChannelOpenReadState.ts | 16 ++++++++++++- 3 files changed, 39 insertions(+), 2 deletions(-) diff --git a/desktop/src/features/channels/ui/ChannelScreen.tsx b/desktop/src/features/channels/ui/ChannelScreen.tsx index 39d569c141..3d2bee490e 100644 --- a/desktop/src/features/channels/ui/ChannelScreen.tsx +++ b/desktop/src/features/channels/ui/ChannelScreen.tsx @@ -217,6 +217,7 @@ export function ChannelScreen({ activeChannelId, activeChannel?.isMember, activeReadAt, + !isDedicatedActivityWindow, ); React.useEffect(() => { if (!activeChannelId) { diff --git a/desktop/src/features/channels/ui/useChannelOpenReadState.test.mjs b/desktop/src/features/channels/ui/useChannelOpenReadState.test.mjs index 4f54d8b309..f19f379031 100644 --- a/desktop/src/features/channels/ui/useChannelOpenReadState.test.mjs +++ b/desktop/src/features/channels/ui/useChannelOpenReadState.test.mjs @@ -1,7 +1,10 @@ import assert from "node:assert/strict"; import test from "node:test"; -import { getTopLevelInboxUnreadOverrideIds } from "./useChannelOpenReadState.ts"; +import { + getTopLevelInboxUnreadOverrideIds, + shouldAdvanceChannelReadState, +} from "./useChannelOpenReadState.ts"; test("opening a channel clears only its top-level Inbox overrides", () => { assert.deepEqual( @@ -23,3 +26,22 @@ test("opening a channel clears only its top-level Inbox overrides", () => { ["top-level"], ); }); + +test("passive activity companions never advance synced read state", () => { + assert.equal( + shouldAdvanceChannelReadState({ + activeChannelId: "general", + enabled: false, + isChannelMember: true, + }), + false, + ); + assert.equal( + shouldAdvanceChannelReadState({ + activeChannelId: "general", + enabled: true, + isChannelMember: true, + }), + true, + ); +}); diff --git a/desktop/src/features/channels/ui/useChannelOpenReadState.ts b/desktop/src/features/channels/ui/useChannelOpenReadState.ts index ff927c00bb..85a18b1e14 100644 --- a/desktop/src/features/channels/ui/useChannelOpenReadState.ts +++ b/desktop/src/features/channels/ui/useChannelOpenReadState.ts @@ -17,16 +17,29 @@ export function getTopLevelInboxUnreadOverrideIds( ); } +export function shouldAdvanceChannelReadState({ + activeChannelId, + enabled, + isChannelMember, +}: { + activeChannelId: string | null; + enabled: boolean; + isChannelMember: boolean | undefined; +}): boolean { + return enabled && activeChannelId !== null && isChannelMember !== false; +} + export function useChannelOpenReadState( activeChannelId: string | null, isChannelMember: boolean | undefined, activeReadAt: string | null, + enabled = true, ) { const { feedItemState, locallyUnreadFeedItems, markChannelRead } = useAppShell(); React.useEffect(() => { - if (!activeChannelId || isChannelMember === false) return; + if (!activeChannelId || !enabled || isChannelMember === false) return; for (const itemId of getTopLevelInboxUnreadOverrideIds( locallyUnreadFeedItems, activeChannelId, @@ -37,6 +50,7 @@ export function useChannelOpenReadState( }, [ activeChannelId, activeReadAt, + enabled, feedItemState.undoUnread, isChannelMember, locallyUnreadFeedItems,