Description
In AnnouncementToastProvider, the useEffect cleanup only clears the outer 1500ms timer. The inner stagger timers (i * 800 per announcement) are never cleared. If the root layout unmounts during the stagger, late toast calls fire after cleanup.
File to change
surfsense_web/components/announcements/AnnouncementToastProvider.tsx (lines 64-82)
Current code
useEffect(() => {
if (hasChecked.current) return;
hasChecked.current = true;
const timer = setTimeout(() => {
// ...
for (let i = 0; i < importantUntoasted.length; i++) {
const announcement = importantUntoasted[i];
setTimeout(() => showAnnouncementToast(announcement), i * 800); // Not tracked!
}
}, 1500);
return () => clearTimeout(timer); // Only clears outer timer
}, []);
What to do
Track inner timer IDs and clear all in cleanup:
useEffect(() => {
if (hasChecked.current) return;
hasChecked.current = true;
const timerIds: ReturnType<typeof setTimeout>[] = [];
const outerTimer = setTimeout(() => {
// ...
for (let i = 0; i < importantUntoasted.length; i++) {
const announcement = importantUntoasted[i];
timerIds.push(
setTimeout(() => showAnnouncementToast(announcement), i * 800)
);
}
}, 1500);
return () => {
clearTimeout(outerTimer);
timerIds.forEach(clearTimeout);
};
}, []);
Acceptance criteria
- All stagger timers are cleared on cleanup
- Announcement toasts still appear with staggered timing on normal flow
Description
In
AnnouncementToastProvider, theuseEffectcleanup only clears the outer 1500ms timer. The inner stagger timers (i * 800per announcement) are never cleared. If the root layout unmounts during the stagger, late toast calls fire after cleanup.File to change
surfsense_web/components/announcements/AnnouncementToastProvider.tsx(lines 64-82)Current code
What to do
Track inner timer IDs and clear all in cleanup:
Acceptance criteria