From 283c24942d97ef437b78be06920cd14ab9e5a0b5 Mon Sep 17 00:00:00 2001 From: Suriya Date: Wed, 8 Jul 2026 17:45:32 +0530 Subject: [PATCH] fix: stop the notification-permission toast from stacking AppContent was declared inline inside App(), making it a new component reference on every App render -- React would unmount/remount it each time, re-running its useEffect (generateToken + FCM listener setup) and re-showing the "Enable notifications" toast, which never auto-dismisses and has no dedup, so they piled up. Moved AppContent to a stable top-level component and added a one-per-tab guard on the toast itself as a second line of defense. --- src/App.js | 36 +++++++++++++---------- src/firebase_notification/notification.js | 11 ++++++- 2 files changed, 30 insertions(+), 17 deletions(-) diff --git a/src/App.js b/src/App.js index c3e98bb..3c38374 100644 --- a/src/App.js +++ b/src/App.js @@ -13,6 +13,26 @@ import useInactivityLogout from 'hooks/useInactivityLogout'; // ==============================|| APP - THEME, ROUTER, LOCAL ||============================== // +// Was previously declared inline inside App(), which made it a fresh +// component reference on every App render — React would unmount/remount it +// each time, re-firing its useEffect (and the FCM permission toast) on +// every App re-render instead of once per app load. +const AppContent = () => { + useInactivityLogout(); + + useEffect(() => { + generateToken(); + initFirebaseNotificationListener(); + }, []); + + return ( + <> + + + + ); +}; + const App = () => { const navigate = useNavigate(); useEffect(() => { @@ -21,22 +41,6 @@ const App = () => { } }, [navigate]); - const AppContent = () => { - useInactivityLogout(); - - useEffect(() => { - generateToken(); - initFirebaseNotificationListener(); - }, []); - - return ( - <> - - - - ); - }; - return ( <> diff --git a/src/firebase_notification/notification.js b/src/firebase_notification/notification.js index eb88714..413683f 100644 --- a/src/firebase_notification/notification.js +++ b/src/firebase_notification/notification.js @@ -22,6 +22,12 @@ const opentoast = (message, color, vertical = 'bottom') => { }); }; +// Notification.requestPermission() re-resolves with the browser's current +// (often already-decided) permission every time this runs. Without a guard, +// any repeat call — e.g. from a remount — re-shows the same permanent, +// non-auto-dismissing toast and they stack up. Only warn once per tab. +let notificationWarningShown = false; + // ===================== Generate FCM Token ===================== export const generateToken = async () => { try { @@ -29,7 +35,10 @@ export const generateToken = async () => { dispatch(setFcmPermission(permission)); if (permission !== 'granted') { - opentoast('Enable notifications to receive OTP, alerts, and updates', 'error'); + if (!notificationWarningShown) { + notificationWarningShown = true; + opentoast('Enable notifications to receive OTP, alerts, and updates', 'error'); + } return; }