diff --git a/src/Expensify.tsx b/src/Expensify.tsx
index 0afde4a09222b..234f23d410808 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 FullstoryInitHandler from './FullstoryInitHandler';
+import GlobalModals from './GlobalModals';
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/GlobalModals.tsx b/src/GlobalModals.tsx
new file mode 100644
index 0000000000000..b5b2b322ba1da
--- /dev/null
+++ b/src/GlobalModals.tsx
@@ -0,0 +1,35 @@
+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';
+
+/**
+ * Renders global modals and overlays that are mounted once at the top level.
+ */
+function GlobalModals() {
+ return (
+ <>
+
+ {/* 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/components/UpdateAppModal/BaseUpdateAppModal.tsx b/src/components/UpdateAppModal.tsx
similarity index 53%
rename from src/components/UpdateAppModal/BaseUpdateAppModal.tsx
rename to src/components/UpdateAppModal.tsx
index 2f01f4ff72e09..b0f4e4a488994 100755
--- a/src/components/UpdateAppModal/BaseUpdateAppModal.tsx
+++ b/src/components/UpdateAppModal.tsx
@@ -1,17 +1,19 @@
import React, {useState} from 'react';
-import ConfirmModal from '@components/ConfirmModal';
import useLocalize from '@hooks/useLocalize';
-import type UpdateAppModalProps from './types';
+import useOnyx from '@hooks/useOnyx';
+import ONYXKEYS from '@src/ONYXKEYS';
+import ConfirmModal from './ConfirmModal';
-function BaseUpdateAppModal({onSubmit}: UpdateAppModalProps) {
+function UpdateAppModal() {
const [isModalOpen, setIsModalOpen] = useState(true);
const {translate} = useLocalize();
+ const [updateAvailable] = useOnyx(ONYXKEYS.UPDATE_AVAILABLE, {initWithStoredValues: false});
- /**
- * Execute the onSubmit callback and close the modal.
- */
- const submitAndClose = () => {
- onSubmit?.();
+ if (!updateAvailable) {
+ return null;
+ }
+
+ const handleClose = () => {
setIsModalOpen(false);
};
@@ -19,8 +21,8 @@ function BaseUpdateAppModal({onSubmit}: UpdateAppModalProps) {
setIsModalOpen(false)}
+ onConfirm={handleClose}
+ onCancel={handleClose}
prompt={translate('baseUpdateAppModal.updatePrompt')}
confirmText={translate('baseUpdateAppModal.updateApp')}
cancelText={translate('common.cancel')}
@@ -28,6 +30,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;