From 882fa8270b18cb8f21a2bc9965eb99d67dd422b4 Mon Sep 17 00:00:00 2001 From: Adam Setch Date: Mon, 26 Jan 2026 12:40:09 -0500 Subject: [PATCH] fix: inbox flicker during loading Signed-off-by: Adam Setch --- src/renderer/hooks/useNotifications.ts | 63 ++++++++++++++------------ src/renderer/routes/Notifications.tsx | 47 +++++++++++++++---- 2 files changed, 71 insertions(+), 39 deletions(-) diff --git a/src/renderer/hooks/useNotifications.ts b/src/renderer/hooks/useNotifications.ts index eaae98ddc..0a9236c4e 100644 --- a/src/renderer/hooks/useNotifications.ts +++ b/src/renderer/hooks/useNotifications.ts @@ -97,41 +97,44 @@ export const useNotifications = (): NotificationsState => { const fetchNotifications = useCallback( async (state: GitifyState) => { setStatus('loading'); - setGlobalError(null); - - const previousNotifications = notifications; - const fetchedNotifications = await getAllNotifications(state); - setNotifications(fetchedNotifications); - - // Set Global Error if all accounts have the same error - const allAccountsHaveErrors = - doesAllAccountsHaveErrors(fetchedNotifications); - const allAccountErrorsAreSame = - areAllAccountErrorsSame(fetchedNotifications); - - if (allAccountsHaveErrors) { - const accountError = fetchedNotifications[0].error; - setStatus('error'); - setGlobalError(allAccountErrorsAreSame ? accountError : null); - return; - } + try { + const previousNotifications = notifications; + const fetchedNotifications = await getAllNotifications(state); + setNotifications(fetchedNotifications); + + // Set Global Error if all accounts have the same error + const allAccountsHaveErrors = + doesAllAccountsHaveErrors(fetchedNotifications); + const allAccountErrorsAreSame = + areAllAccountErrorsSame(fetchedNotifications); + + if (allAccountsHaveErrors) { + const accountError = fetchedNotifications[0].error; + setStatus('error'); + setGlobalError(allAccountErrorsAreSame ? accountError : null); + return; + } - const diffNotifications = getNewNotifications( - previousNotifications, - fetchedNotifications, - ); + const diffNotifications = getNewNotifications( + previousNotifications, + fetchedNotifications, + ); - if (diffNotifications.length > 0) { - if (state.settings.playSound) { - raiseSoundNotification(state.settings.notificationVolume); - } + if (diffNotifications.length > 0) { + if (state.settings.playSound) { + raiseSoundNotification(state.settings.notificationVolume); + } - if (state.settings.showNotifications) { - raiseNativeNotification(diffNotifications); + if (state.settings.showNotifications) { + raiseNativeNotification(diffNotifications); + } } - } - setStatus('success'); + setStatus('success'); + setGlobalError(null); + } finally { + isFetchingRef.current = false; + } }, [notifications], ); diff --git a/src/renderer/routes/Notifications.tsx b/src/renderer/routes/Notifications.tsx index fcc24329b..a6f02c95b 100644 --- a/src/renderer/routes/Notifications.tsx +++ b/src/renderer/routes/Notifications.tsx @@ -1,4 +1,4 @@ -import { type FC, useMemo } from 'react'; +import { type FC, useMemo, useRef } from 'react'; import { useAppContext } from '../hooks/useAppContext'; @@ -14,28 +14,57 @@ export const NotificationsRoute: FC = () => { const { notifications, status, globalError, settings, hasNotifications } = useAppContext(); + // Store previous successful state + const prevStateRef = useRef({ + notifications, + status, + globalError, + hasNotifications, + }); + + // Update ref only if not loading + if (status !== 'loading') { + prevStateRef.current = { + notifications, + status, + globalError, + hasNotifications, + }; + } + + // Use previous state if loading + const displayState = + status === 'loading' + ? prevStateRef.current + : { + notifications, + status, + globalError, + hasNotifications, + }; + const hasMultipleAccounts = useMemo( - () => notifications.length > 1, - [notifications], + () => displayState.notifications.length > 1, + [displayState.notifications], ); const hasNoAccountErrors = useMemo( - () => notifications.every((account) => account.error === null), - [notifications], + () => displayState.notifications.every((account) => account.error === null), + [displayState.notifications], ); - if (status === 'error') { - return ; + if (displayState.status === 'error') { + return ; } - if (!hasNotifications && hasNoAccountErrors) { + if (!displayState.hasNotifications && hasNoAccountErrors) { return ; } return ( - {notifications.map((accountNotification) => { + {displayState.notifications.map((accountNotification) => { return (