Skip to content
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

fix: back button returns to expense report after submitting track expense #53065

Open
wants to merge 11 commits into
base: main
Choose a base branch
from
24 changes: 23 additions & 1 deletion src/libs/Navigation/Navigation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import NAVIGATORS from '@src/NAVIGATORS';
import ONYXKEYS from '@src/ONYXKEYS';
import type {HybridAppRoute, Route} from '@src/ROUTES';
import ROUTES, {HYBRID_APP_ROUTES} from '@src/ROUTES';
import {PROTECTED_SCREENS} from '@src/SCREENS';
import SCREENS, {PROTECTED_SCREENS} from '@src/SCREENS';
import type {Screen} from '@src/SCREENS';
import type {Report} from '@src/types/onyx';
import originalCloseRHPFlow from './closeRHPFlow';
Expand Down Expand Up @@ -428,6 +428,13 @@ function getTopMostCentralPaneRouteFromRootState() {
return getTopmostCentralPaneRoute(navigationRef.getRootState() as State<RootStackParamList>);
}

function getReportRouteByID(reportID?: string) {
if (!reportID) {
return null;
}
return navigationRef.getRootState().routes.find((route) => route.name === SCREENS.REPORT && !!route.params && 'reportID' in route.params && route.params.reportID === reportID);
}

function removeScreenFromNavigationState(screen: Screen) {
isNavigationReady().then(() => {
navigationRef.dispatch((state) => {
Expand All @@ -442,6 +449,19 @@ function removeScreenFromNavigationState(screen: Screen) {
});
}

function removeScreenByKey(key: string) {
const state = navigationRef.getRootState();
const routes = state.routes.filter((item) => item.key !== key);

navigationRef.current?.dispatch(() => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
navigationRef.current?.dispatch(() => {
isNavigationReady().then(() => {
navigationRef.dispatch((state) => {
const routes = state.routes.filter((item) => item.key !== key);

return CommonActions.reset({
...state,
routes,
index: routes.length < state.routes.length ? state.index - 1 : state.index,
});
});
}

export default {
setShouldPopAllStateOnUP,
navigate,
Expand All @@ -467,6 +487,8 @@ export default {
setNavigationActionToMicrotaskQueue,
getTopMostCentralPaneRouteFromRootState,
removeScreenFromNavigationState,
removeScreenByKey,
getReportRouteByID,
};

export {navigationRef};
6 changes: 6 additions & 0 deletions src/libs/actions/IOU.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4414,6 +4414,12 @@ function requestMoney(requestMoneyInformation: RequestMoneyInformation) {

InteractionManager.runAfterInteractions(() => removeDraftTransaction(CONST.IOU.OPTIMISTIC_TRANSACTION_ID));
Navigation.dismissModal(isSearchTopmostCentralPane() ? undefined : activeReportID);

const trackReport = Navigation.getReportRouteByID(linkedTrackedExpenseReportAction?.childReportID);
if (trackReport?.key) {
Navigation.isNavigationReady().then(() => Navigation.removeScreenByKey(trackReport.key));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We're calling isNavigationReady() twice (first from here and then from inside the removeScreenByKey method itself). Is this intentional?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added the call isNavigationReady to fix the bug below with browser back button:

Screen.Recording.2025-01-07.at.23.37.22.mov

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@eVoloshchak I just updated the function logics, we don't need to use isNavigationReady here anymore.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we move .isNavigationReady() to removeScreenByKey function itself? That way we won't have to call it each time manually

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this PR I implemented the same logic without isNavigationReady, so I think we shouldn't move it to removeScreenByKey

}

if (activeReportID) {
notifyNewAction(activeReportID, payeeAccountID);
}
Expand Down
12 changes: 12 additions & 0 deletions tests/actions/IOUTest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,19 @@ jest.mock('@src/libs/Navigation/Navigation', () => ({
goBack: jest.fn(),
getTopmostReportId: jest.fn(() => topMostReportID),
setNavigationActionToMicrotaskQueue: jest.fn(),
removeScreenByKey: jest.fn(),
isNavigationReady: jest.fn(() => Promise.resolve()),
getPreviousTrackReport: jest.fn(),
}));

jest.mock('@src/libs/Navigation/navigationRef', () => ({
getRootState: () => ({
routes: [],
}),
}));

jest.mock('@react-navigation/native');

jest.mock('@src/libs/actions/Report', () => {
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
const originalModule = jest.requireActual('@src/libs/actions/Report');
Expand All @@ -88,6 +99,7 @@ jest.mock('@src/libs/actions/Report', () => {
notifyNewAction: jest.fn(),
};
});

jest.mock('@src/libs/Navigation/isSearchTopmostCentralPane', () => jest.fn());

const CARLOS_EMAIL = '[email protected]';
Expand Down
Loading