@@ -23,9 +23,10 @@ import {
2323} from "./panel-layout" ;
2424import { nextPendingTurnChatId } from "./pending-turn" ;
2525import { nextVisibleChat } from "./unread-counts" ;
26- import { planWakeToasts , startWakePolling , wakesToToast } from "./wake-poll" ;
26+ import { createWakePendingCount , startWakePolling , wakesToToast } from "./wake-poll" ;
2727import { shouldPollWakeFeed , subscribeWatchActivity } from "./watch-activity" ;
2828import {
29+ dismissWatchWakesSummaryToast ,
2930 showWatchWakesSummaryToast ,
3031 showWatchWakeToast ,
3132 WAKE_TOAST_MAX_INDIVIDUAL ,
@@ -101,8 +102,8 @@ export function DashboardAgent({
101102
102103 // The count the still-visible grouped toast claims. Consecutive polls add to it so a
103104 // later batch grows the summary instead of overwriting it with only its own count;
104- // reset when the user opens the panel from that toast .
105- const summaryPending = useRef ( 0 ) ;
105+ // reset when the user opens the panel, whichever route they took .
106+ const wakePending = useRef ( createWakePendingCount ( ) ) ;
106107
107108 // Switching environment re-runs the layout loader but does not remount it, so the seeds
108109 // above would keep the old environment's counts.
@@ -146,35 +147,58 @@ export function DashboardAgent({
146147 undefined
147148 ) ;
148149
149- const setPanelOpen = useCallback ( ( next : boolean ) => {
150- setOpen ( next ) ;
151- // Pending requests must be dropped or a stale one re-applies on the next open.
152- if ( ! next ) {
150+ // The single entry point for opening the panel — every open route must go through it.
151+ // Opening acknowledges the wakes counted so far, and the visible summary goes with the
152+ // count it was claiming.
153+ const openPanel = useCallback ( ( ) => {
154+ wakePending . current . acknowledge ( ) ;
155+ dismissWatchWakesSummaryToast ( ) ;
156+ setOpen ( true ) ;
157+ } , [ ] ) ;
158+
159+ const setPanelOpen = useCallback (
160+ ( next : boolean ) => {
161+ if ( next ) {
162+ openPanel ( ) ;
163+ return ;
164+ }
165+ setOpen ( false ) ;
166+ // Pending requests must be dropped or a stale one re-applies on the next open.
153167 visibleChat . current = null ;
154168 setFullscreen ( false ) ;
155169 writeAgentFullscreen ( false ) ;
156170 setRequestedMessage ( undefined ) ;
157171 setOpenChatRequest ( undefined ) ;
158172 setWatchRequest ( undefined ) ;
159- }
160- } , [ ] ) ;
173+ } ,
174+ [ openPanel ]
175+ ) ;
161176
162- const openChat = useCallback ( ( chatId : string ) => {
163- setOpen ( true ) ;
164- setOpenChatRequest ( ( current ) => ( { chatId, seq : ( current ?. seq ?? 0 ) + 1 } ) ) ;
165- } , [ ] ) ;
177+ const openChat = useCallback (
178+ ( chatId : string ) => {
179+ openPanel ( ) ;
180+ setOpenChatRequest ( ( current ) => ( { chatId, seq : ( current ?. seq ?? 0 ) + 1 } ) ) ;
181+ } ,
182+ [ openPanel ]
183+ ) ;
166184
167- const openWith = useCallback ( ( text : string ) => {
168- const trimmed = text . trim ( ) ;
169- if ( ! trimmed ) return ;
170- setOpen ( true ) ;
171- setRequestedMessage ( ( current ) => ( { text : trimmed , seq : ( current ?. seq ?? 0 ) + 1 } ) ) ;
172- } , [ ] ) ;
185+ const openWith = useCallback (
186+ ( text : string ) => {
187+ const trimmed = text . trim ( ) ;
188+ if ( ! trimmed ) return ;
189+ openPanel ( ) ;
190+ setRequestedMessage ( ( current ) => ( { text : trimmed , seq : ( current ?. seq ?? 0 ) + 1 } ) ) ;
191+ } ,
192+ [ openPanel ]
193+ ) ;
173194
174- const openWithWatch = useCallback ( ( spec : WatchSpec ) => {
175- setOpen ( true ) ;
176- setWatchRequest ( ( current ) => ( { spec, seq : ( current ?. seq ?? 0 ) + 1 } ) ) ;
177- } , [ ] ) ;
195+ const openWithWatch = useCallback (
196+ ( spec : WatchSpec ) => {
197+ openPanel ( ) ;
198+ setWatchRequest ( ( current ) => ( { spec, seq : ( current ?. seq ?? 0 ) + 1 } ) ) ;
199+ } ,
200+ [ openPanel ]
201+ ) ;
178202
179203 // Nothing to be woken about means nothing to poll for. The page load's unread count and
180204 // active-watch flag are the ungated signals; the browser's own memory of a watch starts the
@@ -230,17 +254,9 @@ export function DashboardAgent({
230254 for ( const wake of fresh ) rememberToasted ( wake . watchId ) ;
231255
232256 if ( fresh . length > 0 ) {
233- const { plan, pending } = planWakeToasts (
234- fresh ,
235- summaryPending . current ,
236- WAKE_TOAST_MAX_INDIVIDUAL
237- ) ;
238- summaryPending . current = pending ;
257+ const plan = wakePending . current . plan ( fresh , WAKE_TOAST_MAX_INDIVIDUAL ) ;
239258 if ( plan . mode === "summary" ) {
240- showWatchWakesSummaryToast ( plan . count , ( ) => {
241- summaryPending . current = 0 ;
242- setPanelOpen ( true ) ;
243- } ) ;
259+ showWatchWakesSummaryToast ( plan . count , ( ) => setPanelOpen ( true ) ) ;
244260 } else {
245261 for ( const wake of [ ...plan . wakes ] . reverse ( ) ) {
246262 showWatchWakeToast ( wake , openChat ) ;
0 commit comments