Suppress reminder toasts while lock screen is active

Swap LockProvider to outer wrapper so AlertsProvider can read isLocked.
When locked, dismiss all visible reminder toasts and skip firing new ones.
Toasts re-fire normally on unlock via the firedRef.clear() reset.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Kyle 2026-02-25 18:23:26 +08:00
parent 5ad0a610bd
commit 17643d54ea
2 changed files with 16 additions and 6 deletions

View File

@ -14,8 +14,8 @@ export default function AppLayout() {
const [mobileOpen, setMobileOpen] = useState(false); const [mobileOpen, setMobileOpen] = useState(false);
return ( return (
<AlertsProvider>
<LockProvider> <LockProvider>
<AlertsProvider>
<div className="flex h-screen overflow-hidden bg-background"> <div className="flex h-screen overflow-hidden bg-background">
<Sidebar <Sidebar
collapsed={collapsed} collapsed={collapsed}
@ -37,7 +37,7 @@ export default function AppLayout() {
</div> </div>
</div> </div>
<LockOverlay /> <LockOverlay />
</LockProvider>
</AlertsProvider> </AlertsProvider>
</LockProvider>
); );
} }

View File

@ -5,6 +5,7 @@ import { toast } from 'sonner';
import { Bell, X } from 'lucide-react'; import { Bell, X } from 'lucide-react';
import api from '@/lib/api'; import api from '@/lib/api';
import { getRelativeTime, toLocalDatetime } from '@/lib/date-utils'; import { getRelativeTime, toLocalDatetime } from '@/lib/date-utils';
import { useLock } from '@/hooks/useLock';
import SnoozeDropdown from '@/components/reminders/SnoozeDropdown'; import SnoozeDropdown from '@/components/reminders/SnoozeDropdown';
import type { Reminder } from '@/types'; import type { Reminder } from '@/types';
@ -29,6 +30,7 @@ export function useAlerts() {
export function AlertsProvider({ children }: { children: ReactNode }) { export function AlertsProvider({ children }: { children: ReactNode }) {
const queryClient = useQueryClient(); const queryClient = useQueryClient();
const location = useLocation(); const location = useLocation();
const { isLocked } = useLock();
const firedRef = useRef<Set<number>>(new Set()); const firedRef = useRef<Set<number>>(new Set());
const prevPathnameRef = useRef(location.pathname); const prevPathnameRef = useRef(location.pathname);
const isDashboard = location.pathname === '/' || location.pathname === '/dashboard'; const isDashboard = location.pathname === '/' || location.pathname === '/dashboard';
@ -186,12 +188,20 @@ export function AlertsProvider({ children }: { children: ReactNode }) {
} }
} }
// Unified toast management — single effect handles both route changes and new alerts // Unified toast management — single effect handles route changes, lock state, and new alerts
useEffect(() => { useEffect(() => {
const wasOnDashboard = prevPathnameRef.current === '/' || prevPathnameRef.current === '/dashboard'; const wasOnDashboard = prevPathnameRef.current === '/' || prevPathnameRef.current === '/dashboard';
const nowOnDashboard = isDashboard; const nowOnDashboard = isDashboard;
prevPathnameRef.current = location.pathname; prevPathnameRef.current = location.pathname;
// Suppress toasts while locked — dismiss any visible ones
if (isLocked) {
alerts.forEach((a) => toast.dismiss(`reminder-${a.id}`));
toast.dismiss('reminder-summary');
firedRef.current.clear();
return;
}
if (nowOnDashboard) { if (nowOnDashboard) {
// On dashboard — dismiss all toasts, banner takes over // On dashboard — dismiss all toasts, banner takes over
alerts.forEach((a) => toast.dismiss(`reminder-${a.id}`)); alerts.forEach((a) => toast.dismiss(`reminder-${a.id}`));
@ -207,7 +217,7 @@ export function AlertsProvider({ children }: { children: ReactNode }) {
// On non-dashboard page — fire toasts for any unfired alerts // On non-dashboard page — fire toasts for any unfired alerts
fireToasts(alerts); fireToasts(alerts);
}, [location.pathname, isDashboard, alerts]); }, [location.pathname, isDashboard, alerts, isLocked]);
return ( return (
<AlertsContext.Provider value={{ alerts, dismiss: handleDismiss, snooze: handleSnooze }}> <AlertsContext.Provider value={{ alerts, dismiss: handleDismiss, snooze: handleSnooze }}>