@@ -67,6 +67,9 @@ export function DashboardAgent({
6767 // Work that finished behind a closed panel. Counted server-side on page load and refreshed
6868 // with the chat list; the wake poll doesn't carry it.
6969 const [ unreadWork , setUnreadWork ] = useState ( initialUnreadWork ) ;
70+ // A turn this tab started may finish after the panel closes; that is exactly the case the
71+ // dot exists for, so the poll has to be running when it lands.
72+ const [ turnStarted , setTurnStarted ] = useState ( false ) ;
7073 const toastedWakes = useRef ( new Set < string > ( ) ) ;
7174 // The toast source is recent deliveries, not unread, so the dedupe must survive a reload.
7275 useEffect ( ( ) => {
@@ -165,14 +168,16 @@ export function DashboardAgent({
165168 shouldPollWakeFeed ( {
166169 serverUnreadWakes : initialUnreadWakes ,
167170 serverHasActiveWatches : hasActiveWatches ,
171+ serverUnreadWork : initialUnreadWork ,
172+ turnInFlight : turnStarted ,
168173 organizationId : organization . id ,
169174 } )
170175 )
171176 setWatching ( true ) ;
172177 } ;
173178 sync ( ) ;
174179 return subscribeWatchActivity ( sync ) ;
175- } , [ organization . id , initialUnreadWakes , hasActiveWatches ] ) ;
180+ } , [ organization . id , initialUnreadWakes , hasActiveWatches , initialUnreadWork , turnStarted ] ) ;
176181
177182 useEffect ( ( ) => {
178183 if ( ! hasAccess || ! watching ) return ;
@@ -185,13 +190,19 @@ export function DashboardAgent({
185190 signal : AbortSignal . timeout ( UNREAD_REQUEST_TIMEOUT_MS ) ,
186191 } ) ;
187192 if ( ! res . ok ) return ;
188- const data = ( await res . json ( ) ) as { unreadWakes ?: number ; wakes ?: WatchWake [ ] } ;
193+ const data = ( await res . json ( ) ) as {
194+ unreadWakes ?: number ;
195+ unreadWork ?: number ;
196+ wakes ?: WatchWake [ ] ;
197+ } ;
189198 if ( cancelled ) return ;
190199 // The wakes list carries read ones too, so only unread ones are subtracted.
191200 const unreadInView = ( data . wakes ?? [ ] ) . filter (
192201 ( wake ) => wake . unread && wake . chatId === visibleChat . current
193202 ) . length ;
194203 setUnreadWakes ( Math . max ( 0 , ( data . unreadWakes ?? 0 ) - unreadInView ) ) ;
204+ // A chat open in the panel is being read right now, so it isn't unread work.
205+ setUnreadWork ( Math . max ( 0 , ( data . unreadWork ?? 0 ) - ( open && visibleChat . current ? 1 : 0 ) ) ) ;
195206
196207 const fresh = ( data . wakes ?? [ ] ) . filter ( ( wake ) => ! toastedWakes . current . has ( wake . watchId ) ) ;
197208 for ( const wake of fresh ) rememberToasted ( wake . watchId ) ;
0 commit comments