From 1df6df7256ed9d5add9b6a29961b76f0719fa7c7 Mon Sep 17 00:00:00 2001
From: Github <olimpia.zurek@gmail.com>
Date: Fri, 28 Feb 2025 10:13:46 +0100
Subject: [PATCH 1/3] Make Troubleshoot menu available in Sign In page

---
 src/Expensify.tsx                             |  8 +-
 src/NAVIGATORS.ts                             |  1 +
 src/ROUTES.ts                                 |  4 +
 src/SCREENS.ts                                |  1 +
 src/components/TestToolMenu.tsx               | 97 ++++++++++---------
 src/components/TestToolsModal.tsx             | 10 +-
 src/hooks/useDebugShortcut.tsx                | 26 +++++
 src/hooks/useIsAuthenticated.tsx              | 11 +++
 .../ModalStackNavigators/index.tsx            |  6 ++
 .../Navigators/PublicRightModalNavigator.tsx  | 60 ++++++++++++
 .../Navigation/AppNavigator/PublicScreens.tsx |  8 ++
 src/libs/Navigation/linkingConfig/config.ts   |  8 ++
 src/libs/Navigation/types.ts                  |  8 ++
 src/pages/settings/AboutPage/ConsolePage.tsx  | 20 ++--
 14 files changed, 213 insertions(+), 55 deletions(-)
 create mode 100644 src/hooks/useDebugShortcut.tsx
 create mode 100644 src/hooks/useIsAuthenticated.tsx
 create mode 100644 src/libs/Navigation/AppNavigator/Navigators/PublicRightModalNavigator.tsx

diff --git a/src/Expensify.tsx b/src/Expensify.tsx
index 85e8f6c6af88..0f3138bbfb75 100644
--- a/src/Expensify.tsx
+++ b/src/Expensify.tsx
@@ -12,9 +12,12 @@ import GrowlNotification from './components/GrowlNotification';
 import RequireTwoFactorAuthenticationModal from './components/RequireTwoFactorAuthenticationModal';
 import AppleAuthWrapper from './components/SignInButtons/AppleAuthWrapper';
 import SplashScreenHider from './components/SplashScreenHider';
+import TestToolsModal from './components/TestToolsModal';
 import UpdateAppModal from './components/UpdateAppModal';
 import * as CONFIG from './CONFIG';
 import CONST from './CONST';
+import useDebugShortcut from './hooks/useDebugShortcut';
+import useIsAuthenticated from './hooks/useIsAuthenticated';
 import useLocalize from './hooks/useLocalize';
 import {updateLastRoute} from './libs/actions/App';
 import {disconnect} from './libs/actions/Delegate';
@@ -97,6 +100,8 @@ function Expensify() {
     const [focusModeNotification] = useOnyx(ONYXKEYS.FOCUS_MODE_NOTIFICATION, {initWithStoredValues: false});
     const [lastVisitedPath] = useOnyx(ONYXKEYS.LAST_VISITED_PATH);
 
+    useDebugShortcut();
+
     useEffect(() => {
         if (!account?.needsTwoFactorAuthSetup || account.requiresTwoFactorAuth) {
             return;
@@ -113,7 +118,7 @@ function Expensify() {
         setAttemptedToOpenPublicRoom(true);
     }, [isCheckingPublicRoom]);
 
-    const isAuthenticated = useMemo(() => !!(session?.authToken ?? null), [session]);
+    const isAuthenticated = useIsAuthenticated();
     const autoAuthState = useMemo(() => session?.autoAuthState ?? '', [session]);
 
     const shouldInit = isNavigationReady && hasAttemptedToOpenPublicRoom;
@@ -306,6 +311,7 @@ function Expensify() {
                 />
             )}
             {shouldHideSplash && <SplashScreenHider onHide={onSplashHide} />}
+            <TestToolsModal />
         </DeeplinkWrapper>
     );
 }
diff --git a/src/NAVIGATORS.ts b/src/NAVIGATORS.ts
index de3a66e1f441..0bf4059cfbd2 100644
--- a/src/NAVIGATORS.ts
+++ b/src/NAVIGATORS.ts
@@ -15,4 +15,5 @@ export default {
     SETTINGS_SPLIT_NAVIGATOR: 'SettingsSplitNavigator',
     WORKSPACE_SPLIT_NAVIGATOR: 'WorkspaceSplitNavigator',
     SEARCH_FULLSCREEN_NAVIGATOR: 'SearchFullscreenNavigator',
+    PUBLIC_RIGHT_MODAL_NAVIGATOR: 'PublicRightModalNavigator',
 } as const;
diff --git a/src/ROUTES.ts b/src/ROUTES.ts
index 41fd4b830f12..0c3ed4d0911f 100644
--- a/src/ROUTES.ts
+++ b/src/ROUTES.ts
@@ -133,6 +133,10 @@ const ROUTES = {
         },
     },
     WORKSPACE_SWITCHER: 'workspace-switcher',
+    PUBLIC_CONSOLE_DEBUG: {
+        route: 'troubleshoot/console',
+        getRoute: (backTo?: string) => getUrlWithBackToParam(`troubleshoot/console`, backTo),
+    },
     SETTINGS: 'settings',
     SETTINGS_PROFILE: 'settings/profile',
     SETTINGS_CHANGE_CURRENCY: 'settings/add-payment-card/change-currency',
diff --git a/src/SCREENS.ts b/src/SCREENS.ts
index 7e09c0277fe4..f28d1fc990e1 100644
--- a/src/SCREENS.ts
+++ b/src/SCREENS.ts
@@ -200,6 +200,7 @@ const SCREENS = {
         MISSING_PERSONAL_DETAILS: 'MissingPersonalDetails',
         DEBUG: 'Debug',
     },
+    PUBLIC_CONSOLE_DEBUG: 'Console_Debug',
     ONBOARDING_MODAL: {
         ONBOARDING: 'Onboarding',
     },
diff --git a/src/components/TestToolMenu.tsx b/src/components/TestToolMenu.tsx
index 83aba3d4b61e..8d8c3bc4dc89 100644
--- a/src/components/TestToolMenu.tsx
+++ b/src/components/TestToolMenu.tsx
@@ -1,11 +1,12 @@
 import React from 'react';
 import {useOnyx} from 'react-native-onyx';
+import useIsAuthenticated from '@hooks/useIsAuthenticated';
 import useLocalize from '@hooks/useLocalize';
 import useThemeStyles from '@hooks/useThemeStyles';
-import * as ApiUtils from '@libs/ApiUtils';
-import * as Network from '@userActions/Network';
-import * as Session from '@userActions/Session';
-import * as User from '@userActions/User';
+import {isUsingStagingApi} from '@libs/ApiUtils';
+import {setShouldFailAllRequests, setShouldForceOffline, setShouldSimulatePoorConnection} from '@userActions/Network';
+import {expireSessionWithDelay, invalidateAuthToken, invalidateCredentials} from '@userActions/Session';
+import {setIsDebugModeEnabled, setShouldUseStagingServer} from '@userActions/User';
 import CONFIG from '@src/CONFIG';
 import ONYXKEYS from '@src/ONYXKEYS';
 import type {User as UserOnyx} from '@src/types/onyx';
@@ -28,11 +29,14 @@ function TestToolMenu() {
     const [network] = useOnyx(ONYXKEYS.NETWORK);
     const [user = USER_DEFAULT] = useOnyx(ONYXKEYS.USER);
     const [isUsingImportedState] = useOnyx(ONYXKEYS.IS_USING_IMPORTED_STATE);
-    const shouldUseStagingServer = user?.shouldUseStagingServer ?? ApiUtils.isUsingStagingApi();
+    const shouldUseStagingServer = user?.shouldUseStagingServer ?? isUsingStagingApi();
     const isDebugModeEnabled = !!user?.isDebugModeEnabled;
     const styles = useThemeStyles();
     const {translate} = useLocalize();
 
+    // Check if the user is authenticated to show options that require authentication
+    const isAuthenticated = useIsAuthenticated();
+
     return (
         <>
             <Text
@@ -41,14 +45,45 @@ function TestToolMenu() {
             >
                 {translate('initialSettingsPage.troubleshoot.testingPreferences')}
             </Text>
-            {/* When toggled the app will be put into debug mode. */}
-            <TestToolRow title={translate('initialSettingsPage.troubleshoot.debugMode')}>
-                <Switch
-                    accessibilityLabel={translate('initialSettingsPage.troubleshoot.debugMode')}
-                    isOn={isDebugModeEnabled}
-                    onToggle={() => User.setIsDebugModeEnabled(!isDebugModeEnabled)}
-                />
-            </TestToolRow>
+            {isAuthenticated && (
+                <>
+                    {/* When toggled the app will be put into debug mode. */}
+                    <TestToolRow title={translate('initialSettingsPage.troubleshoot.debugMode')}>
+                        <Switch
+                            accessibilityLabel={translate('initialSettingsPage.troubleshoot.debugMode')}
+                            isOn={isDebugModeEnabled}
+                            onToggle={() => setIsDebugModeEnabled(!isDebugModeEnabled)}
+                        />
+                    </TestToolRow>
+
+                    {/* Instantly invalidates a user's local authToken. Useful for testing flows related to reauthentication. */}
+                    <TestToolRow title={translate('initialSettingsPage.troubleshoot.authenticationStatus')}>
+                        <Button
+                            small
+                            text={translate('initialSettingsPage.troubleshoot.invalidate')}
+                            onPress={() => invalidateAuthToken()}
+                        />
+                    </TestToolRow>
+
+                    {/* Invalidate stored user auto-generated credentials. Useful for manually testing sign out logic. */}
+                    <TestToolRow title={translate('initialSettingsPage.troubleshoot.deviceCredentials')}>
+                        <Button
+                            small
+                            text={translate('initialSettingsPage.troubleshoot.destroy')}
+                            onPress={() => invalidateCredentials()}
+                        />
+                    </TestToolRow>
+
+                    {/* Sends an expired session to the FE and invalidates the session by the same time in the BE. Action is delayed for 15s */}
+                    <TestToolRow title={translate('initialSettingsPage.troubleshoot.authenticationStatus')}>
+                        <Button
+                            small
+                            text={translate('initialSettingsPage.troubleshoot.invalidateWithDelay')}
+                            onPress={() => expireSessionWithDelay()}
+                        />
+                    </TestToolRow>
+                </>
+            )}
 
             {/* Option to switch between staging and default api endpoints.
         This enables QA, internal testers and external devs to take advantage of sandbox environments for 3rd party services like Plaid and Onfido.
@@ -58,7 +93,7 @@ function TestToolMenu() {
                     <Switch
                         accessibilityLabel="Use Staging Server"
                         isOn={shouldUseStagingServer}
-                        onToggle={() => User.setShouldUseStagingServer(!shouldUseStagingServer)}
+                        onToggle={() => setShouldUseStagingServer(!shouldUseStagingServer)}
                     />
                 </TestToolRow>
             )}
@@ -68,7 +103,7 @@ function TestToolMenu() {
                 <Switch
                     accessibilityLabel="Force offline"
                     isOn={!!network?.shouldForceOffline}
-                    onToggle={() => Network.setShouldForceOffline(!network?.shouldForceOffline)}
+                    onToggle={() => setShouldForceOffline(!network?.shouldForceOffline)}
                     disabled={!!isUsingImportedState || !!network?.shouldSimulatePoorConnection || network?.shouldFailAllRequests}
                 />
             </TestToolRow>
@@ -78,7 +113,7 @@ function TestToolMenu() {
                 <Switch
                     accessibilityLabel="Simulate poor internet connection"
                     isOn={!!network?.shouldSimulatePoorConnection}
-                    onToggle={() => Network.setShouldSimulatePoorConnection(!network?.shouldSimulatePoorConnection, network?.poorConnectionTimeoutID)}
+                    onToggle={() => setShouldSimulatePoorConnection(!network?.shouldSimulatePoorConnection, network?.poorConnectionTimeoutID)}
                     disabled={!!isUsingImportedState || !!network?.shouldFailAllRequests || network?.shouldForceOffline}
                 />
             </TestToolRow>
@@ -88,38 +123,10 @@ function TestToolMenu() {
                 <Switch
                     accessibilityLabel="Simulate failing network requests"
                     isOn={!!network?.shouldFailAllRequests}
-                    onToggle={() => Network.setShouldFailAllRequests(!network?.shouldFailAllRequests)}
+                    onToggle={() => setShouldFailAllRequests(!network?.shouldFailAllRequests)}
                     disabled={!!network?.shouldForceOffline || network?.shouldSimulatePoorConnection}
                 />
             </TestToolRow>
-
-            {/* Instantly invalidates a user's local authToken. Useful for testing flows related to reauthentication. */}
-            <TestToolRow title={translate('initialSettingsPage.troubleshoot.authenticationStatus')}>
-                <Button
-                    small
-                    text={translate('initialSettingsPage.troubleshoot.invalidate')}
-                    onPress={() => Session.invalidateAuthToken()}
-                />
-            </TestToolRow>
-
-            {/* Invalidate stored user auto-generated credentials. Useful for manually testing sign out logic. */}
-            <TestToolRow title={translate('initialSettingsPage.troubleshoot.deviceCredentials')}>
-                <Button
-                    small
-                    text={translate('initialSettingsPage.troubleshoot.destroy')}
-                    onPress={() => Session.invalidateCredentials()}
-                />
-            </TestToolRow>
-
-            {/* Sends an expired session to the FE and invalidates the session by the same time in the BE. Action is delayed for 15s */}
-            <TestToolRow title={translate('initialSettingsPage.troubleshoot.authenticationStatus')}>
-                <Button
-                    small
-                    text={translate('initialSettingsPage.troubleshoot.invalidateWithDelay')}
-                    onPress={() => Session.expireSessionWithDelay()}
-                />
-            </TestToolRow>
-
             <TestCrash />
         </>
     );
diff --git a/src/components/TestToolsModal.tsx b/src/components/TestToolsModal.tsx
index 7c2e161b2d11..a16552f9ba9a 100644
--- a/src/components/TestToolsModal.tsx
+++ b/src/components/TestToolsModal.tsx
@@ -1,6 +1,7 @@
 import React from 'react';
 import {View} from 'react-native';
 import {useOnyx} from 'react-native-onyx';
+import useIsAuthenticated from '@hooks/useIsAuthenticated';
 import useLocalize from '@hooks/useLocalize';
 import useStyleUtils from '@hooks/useStyleUtils';
 import useThemeStyles from '@hooks/useThemeStyles';
@@ -18,6 +19,10 @@ import TestToolMenu from './TestToolMenu';
 import TestToolRow from './TestToolRow';
 import Text from './Text';
 
+function getRouteBasedOnAuthStatus(isAuthenticated: boolean, activeRoute: string) {
+    return isAuthenticated ? ROUTES.SETTINGS_CONSOLE.getRoute(activeRoute) : ROUTES.PUBLIC_CONSOLE_DEBUG.getRoute(activeRoute);
+}
+
 function TestToolsModal() {
     const [isTestToolsModalOpen = false] = useOnyx(ONYXKEYS.IS_TEST_TOOLS_MODAL_OPEN);
     const [shouldStoreLogs = false] = useOnyx(ONYXKEYS.SHOULD_STORE_LOGS);
@@ -25,6 +30,9 @@ function TestToolsModal() {
     const StyleUtils = useStyleUtils();
     const styles = useThemeStyles();
     const {translate} = useLocalize();
+    const activeRoute = Navigation.getActiveRoute();
+    const isAuthenticated = useIsAuthenticated();
+    const route = getRouteBasedOnAuthStatus(isAuthenticated, activeRoute);
 
     return (
         <Modal
@@ -48,7 +56,7 @@ function TestToolsModal() {
                             text={translate('initialSettingsPage.debugConsole.viewConsole')}
                             onPress={() => {
                                 toggleTestToolsModal();
-                                Navigation.navigate(ROUTES.SETTINGS_CONSOLE.getRoute(Navigation.getActiveRoute()));
+                                Navigation.navigate(route);
                             }}
                         />
                     </TestToolRow>
diff --git a/src/hooks/useDebugShortcut.tsx b/src/hooks/useDebugShortcut.tsx
new file mode 100644
index 000000000000..38b2abccce0c
--- /dev/null
+++ b/src/hooks/useDebugShortcut.tsx
@@ -0,0 +1,26 @@
+import {useEffect} from 'react';
+import KeyboardShortcut from '@libs/KeyboardShortcut';
+import toggleTestToolsModal from '@userActions/TestTool';
+import CONST from '@src/CONST';
+
+function useDebugShortcut() {
+    useEffect(() => {
+        const debugShortcutConfig = CONST.KEYBOARD_SHORTCUTS.DEBUG;
+        const unsubscribeDebugShortcut = KeyboardShortcut.subscribe(
+            debugShortcutConfig.shortcutKey,
+            () => toggleTestToolsModal(),
+            debugShortcutConfig.descriptionKey,
+            debugShortcutConfig.modifiers,
+            true,
+        );
+
+        return () => {
+            unsubscribeDebugShortcut();
+        };
+
+        // Rule disabled because this effect is only for component did mount & will component unmount lifecycle event
+        // eslint-disable-next-line react-compiler/react-compiler, react-hooks/exhaustive-deps
+    }, []);
+}
+
+export default useDebugShortcut;
diff --git a/src/hooks/useIsAuthenticated.tsx b/src/hooks/useIsAuthenticated.tsx
new file mode 100644
index 000000000000..cfca734f9b86
--- /dev/null
+++ b/src/hooks/useIsAuthenticated.tsx
@@ -0,0 +1,11 @@
+import {useMemo} from 'react';
+import {useOnyx} from 'react-native-onyx';
+import ONYXKEYS from '@src/ONYXKEYS';
+
+function useIsAuthenticated() {
+    const [session] = useOnyx(ONYXKEYS.SESSION);
+    const isAuthenticated = useMemo(() => !!(session?.authToken ?? null), [session]);
+    return isAuthenticated;
+}
+
+export default useIsAuthenticated;
diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx
index 91939c86f07f..89e16db6ac23 100644
--- a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx
+++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx
@@ -3,6 +3,7 @@ import React from 'react';
 import createPlatformStackNavigator from '@libs/Navigation/PlatformStackNavigation/createPlatformStackNavigator';
 import type {
     AddPersonalBankAccountNavigatorParamList,
+    ConsoleNavigatorParamList,
     DebugParamList,
     EditRequestNavigatorParamList,
     EnablePaymentsNavigatorParamList,
@@ -226,6 +227,10 @@ const NewTeachersUniteNavigator = createModalStackNavigator<TeachersUniteNavigat
     [SCREENS.I_AM_A_TEACHER]: () => require<ReactComponentModule>('../../../../pages/TeachersUnite/ImTeacherPage').default,
 });
 
+const ConsoleModalStackNavigator = createModalStackNavigator<ConsoleNavigatorParamList>({
+    [SCREENS.PUBLIC_CONSOLE_DEBUG]: () => require<ReactComponentModule>('../../../../pages/settings/AboutPage/ConsolePage').default,
+});
+
 const SettingsModalStackNavigator = createModalStackNavigator<SettingsNavigatorParamList>({
     [SCREENS.SETTINGS.SHARE_CODE]: () => require<ReactComponentModule>('../../../../pages/ShareCodePage').default,
     [SCREENS.SETTINGS.PROFILE.PRONOUNS]: () => require<ReactComponentModule>('../../../../pages/settings/Profile/PronounsPage').default,
@@ -761,4 +766,5 @@ export {
     MissingPersonalDetailsModalStackNavigator,
     DebugModalStackNavigator,
     WorkspaceConfirmationModalStackNavigator,
+    ConsoleModalStackNavigator,
 };
diff --git a/src/libs/Navigation/AppNavigator/Navigators/PublicRightModalNavigator.tsx b/src/libs/Navigation/AppNavigator/Navigators/PublicRightModalNavigator.tsx
new file mode 100644
index 000000000000..cc8691d61484
--- /dev/null
+++ b/src/libs/Navigation/AppNavigator/Navigators/PublicRightModalNavigator.tsx
@@ -0,0 +1,60 @@
+import type {StackCardInterpolationProps} from '@react-navigation/stack';
+import React, {useMemo} from 'react';
+import {View} from 'react-native';
+import NoDropZone from '@components/DragAndDrop/NoDropZone';
+import useResponsiveLayout from '@hooks/useResponsiveLayout';
+import useThemeStyles from '@hooks/useThemeStyles';
+import {isSafari} from '@libs/Browser';
+import * as ModalStackNavigators from '@libs/Navigation/AppNavigator/ModalStackNavigators';
+import useModalCardStyleInterpolator from '@libs/Navigation/AppNavigator/useModalCardStyleInterpolator';
+import useSideModalStackScreenOptions from '@libs/Navigation/AppNavigator/useSideModalStackScreenOptions';
+import createPlatformStackNavigator from '@libs/Navigation/PlatformStackNavigation/createPlatformStackNavigator';
+import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types';
+import type {ConsoleNavigatorParamList, PublicScreensParamList} from '@libs/Navigation/types';
+import NAVIGATORS from '@src/NAVIGATORS';
+import SCREENS from '@src/SCREENS';
+import Overlay from './Overlay';
+
+type PublicRightModalNavigatorComponentProps = PlatformStackScreenProps<PublicScreensParamList, typeof NAVIGATORS.PUBLIC_RIGHT_MODAL_NAVIGATOR>;
+
+const Stack = createPlatformStackNavigator<ConsoleNavigatorParamList>();
+
+function PublicRightModalNavigatorComponent({navigation}: PublicRightModalNavigatorComponentProps) {
+    const styles = useThemeStyles();
+    const {shouldUseNarrowLayout} = useResponsiveLayout();
+    const modalNavigatorOptions = useSideModalStackScreenOptions();
+    const customInterpolator = useModalCardStyleInterpolator();
+
+    const screenOptions = useMemo(() => {
+        // The .forHorizontalIOS interpolator from `@react-navigation` is misbehaving on Safari, so we override it with Expensify custom interpolator
+        if (isSafari()) {
+            return {
+                ...modalNavigatorOptions,
+                web: {
+                    ...modalNavigatorOptions.web,
+                    cardStyleInterpolator: (props: StackCardInterpolationProps) => customInterpolator({props}),
+                },
+            };
+        }
+
+        return modalNavigatorOptions;
+    }, [customInterpolator, modalNavigatorOptions]);
+    return (
+        <NoDropZone>
+            {!shouldUseNarrowLayout && <Overlay onPress={navigation.goBack} />}
+            <View style={styles.RHPNavigatorContainer(shouldUseNarrowLayout)}>
+                <Stack.Navigator
+                    screenOptions={screenOptions}
+                    id={NAVIGATORS.PUBLIC_RIGHT_MODAL_NAVIGATOR}
+                >
+                    <Stack.Screen
+                        name={SCREENS.PUBLIC_CONSOLE_DEBUG}
+                        component={ModalStackNavigators.ConsoleModalStackNavigator}
+                    />
+                </Stack.Navigator>
+            </View>
+        </NoDropZone>
+    );
+}
+
+export default PublicRightModalNavigatorComponent;
diff --git a/src/libs/Navigation/AppNavigator/PublicScreens.tsx b/src/libs/Navigation/AppNavigator/PublicScreens.tsx
index 77e379e80293..1fc3a30e6c76 100644
--- a/src/libs/Navigation/AppNavigator/PublicScreens.tsx
+++ b/src/libs/Navigation/AppNavigator/PublicScreens.tsx
@@ -14,10 +14,13 @@ import ValidateLoginPage from '@pages/ValidateLoginPage';
 import NAVIGATORS from '@src/NAVIGATORS';
 import SCREENS from '@src/SCREENS';
 import defaultScreenOptions from './defaultScreenOptions';
+import PublicRightModalNavigator from './Navigators/PublicRightModalNavigator';
+import useRootNavigatorScreenOptions from './useRootNavigatorScreenOptions';
 
 const RootStack = createPlatformStackNavigator<PublicScreensParamList>();
 
 function PublicScreens() {
+    const rootNavigatorScreenOptions = useRootNavigatorScreenOptions();
     return (
         <RootStack.Navigator screenOptions={defaultScreenOptions}>
             {/* The structure for the HOME route has to be the same in public and auth screens. That's why the name for SignInPage is REPORTS_SPLIT_NAVIGATOR. */}
@@ -59,6 +62,11 @@ function PublicScreens() {
                 name={SCREENS.SAML_SIGN_IN}
                 component={SAMLSignInPage}
             />
+            <RootStack.Screen
+                name={NAVIGATORS.PUBLIC_RIGHT_MODAL_NAVIGATOR}
+                component={PublicRightModalNavigator}
+                options={rootNavigatorScreenOptions.rightModalNavigator}
+            />
         </RootStack.Navigator>
     );
 }
diff --git a/src/libs/Navigation/linkingConfig/config.ts b/src/libs/Navigation/linkingConfig/config.ts
index 848c4ed9cdcd..2da40da6add7 100644
--- a/src/libs/Navigation/linkingConfig/config.ts
+++ b/src/libs/Navigation/linkingConfig/config.ts
@@ -38,6 +38,14 @@ const config: LinkingOptions<RootNavigatorParamList>['config'] = {
                 },
             },
         },
+        [NAVIGATORS.PUBLIC_RIGHT_MODAL_NAVIGATOR]: {
+            screens: {
+                [SCREENS.PUBLIC_CONSOLE_DEBUG]: {
+                    path: ROUTES.PUBLIC_CONSOLE_DEBUG.route,
+                    exact: true,
+                },
+            },
+        },
         [NAVIGATORS.FEATURE_TRANING_MODAL_NAVIGATOR]: {
             screens: {
                 [SCREENS.FEATURE_TRAINING_ROOT]: {
diff --git a/src/libs/Navigation/types.ts b/src/libs/Navigation/types.ts
index 45d9119f0a7e..e406704a3c11 100644
--- a/src/libs/Navigation/types.ts
+++ b/src/libs/Navigation/types.ts
@@ -69,6 +69,12 @@ type BackToParams = {
     backTo?: Routes;
 };
 
+type ConsoleNavigatorParamList = {
+    [SCREENS.PUBLIC_CONSOLE_DEBUG]: {
+        backTo: Routes;
+    };
+};
+
 type SettingsNavigatorParamList = {
     [SCREENS.SETTINGS.SHARE_CODE]: undefined;
     [SCREENS.SETTINGS.PROFILE.PRONOUNS]: undefined;
@@ -1777,6 +1783,7 @@ type PublicScreensParamList = SharedScreensParamList & {
     [SCREENS.SAML_SIGN_IN]: undefined;
     [SCREENS.CONNECTION_COMPLETE]: undefined;
     [SCREENS.BANK_CONNECTION_COMPLETE]: undefined;
+    [NAVIGATORS.PUBLIC_RIGHT_MODAL_NAVIGATOR]: NavigatorScreenParams<ConsoleNavigatorParamList>;
 };
 
 type AuthScreensParamList = SharedScreensParamList & {
@@ -1994,4 +2001,5 @@ export type {
     MigratedUserModalNavigatorParamList,
     WorkspaceConfirmationNavigatorParamList,
     TwoFactorAuthNavigatorParamList,
+    ConsoleNavigatorParamList,
 };
diff --git a/src/pages/settings/AboutPage/ConsolePage.tsx b/src/pages/settings/AboutPage/ConsolePage.tsx
index 75792df40a23..bd4f317a2d20 100644
--- a/src/pages/settings/AboutPage/ConsolePage.tsx
+++ b/src/pages/settings/AboutPage/ConsolePage.tsx
@@ -14,6 +14,7 @@ import type {PopoverMenuItem} from '@components/PopoverMenu';
 import ScreenWrapper from '@components/ScreenWrapper';
 import Text from '@components/Text';
 import TextInput from '@components/TextInput';
+import useIsAuthenticated from '@hooks/useIsAuthenticated';
 import useKeyboardShortcut from '@hooks/useKeyboardShortcut';
 import useLocalize from '@hooks/useLocalize';
 import useTheme from '@hooks/useTheme';
@@ -51,6 +52,7 @@ function ConsolePage() {
     const theme = useTheme();
     const {windowWidth} = useWindowDimensions();
     const route = useRoute<PlatformStackRouteProp<SettingsNavigatorParamList, typeof SCREENS.SETTINGS.CONSOLE>>();
+    const isAuthenticated = useIsAuthenticated();
 
     const menuItems: PopoverMenuItem[] = useMemo(
         () => [
@@ -181,14 +183,16 @@ function ConsolePage() {
                     icon={Expensicons.Download}
                     style={[styles.flex1, styles.mr1]}
                 />
-                <Button
-                    text={translate('initialSettingsPage.debugConsole.shareLog')}
-                    onPress={shareLogs}
-                    large
-                    icon={!isGeneratingLogsFile ? Expensicons.UploadAlt : undefined}
-                    style={[styles.flex1, styles.ml1]}
-                    isLoading={isGeneratingLogsFile}
-                />
+                {isAuthenticated && (
+                    <Button
+                        text={translate('initialSettingsPage.debugConsole.shareLog')}
+                        onPress={shareLogs}
+                        large
+                        icon={!isGeneratingLogsFile ? Expensicons.UploadAlt : undefined}
+                        style={[styles.flex1, styles.ml1]}
+                        isLoading={isGeneratingLogsFile}
+                    />
+                )}
             </View>
             <View style={[styles.mh5]}>
                 <TextInput

From d19fcd7be71b0a1847f5aecb0dc66ff95e69cd19 Mon Sep 17 00:00:00 2001
From: Github <olimpia.zurek@gmail.com>
Date: Tue, 4 Mar 2025 10:25:56 +0100
Subject: [PATCH 2/3] move screenOptions to hook

---
 .../Navigators/PublicRightModalNavigator.tsx  | 23 +++-------------
 .../Navigators/RightModalNavigator.tsx        | 24 +++--------------
 .../AppNavigator/useCustomScreenOptions.ts    | 26 +++++++++++++++++++
 3 files changed, 32 insertions(+), 41 deletions(-)
 create mode 100644 src/libs/Navigation/AppNavigator/useCustomScreenOptions.ts

diff --git a/src/libs/Navigation/AppNavigator/Navigators/PublicRightModalNavigator.tsx b/src/libs/Navigation/AppNavigator/Navigators/PublicRightModalNavigator.tsx
index cc8691d61484..dccf2e10fc75 100644
--- a/src/libs/Navigation/AppNavigator/Navigators/PublicRightModalNavigator.tsx
+++ b/src/libs/Navigation/AppNavigator/Navigators/PublicRightModalNavigator.tsx
@@ -1,13 +1,10 @@
-import type {StackCardInterpolationProps} from '@react-navigation/stack';
-import React, {useMemo} from 'react';
+import React from 'react';
 import {View} from 'react-native';
 import NoDropZone from '@components/DragAndDrop/NoDropZone';
 import useResponsiveLayout from '@hooks/useResponsiveLayout';
 import useThemeStyles from '@hooks/useThemeStyles';
-import {isSafari} from '@libs/Browser';
 import * as ModalStackNavigators from '@libs/Navigation/AppNavigator/ModalStackNavigators';
-import useModalCardStyleInterpolator from '@libs/Navigation/AppNavigator/useModalCardStyleInterpolator';
-import useSideModalStackScreenOptions from '@libs/Navigation/AppNavigator/useSideModalStackScreenOptions';
+import useCustomScreenOptions from '@libs/Navigation/AppNavigator/useCustomScreenOptions';
 import createPlatformStackNavigator from '@libs/Navigation/PlatformStackNavigation/createPlatformStackNavigator';
 import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types';
 import type {ConsoleNavigatorParamList, PublicScreensParamList} from '@libs/Navigation/types';
@@ -22,23 +19,9 @@ const Stack = createPlatformStackNavigator<ConsoleNavigatorParamList>();
 function PublicRightModalNavigatorComponent({navigation}: PublicRightModalNavigatorComponentProps) {
     const styles = useThemeStyles();
     const {shouldUseNarrowLayout} = useResponsiveLayout();
-    const modalNavigatorOptions = useSideModalStackScreenOptions();
-    const customInterpolator = useModalCardStyleInterpolator();
 
-    const screenOptions = useMemo(() => {
-        // The .forHorizontalIOS interpolator from `@react-navigation` is misbehaving on Safari, so we override it with Expensify custom interpolator
-        if (isSafari()) {
-            return {
-                ...modalNavigatorOptions,
-                web: {
-                    ...modalNavigatorOptions.web,
-                    cardStyleInterpolator: (props: StackCardInterpolationProps) => customInterpolator({props}),
-                },
-            };
-        }
+    const screenOptions = useCustomScreenOptions();
 
-        return modalNavigatorOptions;
-    }, [customInterpolator, modalNavigatorOptions]);
     return (
         <NoDropZone>
             {!shouldUseNarrowLayout && <Overlay onPress={navigation.goBack} />}
diff --git a/src/libs/Navigation/AppNavigator/Navigators/RightModalNavigator.tsx b/src/libs/Navigation/AppNavigator/Navigators/RightModalNavigator.tsx
index b1d923c69b29..37866a2e0273 100644
--- a/src/libs/Navigation/AppNavigator/Navigators/RightModalNavigator.tsx
+++ b/src/libs/Navigation/AppNavigator/Navigators/RightModalNavigator.tsx
@@ -1,16 +1,13 @@
-import type {StackCardInterpolationProps} from '@react-navigation/stack';
-import React, {useMemo, useRef} from 'react';
+import React, {useRef} from 'react';
 import {InteractionManager, View} from 'react-native';
 import NoDropZone from '@components/DragAndDrop/NoDropZone';
 import useResponsiveLayout from '@hooks/useResponsiveLayout';
 import useThemeStyles from '@hooks/useThemeStyles';
 import {abandonReviewDuplicateTransactions} from '@libs/actions/Transaction';
 import {clearTwoFactorAuthData} from '@libs/actions/TwoFactorAuthActions';
-import {isSafari} from '@libs/Browser';
 import hideKeyboardOnSwipe from '@libs/Navigation/AppNavigator/hideKeyboardOnSwipe';
 import * as ModalStackNavigators from '@libs/Navigation/AppNavigator/ModalStackNavigators';
-import useModalCardStyleInterpolator from '@libs/Navigation/AppNavigator/useModalCardStyleInterpolator';
-import useSideModalStackScreenOptions from '@libs/Navigation/AppNavigator/useSideModalStackScreenOptions';
+import useCustomScreenOptions from '@libs/Navigation/AppNavigator/useCustomScreenOptions';
 import createPlatformStackNavigator from '@libs/Navigation/PlatformStackNavigation/createPlatformStackNavigator';
 import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types';
 import type {AuthScreensParamList, RightModalNavigatorParamList} from '@navigation/types';
@@ -27,23 +24,8 @@ function RightModalNavigator({navigation, route}: RightModalNavigatorProps) {
     const styles = useThemeStyles();
     const {shouldUseNarrowLayout} = useResponsiveLayout();
     const isExecutingRef = useRef<boolean>(false);
-    const customInterpolator = useModalCardStyleInterpolator();
-    const modalNavigatorOptions = useSideModalStackScreenOptions();
 
-    const screenOptions = useMemo(() => {
-        // The .forHorizontalIOS interpolator from `@react-navigation` is misbehaving on Safari, so we override it with Expensify custom interpolator
-        if (isSafari()) {
-            return {
-                ...modalNavigatorOptions,
-                web: {
-                    ...modalNavigatorOptions.web,
-                    cardStyleInterpolator: (props: StackCardInterpolationProps) => customInterpolator({props}),
-                },
-            };
-        }
-
-        return modalNavigatorOptions;
-    }, [customInterpolator, modalNavigatorOptions]);
+    const screenOptions = useCustomScreenOptions();
 
     return (
         <NoDropZone>
diff --git a/src/libs/Navigation/AppNavigator/useCustomScreenOptions.ts b/src/libs/Navigation/AppNavigator/useCustomScreenOptions.ts
new file mode 100644
index 000000000000..af8749a21138
--- /dev/null
+++ b/src/libs/Navigation/AppNavigator/useCustomScreenOptions.ts
@@ -0,0 +1,26 @@
+import type {StackCardInterpolationProps} from '@react-navigation/stack';
+import {useMemo} from 'react';
+import {isSafari} from '@libs/Browser';
+import useModalCardStyleInterpolator from './useModalCardStyleInterpolator';
+import useSideModalStackScreenOptions from './useSideModalStackScreenOptions';
+
+const useCustomScreenOptions = () => {
+    const modalNavigatorOptions = useSideModalStackScreenOptions();
+    const customInterpolator = useModalCardStyleInterpolator();
+
+    return useMemo(() => {
+        if (isSafari()) {
+            return {
+                ...modalNavigatorOptions,
+                web: {
+                    ...modalNavigatorOptions.web,
+                    cardStyleInterpolator: (props: StackCardInterpolationProps) => customInterpolator({props}),
+                },
+            };
+        }
+
+        return modalNavigatorOptions;
+    }, [customInterpolator, modalNavigatorOptions]);
+};
+
+export default useCustomScreenOptions;

From 0c66ea907ab01274460b8e736474dd61cc25f926 Mon Sep 17 00:00:00 2001
From: Github <olimpia.zurek@gmail.com>
Date: Tue, 4 Mar 2025 11:03:28 +0100
Subject: [PATCH 3/3] revert missed comment

---
 src/libs/Navigation/AppNavigator/useCustomScreenOptions.ts | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/libs/Navigation/AppNavigator/useCustomScreenOptions.ts b/src/libs/Navigation/AppNavigator/useCustomScreenOptions.ts
index af8749a21138..b7c0761db4be 100644
--- a/src/libs/Navigation/AppNavigator/useCustomScreenOptions.ts
+++ b/src/libs/Navigation/AppNavigator/useCustomScreenOptions.ts
@@ -9,6 +9,7 @@ const useCustomScreenOptions = () => {
     const customInterpolator = useModalCardStyleInterpolator();
 
     return useMemo(() => {
+        // The .forHorizontalIOS interpolator from `@react-navigation` is misbehaving on Safari, so we override it with Expensify custom interpolator
         if (isSafari()) {
             return {
                 ...modalNavigatorOptions,
