Skip to content

Fix: On tapping device back button to close troubleshoot box from LHN, navigated out of site #58608

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 18 commits into from
May 8, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions src/Expensify.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import FocusModeNotification from './components/FocusModeNotification';
import GrowlNotification from './components/GrowlNotification';
import AppleAuthWrapper from './components/SignInButtons/AppleAuthWrapper';
import SplashScreenHider from './components/SplashScreenHider';
import TestToolsModal from './components/TestToolsModal';
import UpdateAppModal from './components/UpdateAppModal';
import CONFIG from './CONFIG';
import CONST from './CONST';
Expand Down Expand Up @@ -306,7 +305,6 @@ function Expensify() {
/>
)}
{shouldHideSplash && <SplashScreenHider onHide={onSplashHide} />}
<TestToolsModal />
</DeeplinkWrapper>
);
}
Expand Down
1 change: 1 addition & 0 deletions src/NAVIGATORS.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,5 @@ export default {
SEARCH_FULLSCREEN_NAVIGATOR: 'SearchFullscreenNavigator',
SHARE_MODAL_NAVIGATOR: 'ShareModalNavigator',
PUBLIC_RIGHT_MODAL_NAVIGATOR: 'PublicRightModalNavigator',
TEST_TOOLS_MODAL_NAVIGATOR: 'TestToolsModalNavigator',
} as const;
2 changes: 2 additions & 0 deletions src/ROUTES.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1948,6 +1948,8 @@ const ROUTES = {
},
MIGRATED_USER_WELCOME_MODAL: 'onboarding/migrated-user-welcome',

TEST_TOOLS_MODAL: 'test-tools',

TRANSACTION_RECEIPT: {
route: 'r/:reportID/transaction/:transactionID/receipt/:action?/:iouType?',
getRoute: (reportID: string | undefined, transactionID: string | undefined, readonly = false, isFromReviewDuplicates = false, action?: IOUAction, iouType?: IOUType) => {
Expand Down
4 changes: 4 additions & 0 deletions src/SCREENS.ts
Original file line number Diff line number Diff line change
Expand Up @@ -671,6 +671,10 @@ const SCREENS = {
ROOT: 'TestDrive_Demo_Root',
},

TEST_TOOLS_MODAL: {
ROOT: 'TestToolsModal_Root',
},

I_KNOW_A_TEACHER: 'I_Know_A_Teacher',
INTRO_SCHOOL_PRINCIPAL: 'Intro_School_Principal',
I_AM_A_TEACHER: 'I_Am_A_Teacher',
Expand Down
38 changes: 37 additions & 1 deletion src/components/Search/SearchRouter/SearchRouterContext.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, {useContext, useMemo, useRef, useState} from 'react';
import React, {useContext, useEffect, useMemo, useRef, useState} from 'react';
import type {AnimatedTextInputRef} from '@components/RNTextInput';
import isSearchTopmostFullScreenRoute from '@libs/Navigation/helpers/isSearchTopmostFullScreenRoute';
import {navigationRef} from '@libs/Navigation/Navigation';
Expand All @@ -16,6 +16,10 @@ type SearchRouterContext = {
unregisterSearchPageInput: () => void;
};

type HistoryState = {
isSearchModalOpen?: boolean;
};

const defaultSearchContext: SearchRouterContext = {
isSearchRouterDisplayed: false,
openSearchRouter: () => {},
Expand All @@ -27,17 +31,43 @@ const defaultSearchContext: SearchRouterContext = {

const Context = React.createContext<SearchRouterContext>(defaultSearchContext);

const supportsHistoryAPI = typeof window !== 'undefined' && typeof window.history !== 'undefined';
const canListenPopState = typeof window !== 'undefined' && typeof window.addEventListener === 'function';

function SearchRouterContextProvider({children}: ChildrenProps) {
const [isSearchRouterDisplayed, setIsSearchRouterDisplayed] = useState(false);
const searchRouterDisplayedRef = useRef(false);
const searchPageInputRef = useRef<AnimatedTextInputRef | undefined>(undefined);

useEffect(() => {
if (!canListenPopState) {
return;
}

const handlePopState = (event: PopStateEvent) => {
const state = event.state as HistoryState | null;
if (state?.isSearchModalOpen) {
setIsSearchRouterDisplayed(true);
searchRouterDisplayedRef.current = true;
} else {
setIsSearchRouterDisplayed(false);
searchRouterDisplayedRef.current = false;
}
};

window.addEventListener('popstate', handlePopState);
return () => window.removeEventListener('popstate', handlePopState);
}, []);

const routerContext = useMemo(() => {
const openSearchRouter = () => {
close(
() => {
setIsSearchRouterDisplayed(true);
searchRouterDisplayedRef.current = true;
if (supportsHistoryAPI) {
window.history.pushState({isSearchModalOpen: true} satisfies HistoryState, '');
}
},
false,
true,
Expand All @@ -46,6 +76,12 @@ function SearchRouterContextProvider({children}: ChildrenProps) {
const closeSearchRouter = () => {
setIsSearchRouterDisplayed(false);
searchRouterDisplayedRef.current = false;
if (supportsHistoryAPI) {
const state = window.history.state as HistoryState | null;
if (state?.isSearchModalOpen) {
window.history.back();
}
}
};

// There are callbacks that live outside of React render-loop and interact with SearchRouter
Expand Down
3 changes: 1 addition & 2 deletions src/components/Search/SearchRouter/SearchRouterModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import useResponsiveLayout from '@hooks/useResponsiveLayout';
import useThemeStyles from '@hooks/useThemeStyles';
import useViewportOffsetTop from '@hooks/useViewportOffsetTop';
import useWindowDimensions from '@hooks/useWindowDimensions';
import {isMobileChrome, isMobileIOS} from '@libs/Browser';
import {isMobileIOS} from '@libs/Browser';
import CONST from '@src/CONST';
import SearchRouter from './SearchRouter';
import {useSearchRouterContext} from './SearchRouterContext';
Expand Down Expand Up @@ -34,7 +34,6 @@ function SearchRouterModal() {
fullscreen
propagateSwipe
swipeDirection={shouldUseNarrowLayout ? CONST.SWIPE_DIRECTION.RIGHT : undefined}
shouldHandleNavigationBack={isMobileChrome()}
onClose={closeSearchRouter}
onModalHide={() => setShouldHideInputCaret(isMobileWebIOS)}
onModalShow={() => setShouldHideInputCaret(false)}
Expand Down
84 changes: 0 additions & 84 deletions src/components/TestToolsModal.tsx

This file was deleted.

67 changes: 67 additions & 0 deletions src/components/TestToolsModalPage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import React from 'react';
import {View} from 'react-native';
import useIsAuthenticated from '@hooks/useIsAuthenticated';
import useLocalize from '@hooks/useLocalize';
import useThemeStyles from '@hooks/useThemeStyles';
import useWindowDimensions from '@hooks/useWindowDimensions';
import Navigation from '@navigation/Navigation';
import {shouldShowProfileTool} from '@userActions/TestTool';
import ROUTES from '@src/ROUTES';
import Button from './Button';
import ClientSideLoggingToolMenu from './ClientSideLoggingToolMenu';
import ProfilingToolMenu from './ProfilingToolMenu';
import SafeAreaConsumer from './SafeAreaConsumer';
import ScrollView from './ScrollView';
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 TestToolsModalPage() {
const {windowHeight} = useWindowDimensions();
const styles = useThemeStyles();
const {translate} = useLocalize();
const activeRoute = Navigation.getActiveRoute();
const isAuthenticated = useIsAuthenticated();
const route = getRouteBasedOnAuthStatus(isAuthenticated, activeRoute);

const maxHeight = windowHeight;

return (
<SafeAreaConsumer>
{({safeAreaPaddingBottomStyle}) => (
<View style={[{maxHeight}, styles.h100, styles.pt4, styles.defaultModalContainer, safeAreaPaddingBottomStyle]}>
<ScrollView style={[styles.flex1, styles.flexGrow1, styles.ph5]}>
<Text
style={[styles.textLabelSupporting, styles.mt5, styles.mb3]}
numberOfLines={1}
>
{translate('initialSettingsPage.troubleshoot.releaseOptions')}
</Text>
{shouldShowProfileTool() && <ProfilingToolMenu />}
<ClientSideLoggingToolMenu />
{!!false && (
<TestToolRow title={translate('initialSettingsPage.troubleshoot.debugConsole')}>
<Button
small
text={translate('initialSettingsPage.debugConsole.viewConsole')}
onPress={() => {
Navigation.navigate(route);
}}
/>
</TestToolRow>
)}
<TestToolMenu />
</ScrollView>
</View>
)}
</SafeAreaConsumer>
);
}

TestToolsModalPage.displayName = 'TestToolsModalPage';

export default TestToolsModalPage;
19 changes: 18 additions & 1 deletion src/libs/Navigation/AppNavigator/AuthScreens.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails'
import useOnboardingFlowRouter from '@hooks/useOnboardingFlow';
import useResponsiveLayout from '@hooks/useResponsiveLayout';
import {SidebarOrderedReportIDsContextProvider} from '@hooks/useSidebarOrderedReportIDs';
import useStyleUtils from '@hooks/useStyleUtils';
import useTheme from '@hooks/useTheme';
import {connect} from '@libs/actions/Delegate';
import setFullscreenVisibility from '@libs/actions/setFullscreenVisibility';
Expand All @@ -26,7 +27,7 @@ import Log from '@libs/Log';
import NavBarManager from '@libs/NavBarManager';
import getCurrentUrl from '@libs/Navigation/currentUrl';
import Navigation from '@libs/Navigation/Navigation';
import Animations from '@libs/Navigation/PlatformStackNavigation/navigationOptions/animation';
import Animations, {InternalPlatformAnimations} from '@libs/Navigation/PlatformStackNavigation/navigationOptions/animation';
import Presentation from '@libs/Navigation/PlatformStackNavigation/navigationOptions/presentation';
import type {AuthScreensParamList} from '@libs/Navigation/types';
import NetworkConnection from '@libs/NetworkConnection';
Expand Down Expand Up @@ -69,6 +70,7 @@ import MigratedUserWelcomeModalNavigator from './Navigators/MigratedUserWelcomeM
import OnboardingModalNavigator from './Navigators/OnboardingModalNavigator';
import RightModalNavigator from './Navigators/RightModalNavigator';
import TestDriveModalNavigator from './Navigators/TestDriveModalNavigator';
import TestToolsModalNavigator from './Navigators/TestToolsModalNavigator';
import WelcomeVideoModalNavigator from './Navigators/WelcomeVideoModalNavigator';
import TestDriveDemoNavigator from './TestDriveDemoNavigator';
import useRootNavigatorScreenOptions from './useRootNavigatorScreenOptions';
Expand Down Expand Up @@ -218,6 +220,7 @@ const modalScreenListenersWithCancelSearch = {

function AuthScreens({session, lastOpenedPublicRoomID, initialLastUpdateIDAppliedToClient}: AuthScreensProps) {
const theme = useTheme();
const StyleUtils = useStyleUtils();
const {shouldUseNarrowLayout} = useResponsiveLayout();
const rootNavigatorScreenOptions = useRootNavigatorScreenOptions();
const currentUserPersonalDetails = useCurrentUserPersonalDetails();
Expand Down Expand Up @@ -710,6 +713,20 @@ function AuthScreens({session, lastOpenedPublicRoomID, initialLastUpdateIDApplie
options={rootNavigatorScreenOptions.fullScreen}
component={ConnectionCompletePage}
/>
<RootStack.Screen
name={NAVIGATORS.TEST_TOOLS_MODAL_NAVIGATOR}
options={{
...rootNavigatorScreenOptions.basicModalNavigator,
native: {
contentStyle: {
...StyleUtils.getBackgroundColorWithOpacityStyle(theme.overlay, 0.72),
},
animation: InternalPlatformAnimations.FADE,
},
}}
component={TestToolsModalNavigator}
listeners={modalScreenListeners}
/>
</RootStack.Navigator>
<SearchRouterModal />
</ComposeProviders>
Expand Down
Loading