From 41a06531ae36142aa052b5d2ef369d1c79a75d3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Musia=C5=82?= Date: Mon, 16 Mar 2026 19:20:52 +0100 Subject: [PATCH 1/7] isolate modals from Expensify.tsx --- src/Expensify.tsx | 29 ++--------------------- src/ExpensifyGlobalModals.tsx | 44 +++++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 27 deletions(-) create mode 100644 src/ExpensifyGlobalModals.tsx diff --git a/src/Expensify.tsx b/src/Expensify.tsx index 0afde4a09222b..9a20cb1cef854 100644 --- a/src/Expensify.tsx +++ b/src/Expensify.tsx @@ -4,29 +4,22 @@ import React, {useCallback, useEffect, useLayoutEffect, useRef, useState} from ' import type {NativeEventSubscription} from 'react-native'; import {AppState, Platform} from 'react-native'; import Onyx from 'react-native-onyx'; -import DelegateNoAccessModalProvider from './components/DelegateNoAccessModalProvider'; -import EmojiPicker from './components/EmojiPicker/EmojiPicker'; -import GrowlNotification from './components/GrowlNotification'; import {useInitialURLActions} from './components/InitialURLContextProvider'; -import ProactiveAppReviewModalManager from './components/ProactiveAppReviewModalManager'; -import ScreenShareRequestModal from './components/ScreenShareRequestModal'; import AppleAuthWrapper from './components/SignInButtons/AppleAuthWrapper'; import SplashScreenHider from './components/SplashScreenHider'; -import UpdateAppModal from './components/UpdateAppModal'; import CONFIG from './CONFIG'; import CONST from './CONST'; import DeepLinkHandler from './DeepLinkHandler'; import DelegateAccessHandler from './DelegateAccessHandler'; +import ExpensifyGlobalModals from './ExpensifyGlobalModals'; import FullstoryInitHandler from './FullstoryInitHandler'; import useDebugShortcut from './hooks/useDebugShortcut'; import useIsAuthenticated from './hooks/useIsAuthenticated'; import useLocalize from './hooks/useLocalize'; import useOnyx from './hooks/useOnyx'; import {updateLastRoute} from './libs/actions/App'; -import * as EmojiPickerAction from './libs/actions/EmojiPickerAction'; import * as ActiveClientManager from './libs/ActiveClientManager'; import {isSafari} from './libs/Browser'; -import {growlRef} from './libs/Growl'; import Log from './libs/Log'; import migrateOnyx from './libs/migrateOnyx'; import Navigation from './libs/Navigation/Navigation'; @@ -37,8 +30,6 @@ import {endSpan, getSpan, startSpan} from './libs/telemetry/activeSpans'; import {cleanupMemoryTrackingTelemetry, initializeMemoryTrackingTelemetry} from './libs/telemetry/TelemetrySynchronizer'; import Visibility from './libs/Visibility'; import ONYXKEYS from './ONYXKEYS'; -import PopoverReportActionContextMenu from './pages/inbox/report/ContextMenu/PopoverReportActionContextMenu'; -import * as ReportActionContextMenu from './pages/inbox/report/ContextMenu/ReportActionContextMenu'; import PriorityModeHandler from './PriorityModeHandler'; import type {Route} from './ROUTES'; import {accountIDSelector} from './selectors/Session'; @@ -66,7 +57,6 @@ function Expensify() { const [accountID] = useOnyx(ONYXKEYS.SESSION, {selector: accountIDSelector}); const [lastRoute] = useOnyx(ONYXKEYS.LAST_ROUTE); const [isCheckingPublicRoom = true] = useOnyx(ONYXKEYS.IS_CHECKING_PUBLIC_ROOM, {initWithStoredValues: false}); - const [updateAvailable] = useOnyx(ONYXKEYS.UPDATE_AVAILABLE, {initWithStoredValues: false}); const [updateRequired] = useOnyx(ONYXKEYS.UPDATE_REQUIRED, {initWithStoredValues: false}); const [lastVisitedPath] = useOnyx(ONYXKEYS.LAST_VISITED_PATH); @@ -223,7 +213,6 @@ function Expensify() { const propsToLog = { isCheckingPublicRoom, updateRequired, - updateAvailable, isAuthenticated, lastVisitedPath, }; @@ -282,21 +271,7 @@ function Expensify() { return ( <> - {shouldInit && ( - <> - - - - - - {/* We include the modal for showing a new update at the top level so the option is always present. */} - {updateAvailable && !updateRequired ? : null} - {/* Proactive app review modal shown when user has completed a trigger action */} - - - - )} - + {shouldInit && } diff --git a/src/ExpensifyGlobalModals.tsx b/src/ExpensifyGlobalModals.tsx new file mode 100644 index 0000000000000..530d1292801f0 --- /dev/null +++ b/src/ExpensifyGlobalModals.tsx @@ -0,0 +1,44 @@ +import React from 'react'; +import DelegateNoAccessModalProvider from './components/DelegateNoAccessModalProvider'; +import EmojiPicker from './components/EmojiPicker/EmojiPicker'; +import GrowlNotification from './components/GrowlNotification'; +import ProactiveAppReviewModalManager from './components/ProactiveAppReviewModalManager'; +import ScreenShareRequestModal from './components/ScreenShareRequestModal'; +import UpdateAppModal from './components/UpdateAppModal'; +import useOnyx from './hooks/useOnyx'; +import * as EmojiPickerAction from './libs/actions/EmojiPickerAction'; +import {growlRef} from './libs/Growl'; +import ONYXKEYS from './ONYXKEYS'; +import PopoverReportActionContextMenu from './pages/inbox/report/ContextMenu/PopoverReportActionContextMenu'; +import * as ReportActionContextMenu from './pages/inbox/report/ContextMenu/ReportActionContextMenu'; + +type ExpensifyGlobalModalsProps = { + updateRequired: boolean | undefined; +}; + +/** + * Renders global modals and pickers (GrowlNotification, DelegateNoAccessModal, + * EmojiPicker, UpdateAppModal, etc.) that are mounted once at the top level. + */ +function ExpensifyGlobalModals({updateRequired}: ExpensifyGlobalModalsProps) { + const [updateAvailable] = useOnyx(ONYXKEYS.UPDATE_AVAILABLE, {initWithStoredValues: false}); + + return ( + <> + + + {/* eslint-disable-next-line react-hooks/refs -- module-level createRef, safe to pass as ref prop */} + + + {/* eslint-disable-next-line react-hooks/refs -- module-level createRef, safe to pass as ref prop */} + + {updateAvailable && !updateRequired ? : null} + + + + ); +} + +ExpensifyGlobalModals.displayName = 'ExpensifyGlobalModals'; + +export default React.memo(ExpensifyGlobalModals); From d3eaf166bc76fc27225f9c0bf0a2dbc75a6f77db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Musia=C5=82?= Date: Tue, 17 Mar 2026 10:11:35 +0100 Subject: [PATCH 2/7] cleanup after merge main --- src/Expensify.tsx | 1 - src/ExpensifyGlobalModals.tsx | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Expensify.tsx b/src/Expensify.tsx index d60c0600dcc72..ddd92cde21008 100644 --- a/src/Expensify.tsx +++ b/src/Expensify.tsx @@ -57,7 +57,6 @@ function Expensify() { const [accountID] = useOnyx(ONYXKEYS.SESSION, {selector: accountIDSelector}); const [lastRoute] = useOnyx(ONYXKEYS.LAST_ROUTE); const [isCheckingPublicRoom = true] = useOnyx(ONYXKEYS.RAM_ONLY_IS_CHECKING_PUBLIC_ROOM); - const [updateAvailable] = useOnyx(ONYXKEYS.RAM_ONLY_UPDATE_AVAILABLE); const [updateRequired] = useOnyx(ONYXKEYS.RAM_ONLY_UPDATE_REQUIRED); const [lastVisitedPath] = useOnyx(ONYXKEYS.LAST_VISITED_PATH); diff --git a/src/ExpensifyGlobalModals.tsx b/src/ExpensifyGlobalModals.tsx index 530d1292801f0..7db17b45bee70 100644 --- a/src/ExpensifyGlobalModals.tsx +++ b/src/ExpensifyGlobalModals.tsx @@ -21,7 +21,7 @@ type ExpensifyGlobalModalsProps = { * EmojiPicker, UpdateAppModal, etc.) that are mounted once at the top level. */ function ExpensifyGlobalModals({updateRequired}: ExpensifyGlobalModalsProps) { - const [updateAvailable] = useOnyx(ONYXKEYS.UPDATE_AVAILABLE, {initWithStoredValues: false}); + const [updateAvailable] = useOnyx(ONYXKEYS.RAM_ONLY_UPDATE_AVAILABLE); return ( <> From b3729c107f315eb61ecd42effef3549cd31296c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Musia=C5=82?= Date: Tue, 17 Mar 2026 11:08:49 +0100 Subject: [PATCH 3/7] remove redundant memo --- src/ExpensifyGlobalModals.tsx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/ExpensifyGlobalModals.tsx b/src/ExpensifyGlobalModals.tsx index 7db17b45bee70..cb93e47bdc59b 100644 --- a/src/ExpensifyGlobalModals.tsx +++ b/src/ExpensifyGlobalModals.tsx @@ -39,6 +39,4 @@ function ExpensifyGlobalModals({updateRequired}: ExpensifyGlobalModalsProps) { ); } -ExpensifyGlobalModals.displayName = 'ExpensifyGlobalModals'; - -export default React.memo(ExpensifyGlobalModals); +export default ExpensifyGlobalModals; From 04aadfa2db407509f1c984361ca9a3c1f8a19285 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Musia=C5=82?= Date: Thu, 19 Mar 2026 16:13:24 +0100 Subject: [PATCH 4/7] move most modals to be only available from Authenticated users context --- ...odals.tsx => AuthenticatedGlobalModals.tsx} | 18 ++++-------------- src/Expensify.tsx | 6 ++++-- ...seUpdateAppModal.tsx => UpdateAppModal.tsx} | 15 ++++++++------- src/components/UpdateAppModal/index.tsx | 14 -------------- src/components/UpdateAppModal/types.ts | 6 ------ .../Navigation/AppNavigator/AuthScreens.tsx | 2 ++ 6 files changed, 18 insertions(+), 43 deletions(-) rename src/{ExpensifyGlobalModals.tsx => AuthenticatedGlobalModals.tsx} (68%) rename src/components/{UpdateAppModal/BaseUpdateAppModal.tsx => UpdateAppModal.tsx} (74%) delete mode 100644 src/components/UpdateAppModal/index.tsx delete mode 100644 src/components/UpdateAppModal/types.ts diff --git a/src/ExpensifyGlobalModals.tsx b/src/AuthenticatedGlobalModals.tsx similarity index 68% rename from src/ExpensifyGlobalModals.tsx rename to src/AuthenticatedGlobalModals.tsx index 280ca19cd0aae..0e581cae0f6e3 100644 --- a/src/ExpensifyGlobalModals.tsx +++ b/src/AuthenticatedGlobalModals.tsx @@ -4,25 +4,15 @@ import EmojiPicker from './components/EmojiPicker/EmojiPicker'; import GrowlNotification from './components/GrowlNotification'; import ProactiveAppReviewModalManager from './components/ProactiveAppReviewModalManager'; import ScreenShareRequestModal from './components/ScreenShareRequestModal'; -import UpdateAppModal from './components/UpdateAppModal'; -import useOnyx from './hooks/useOnyx'; import * as EmojiPickerAction from './libs/actions/EmojiPickerAction'; import {growlRef} from './libs/Growl'; -import ONYXKEYS from './ONYXKEYS'; import PopoverReportActionContextMenu from './pages/inbox/report/ContextMenu/PopoverReportActionContextMenu'; import * as ReportActionContextMenu from './pages/inbox/report/ContextMenu/ReportActionContextMenu'; -type ExpensifyGlobalModalsProps = { - updateRequired: boolean | undefined; -}; - /** - * Renders global modals and pickers (GrowlNotification, DelegateNoAccessModal, - * EmojiPicker, UpdateAppModal, etc.) that are mounted once at the top level. + * Renders global modals and overlays that require an authenticated session and are mounted once at the top level. */ -function ExpensifyGlobalModals({updateRequired}: ExpensifyGlobalModalsProps) { - const [updateAvailable] = useOnyx(ONYXKEYS.UPDATE_AVAILABLE); - +function AuthenticatedGlobalModals() { return ( <> @@ -32,11 +22,11 @@ function ExpensifyGlobalModals({updateRequired}: ExpensifyGlobalModalsProps) { {/* eslint-disable-next-line react-hooks/refs -- module-level createRef, safe to pass as ref prop */} - {updateAvailable && !updateRequired ? : null} + {/* Proactive app review modal shown when user has completed a trigger action */} ); } -export default ExpensifyGlobalModals; +export default AuthenticatedGlobalModals; diff --git a/src/Expensify.tsx b/src/Expensify.tsx index 9a20cb1cef854..4d06bd8e62b6c 100644 --- a/src/Expensify.tsx +++ b/src/Expensify.tsx @@ -7,11 +7,11 @@ import Onyx from 'react-native-onyx'; import {useInitialURLActions} from './components/InitialURLContextProvider'; import AppleAuthWrapper from './components/SignInButtons/AppleAuthWrapper'; import SplashScreenHider from './components/SplashScreenHider'; +import UpdateAppModal from './components/UpdateAppModal'; import CONFIG from './CONFIG'; import CONST from './CONST'; import DeepLinkHandler from './DeepLinkHandler'; import DelegateAccessHandler from './DelegateAccessHandler'; -import ExpensifyGlobalModals from './ExpensifyGlobalModals'; import FullstoryInitHandler from './FullstoryInitHandler'; import useDebugShortcut from './hooks/useDebugShortcut'; import useIsAuthenticated from './hooks/useIsAuthenticated'; @@ -57,6 +57,7 @@ function Expensify() { const [accountID] = useOnyx(ONYXKEYS.SESSION, {selector: accountIDSelector}); const [lastRoute] = useOnyx(ONYXKEYS.LAST_ROUTE); const [isCheckingPublicRoom = true] = useOnyx(ONYXKEYS.IS_CHECKING_PUBLIC_ROOM, {initWithStoredValues: false}); + const [updateAvailable] = useOnyx(ONYXKEYS.UPDATE_AVAILABLE, {initWithStoredValues: false}); const [updateRequired] = useOnyx(ONYXKEYS.UPDATE_REQUIRED, {initWithStoredValues: false}); const [lastVisitedPath] = useOnyx(ONYXKEYS.LAST_VISITED_PATH); @@ -212,6 +213,7 @@ function Expensify() { if (splashScreenState === CONST.BOOT_SPLASH_STATE.VISIBLE) { const propsToLog = { isCheckingPublicRoom, + updateAvailable, updateRequired, isAuthenticated, lastVisitedPath, @@ -271,7 +273,7 @@ function Expensify() { return ( <> - {shouldInit && } + {shouldInit && !!updateAvailable && } diff --git a/src/components/UpdateAppModal/BaseUpdateAppModal.tsx b/src/components/UpdateAppModal.tsx similarity index 74% rename from src/components/UpdateAppModal/BaseUpdateAppModal.tsx rename to src/components/UpdateAppModal.tsx index 2f01f4ff72e09..092f2f0a4fa57 100755 --- a/src/components/UpdateAppModal/BaseUpdateAppModal.tsx +++ b/src/components/UpdateAppModal.tsx @@ -1,12 +1,15 @@ import React, {useState} from 'react'; -import ConfirmModal from '@components/ConfirmModal'; import useLocalize from '@hooks/useLocalize'; -import type UpdateAppModalProps from './types'; +import ConfirmModal from './ConfirmModal'; -function BaseUpdateAppModal({onSubmit}: UpdateAppModalProps) { +type UpdateAppModalProps = { + /** Callback to fire when we want to trigger the update. */ + onSubmit?: () => void; +}; + +function UpdateAppModal({onSubmit}: UpdateAppModalProps) { const [isModalOpen, setIsModalOpen] = useState(true); const {translate} = useLocalize(); - /** * Execute the onSubmit callback and close the modal. */ @@ -28,6 +31,4 @@ function BaseUpdateAppModal({onSubmit}: UpdateAppModalProps) { ); } -BaseUpdateAppModal.displayName = 'BaseUpdateAppModal'; - -export default React.memo(BaseUpdateAppModal); +export default UpdateAppModal; diff --git a/src/components/UpdateAppModal/index.tsx b/src/components/UpdateAppModal/index.tsx deleted file mode 100644 index 654f1cfbf03cd..0000000000000 --- a/src/components/UpdateAppModal/index.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import React from 'react'; -import BaseUpdateAppModal from './BaseUpdateAppModal'; -import type UpdateAppModalProps from './types'; - -function UpdateAppModal(props: UpdateAppModalProps) { - return ( - - ); -} - -export default UpdateAppModal; diff --git a/src/components/UpdateAppModal/types.ts b/src/components/UpdateAppModal/types.ts deleted file mode 100644 index ae57de671db63..0000000000000 --- a/src/components/UpdateAppModal/types.ts +++ /dev/null @@ -1,6 +0,0 @@ -type UpdateAppModalProps = { - /** Callback to fire when we want to trigger the update. */ - onSubmit?: () => void; -}; - -export default UpdateAppModalProps; diff --git a/src/libs/Navigation/AppNavigator/AuthScreens.tsx b/src/libs/Navigation/AppNavigator/AuthScreens.tsx index 6bd0c360aebab..c22a9b59b71fb 100644 --- a/src/libs/Navigation/AppNavigator/AuthScreens.tsx +++ b/src/libs/Navigation/AppNavigator/AuthScreens.tsx @@ -31,6 +31,7 @@ import NotFoundPage from '@pages/ErrorPage/NotFoundPage'; import RequireTwoFactorAuthenticationOverlay from '@pages/RequireTwoFactorAuthenticationOverlay'; import WorkspacesListPage from '@pages/workspace/WorkspacesListPage'; import * as Modal from '@userActions/Modal'; +import AuthenticatedGlobalModals from '@src/AuthenticatedGlobalModals'; import CONST from '@src/CONST'; import '@src/libs/subscribeToFullReconnect'; import NAVIGATORS from '@src/NAVIGATORS'; @@ -174,6 +175,7 @@ function AuthScreens() { + Date: Thu, 19 Mar 2026 17:04:15 +0100 Subject: [PATCH 5/7] revert to previous approach --- src/Expensify.tsx | 4 +- src/GlobalModals.tsx | 39 +++++++++++++++++++ .../Navigation/AppNavigator/AuthScreens.tsx | 2 - 3 files changed, 41 insertions(+), 4 deletions(-) create mode 100644 src/GlobalModals.tsx diff --git a/src/Expensify.tsx b/src/Expensify.tsx index 4d06bd8e62b6c..d11db448be016 100644 --- a/src/Expensify.tsx +++ b/src/Expensify.tsx @@ -7,12 +7,12 @@ import Onyx from 'react-native-onyx'; import {useInitialURLActions} from './components/InitialURLContextProvider'; import AppleAuthWrapper from './components/SignInButtons/AppleAuthWrapper'; import SplashScreenHider from './components/SplashScreenHider'; -import UpdateAppModal from './components/UpdateAppModal'; import CONFIG from './CONFIG'; import CONST from './CONST'; import DeepLinkHandler from './DeepLinkHandler'; import DelegateAccessHandler from './DelegateAccessHandler'; import FullstoryInitHandler from './FullstoryInitHandler'; +import GlobalModals from './GlobalModals'; import useDebugShortcut from './hooks/useDebugShortcut'; import useIsAuthenticated from './hooks/useIsAuthenticated'; import useLocalize from './hooks/useLocalize'; @@ -273,7 +273,7 @@ function Expensify() { return ( <> - {shouldInit && !!updateAvailable && } + {shouldInit && } diff --git a/src/GlobalModals.tsx b/src/GlobalModals.tsx new file mode 100644 index 0000000000000..40719a43d4b38 --- /dev/null +++ b/src/GlobalModals.tsx @@ -0,0 +1,39 @@ +import React from 'react'; +import DelegateNoAccessModalProvider from './components/DelegateNoAccessModalProvider'; +import EmojiPicker from './components/EmojiPicker/EmojiPicker'; +import GrowlNotification from './components/GrowlNotification'; +import ProactiveAppReviewModalManager from './components/ProactiveAppReviewModalManager'; +import ScreenShareRequestModal from './components/ScreenShareRequestModal'; +import UpdateAppModal from './components/UpdateAppModal'; +import * as EmojiPickerAction from './libs/actions/EmojiPickerAction'; +import {growlRef} from './libs/Growl'; +import PopoverReportActionContextMenu from './pages/inbox/report/ContextMenu/PopoverReportActionContextMenu'; +import * as ReportActionContextMenu from './pages/inbox/report/ContextMenu/ReportActionContextMenu'; + +type GlobalModalsProps = { + updateAvailable?: boolean; +}; + +/** + * Renders global modals and overlays that are mounted once at the top level. + */ +function GlobalModals({updateAvailable}: GlobalModalsProps) { + return ( + <> + {!!updateAvailable && } + {/* Those below are only available to the authenticated user. */} + + + {/* eslint-disable-next-line react-hooks/refs -- module-level createRef, safe to pass as ref prop */} + + + {/* eslint-disable-next-line react-hooks/refs -- module-level createRef, safe to pass as ref prop */} + + {/* Proactive app review modal shown when user has completed a trigger action */} + + + + ); +} + +export default GlobalModals; diff --git a/src/libs/Navigation/AppNavigator/AuthScreens.tsx b/src/libs/Navigation/AppNavigator/AuthScreens.tsx index c22a9b59b71fb..6bd0c360aebab 100644 --- a/src/libs/Navigation/AppNavigator/AuthScreens.tsx +++ b/src/libs/Navigation/AppNavigator/AuthScreens.tsx @@ -31,7 +31,6 @@ import NotFoundPage from '@pages/ErrorPage/NotFoundPage'; import RequireTwoFactorAuthenticationOverlay from '@pages/RequireTwoFactorAuthenticationOverlay'; import WorkspacesListPage from '@pages/workspace/WorkspacesListPage'; import * as Modal from '@userActions/Modal'; -import AuthenticatedGlobalModals from '@src/AuthenticatedGlobalModals'; import CONST from '@src/CONST'; import '@src/libs/subscribeToFullReconnect'; import NAVIGATORS from '@src/NAVIGATORS'; @@ -175,7 +174,6 @@ function AuthScreens() { - Date: Thu, 19 Mar 2026 17:06:15 +0100 Subject: [PATCH 6/7] cleanup --- src/AuthenticatedGlobalModals.tsx | 32 ------------------------------- src/Expensify.tsx | 2 +- 2 files changed, 1 insertion(+), 33 deletions(-) delete mode 100644 src/AuthenticatedGlobalModals.tsx diff --git a/src/AuthenticatedGlobalModals.tsx b/src/AuthenticatedGlobalModals.tsx deleted file mode 100644 index 0e581cae0f6e3..0000000000000 --- a/src/AuthenticatedGlobalModals.tsx +++ /dev/null @@ -1,32 +0,0 @@ -import React from 'react'; -import DelegateNoAccessModalProvider from './components/DelegateNoAccessModalProvider'; -import EmojiPicker from './components/EmojiPicker/EmojiPicker'; -import GrowlNotification from './components/GrowlNotification'; -import ProactiveAppReviewModalManager from './components/ProactiveAppReviewModalManager'; -import ScreenShareRequestModal from './components/ScreenShareRequestModal'; -import * as EmojiPickerAction from './libs/actions/EmojiPickerAction'; -import {growlRef} from './libs/Growl'; -import PopoverReportActionContextMenu from './pages/inbox/report/ContextMenu/PopoverReportActionContextMenu'; -import * as ReportActionContextMenu from './pages/inbox/report/ContextMenu/ReportActionContextMenu'; - -/** - * Renders global modals and overlays that require an authenticated session and are mounted once at the top level. - */ -function AuthenticatedGlobalModals() { - return ( - <> - - - {/* eslint-disable-next-line react-hooks/refs -- module-level createRef, safe to pass as ref prop */} - - - {/* eslint-disable-next-line react-hooks/refs -- module-level createRef, safe to pass as ref prop */} - - {/* Proactive app review modal shown when user has completed a trigger action */} - - - - ); -} - -export default AuthenticatedGlobalModals; diff --git a/src/Expensify.tsx b/src/Expensify.tsx index d11db448be016..707d89b6a9e87 100644 --- a/src/Expensify.tsx +++ b/src/Expensify.tsx @@ -213,8 +213,8 @@ function Expensify() { if (splashScreenState === CONST.BOOT_SPLASH_STATE.VISIBLE) { const propsToLog = { isCheckingPublicRoom, - updateAvailable, updateRequired, + updateAvailable, isAuthenticated, lastVisitedPath, }; From 0e6ad22cbe6b551f34d19ba7c7504707088f3360 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Musia=C5=82?= Date: Fri, 20 Mar 2026 10:49:23 +0100 Subject: [PATCH 7/7] move updateAvailable subscription inside the modal --- src/Expensify.tsx | 4 +--- src/GlobalModals.tsx | 8 ++------ src/components/UpdateAppModal.tsx | 25 ++++++++++++------------- 3 files changed, 15 insertions(+), 22 deletions(-) diff --git a/src/Expensify.tsx b/src/Expensify.tsx index 707d89b6a9e87..234f23d410808 100644 --- a/src/Expensify.tsx +++ b/src/Expensify.tsx @@ -57,7 +57,6 @@ function Expensify() { const [accountID] = useOnyx(ONYXKEYS.SESSION, {selector: accountIDSelector}); const [lastRoute] = useOnyx(ONYXKEYS.LAST_ROUTE); const [isCheckingPublicRoom = true] = useOnyx(ONYXKEYS.IS_CHECKING_PUBLIC_ROOM, {initWithStoredValues: false}); - const [updateAvailable] = useOnyx(ONYXKEYS.UPDATE_AVAILABLE, {initWithStoredValues: false}); const [updateRequired] = useOnyx(ONYXKEYS.UPDATE_REQUIRED, {initWithStoredValues: false}); const [lastVisitedPath] = useOnyx(ONYXKEYS.LAST_VISITED_PATH); @@ -214,7 +213,6 @@ function Expensify() { const propsToLog = { isCheckingPublicRoom, updateRequired, - updateAvailable, isAuthenticated, lastVisitedPath, }; @@ -273,7 +271,7 @@ function Expensify() { return ( <> - {shouldInit && } + {shouldInit && } diff --git a/src/GlobalModals.tsx b/src/GlobalModals.tsx index 40719a43d4b38..b5b2b322ba1da 100644 --- a/src/GlobalModals.tsx +++ b/src/GlobalModals.tsx @@ -10,17 +10,13 @@ import {growlRef} from './libs/Growl'; import PopoverReportActionContextMenu from './pages/inbox/report/ContextMenu/PopoverReportActionContextMenu'; import * as ReportActionContextMenu from './pages/inbox/report/ContextMenu/ReportActionContextMenu'; -type GlobalModalsProps = { - updateAvailable?: boolean; -}; - /** * Renders global modals and overlays that are mounted once at the top level. */ -function GlobalModals({updateAvailable}: GlobalModalsProps) { +function GlobalModals() { return ( <> - {!!updateAvailable && } + {/* Those below are only available to the authenticated user. */} diff --git a/src/components/UpdateAppModal.tsx b/src/components/UpdateAppModal.tsx index 092f2f0a4fa57..b0f4e4a488994 100755 --- a/src/components/UpdateAppModal.tsx +++ b/src/components/UpdateAppModal.tsx @@ -1,20 +1,19 @@ import React, {useState} from 'react'; import useLocalize from '@hooks/useLocalize'; +import useOnyx from '@hooks/useOnyx'; +import ONYXKEYS from '@src/ONYXKEYS'; import ConfirmModal from './ConfirmModal'; -type UpdateAppModalProps = { - /** Callback to fire when we want to trigger the update. */ - onSubmit?: () => void; -}; - -function UpdateAppModal({onSubmit}: UpdateAppModalProps) { +function UpdateAppModal() { const [isModalOpen, setIsModalOpen] = useState(true); const {translate} = useLocalize(); - /** - * Execute the onSubmit callback and close the modal. - */ - const submitAndClose = () => { - onSubmit?.(); + const [updateAvailable] = useOnyx(ONYXKEYS.UPDATE_AVAILABLE, {initWithStoredValues: false}); + + if (!updateAvailable) { + return null; + } + + const handleClose = () => { setIsModalOpen(false); }; @@ -22,8 +21,8 @@ function UpdateAppModal({onSubmit}: UpdateAppModalProps) { setIsModalOpen(false)} + onConfirm={handleClose} + onCancel={handleClose} prompt={translate('baseUpdateAppModal.updatePrompt')} confirmText={translate('baseUpdateAppModal.updateApp')} cancelText={translate('common.cancel')}