diff --git a/src/components/ReportActionItem/MoneyRequestAction.tsx b/src/components/ReportActionItem/MoneyRequestAction.tsx index 41d5249a7fbb..be2756832a87 100644 --- a/src/components/ReportActionItem/MoneyRequestAction.tsx +++ b/src/components/ReportActionItem/MoneyRequestAction.tsx @@ -10,6 +10,7 @@ import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useStyleUtils from '@hooks/useStyleUtils'; import useThemeStyles from '@hooks/useThemeStyles'; import {createTransactionThreadReport} from '@libs/actions/Report'; +import getReportRouteForCurrentContext from '@libs/Navigation/helpers/getReportRouteForCurrentContext'; import Navigation from '@libs/Navigation/Navigation'; import type {PlatformStackRouteProp} from '@libs/Navigation/PlatformStackNavigation/types'; import type {TransactionDuplicateNavigatorParamList} from '@libs/Navigation/types'; @@ -124,7 +125,7 @@ function MoneyRequestAction({ Navigation.navigate(ROUTES.SEARCH_REPORT.getRoute({reportID: transactionThreadReport?.reportID, backTo: Navigation.getActiveRoute()})); return; } - Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute(transactionThreadReport?.reportID, undefined, undefined, Navigation.getActiveRoute())); + Navigation.navigate(getReportRouteForCurrentContext({reportID: transactionThreadReport?.reportID})); return; } @@ -133,7 +134,7 @@ function MoneyRequestAction({ return; } - Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute(action?.childReportID, undefined, undefined, Navigation.getActiveRoute())); + Navigation.navigate(getReportRouteForCurrentContext({reportID: action?.childReportID})); }; const isDeletedParentAction = isDeletedParentActionReportActionsUtils(action); diff --git a/src/components/ReportActionItem/TaskPreview.tsx b/src/components/ReportActionItem/TaskPreview.tsx index e55f9aaffe6f..53993515ebfb 100644 --- a/src/components/ReportActionItem/TaskPreview.tsx +++ b/src/components/ReportActionItem/TaskPreview.tsx @@ -28,13 +28,13 @@ import {canActionTask, completeTask, getTaskAssigneeAccountID, reopenTask} from import ControlSelection from '@libs/ControlSelection'; import {canUseTouchScreen} from '@libs/DeviceCapabilities'; import getButtonState from '@libs/getButtonState'; +import getReportRouteForCurrentContext from '@libs/Navigation/helpers/getReportRouteForCurrentContext'; import Navigation from '@libs/Navigation/Navigation'; import Parser from '@libs/Parser'; import {isCanceledTaskReport, isOpenTaskReport, isReportManager} from '@libs/ReportUtils'; import type {ContextMenuAnchor} from '@pages/inbox/report/ContextMenu/ReportActionContextMenu'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; -import ROUTES from '@src/ROUTES'; import type {Report, ReportAction} from '@src/types/onyx'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; @@ -142,7 +142,7 @@ function TaskPreview({ return ( Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute(taskReportID, undefined, undefined, Navigation.getActiveRoute()))} + onPress={() => Navigation.navigate(getReportRouteForCurrentContext({reportID: taskReportID}))} onPressIn={() => canUseTouchScreen() && ControlSelection.block()} onPressOut={() => ControlSelection.unblock()} onLongPress={(event) => diff --git a/src/libs/Navigation/helpers/dismissModalForCurrentContext.ts b/src/libs/Navigation/helpers/dismissModalForCurrentContext.ts new file mode 100644 index 000000000000..13251710862b --- /dev/null +++ b/src/libs/Navigation/helpers/dismissModalForCurrentContext.ts @@ -0,0 +1,18 @@ +import Navigation from '@libs/Navigation/Navigation'; +import isSearchTopmostFullScreenRoute from './isSearchTopmostFullScreenRoute'; + +function dismissModalForCurrentContext(reportID?: string) { + if (isSearchTopmostFullScreenRoute()) { + Navigation.dismissModal(); + return; + } + + if (!reportID) { + Navigation.dismissModal(); + return; + } + + Navigation.dismissModalWithReport({reportID}); +} + +export default dismissModalForCurrentContext; diff --git a/src/libs/Navigation/helpers/getReportRouteForCurrentContext.ts b/src/libs/Navigation/helpers/getReportRouteForCurrentContext.ts new file mode 100644 index 000000000000..5b91b981db24 --- /dev/null +++ b/src/libs/Navigation/helpers/getReportRouteForCurrentContext.ts @@ -0,0 +1,22 @@ +import Navigation from '@libs/Navigation/Navigation'; +import ROUTES from '@src/ROUTES'; +import type {Route} from '@src/ROUTES'; +import isSearchTopmostFullScreenRoute from './isSearchTopmostFullScreenRoute'; + +type GetReportRouteForCurrentContextParams = { + reportID: string | undefined; + reportActionID?: string; + backTo?: Route; +}; + +function getReportRouteForCurrentContext({reportID, reportActionID, backTo}: GetReportRouteForCurrentContextParams): Route { + const currentRoute = backTo ?? (Navigation.getActiveRoute() as Route); + + if (isSearchTopmostFullScreenRoute()) { + return ROUTES.SEARCH_REPORT.getRoute({reportID, reportActionID, backTo: currentRoute}); + } + + return ROUTES.REPORT_WITH_ID.getRoute(reportID, reportActionID, undefined, currentRoute); +} + +export default getReportRouteForCurrentContext; diff --git a/src/libs/Navigation/helpers/shouldUseBackToOnLeaveReport.ts b/src/libs/Navigation/helpers/shouldUseBackToOnLeaveReport.ts new file mode 100644 index 000000000000..9f8881978985 --- /dev/null +++ b/src/libs/Navigation/helpers/shouldUseBackToOnLeaveReport.ts @@ -0,0 +1,35 @@ +import ROUTES from '@src/ROUTES'; +import type {Route} from '@src/ROUTES'; + +function normalizeRoute(route: string): string { + return route + .replaceAll(/\?.*/g, '') + .replaceAll(/^\/+|\/+$/g, '') + .replaceAll(/\/+/g, '/'); +} + +function doesRouteTargetCurrentReport(route: string, reportID: string): boolean { + const normalizedRoute = normalizeRoute(route); + const currentReportRoutes = [ + ROUTES.REPORT_WITH_ID.getRoute(reportID), + ROUTES.SEARCH_REPORT.getRoute({reportID}), + ROUTES.SEARCH_MONEY_REQUEST_REPORT.getRoute({reportID}), + ROUTES.EXPENSE_REPORT_RHP.getRoute({reportID}), + ].map(normalizeRoute); + + return currentReportRoutes.some((currentReportRoute) => normalizedRoute === currentReportRoute || normalizedRoute.startsWith(`${currentReportRoute}/`)); +} + +function shouldUseBackToOnLeaveReport(reportID: string | undefined, backTo?: Route): boolean { + if (!backTo) { + return false; + } + + if (!reportID) { + return true; + } + + return !doesRouteTargetCurrentReport(backTo, reportID); +} + +export default shouldUseBackToOnLeaveReport; diff --git a/src/libs/actions/Report/index.ts b/src/libs/actions/Report/index.ts index da6c106c15aa..3a047255d21d 100644 --- a/src/libs/actions/Report/index.ts +++ b/src/libs/actions/Report/index.ts @@ -77,7 +77,9 @@ import HttpUtils from '@libs/HttpUtils'; import Log from '@libs/Log'; import {isEmailPublicDomain} from '@libs/LoginUtils'; import {getMovedReportID} from '@libs/ModifiedExpenseMessage'; +import getReportRouteForCurrentContext from '@libs/Navigation/helpers/getReportRouteForCurrentContext'; import type {LinkToOptions} from '@libs/Navigation/helpers/linkTo/types'; +import shouldUseBackToOnLeaveReport from '@libs/Navigation/helpers/shouldUseBackToOnLeaveReport'; import Navigation from '@libs/Navigation/Navigation'; import enhanceParameters from '@libs/Network/enhanceParameters'; import * as NetworkStore from '@libs/Network/NetworkStore'; @@ -195,6 +197,7 @@ import type {OnboardingAccounting} from '@src/CONST'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; +import type {Route} from '@src/ROUTES'; import INPUT_IDS from '@src/types/form/NewRoomForm'; import type { AnyRequest, @@ -2073,7 +2076,7 @@ function navigateToAndOpenChildReport( ) { const report = childReport ?? createChildReport(childReport, parentReportAction, parentReport, currentUserAccountID, introSelected, betas); - Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute(report.reportID, undefined, undefined, Navigation.getActiveRoute())); + Navigation.navigate(getReportRouteForCurrentContext({reportID: report.reportID})); } /** @@ -4297,7 +4300,13 @@ function navigateToMostRecentReport( currentUserAccountID: number, introSelected: OnyxEntry, betas: OnyxEntry, + backTo?: Route, ) { + if (shouldUseBackToOnLeaveReport(currentReport?.reportID, backTo)) { + Navigation.goBack(backTo); + return; + } + const lastAccessedReportID = findLastAccessedReport(false, false, currentReport?.reportID)?.reportID; if (lastAccessedReportID) { @@ -4349,6 +4358,7 @@ function leaveGroupChat( conciergeReportID: string | undefined, introSelected: OnyxEntry, betas: OnyxEntry, + backTo?: Route, ) { const reportID = report.reportID; // Use merge instead of set to avoid deleting the report too quickly, which could cause a brief "not found" page to appear. @@ -4396,7 +4406,7 @@ function leaveGroupChat( }, ]; - navigateToMostRecentReport(report, conciergeReportID, currentUserAccountID, introSelected, betas); + navigateToMostRecentReport(report, conciergeReportID, currentUserAccountID, introSelected, betas, backTo); API.write(WRITE_COMMANDS.LEAVE_GROUP_CHAT, {reportID}, {optimisticData, successData, failureData}); } @@ -4408,6 +4418,7 @@ function leaveRoom( introSelected: OnyxEntry, betas: OnyxEntry, isWorkspaceMemberLeavingWorkspaceRoom = false, + backTo?: Route, ) { const reportID = report.reportID; const isChatThread = isChatThreadReportUtils(report); @@ -4512,7 +4523,7 @@ function leaveRoom( return; } // In other cases, the report is deleted and we should move the user to another report. - navigateToMostRecentReport(report, conciergeReportID, currentUserAccountID, introSelected, betas); + navigateToMostRecentReport(report, conciergeReportID, currentUserAccountID, introSelected, betas, backTo); } function buildInviteToRoomOnyxData(report: Report, inviteeEmailsToAccountIDs: InvitedEmailsToAccountIDs, formatPhoneNumber: LocaleContextProps['formatPhoneNumber']) { diff --git a/src/libs/actions/Task.ts b/src/libs/actions/Task.ts index 96226fe62507..d9828633a184 100644 --- a/src/libs/actions/Task.ts +++ b/src/libs/actions/Task.ts @@ -9,6 +9,7 @@ import {WRITE_COMMANDS} from '@libs/API/types'; import DateUtils from '@libs/DateUtils'; import * as ErrorUtils from '@libs/ErrorUtils'; import * as LocalePhoneNumber from '@libs/LocalePhoneNumber'; +import dismissModalForCurrentContext from '@libs/Navigation/helpers/dismissModalForCurrentContext'; import Navigation from '@libs/Navigation/Navigation'; import NetworkConnection from '@libs/NetworkConnection'; import * as OptionsListUtils from '@libs/OptionsListUtils'; @@ -375,7 +376,7 @@ function createTaskAndNavigate(params: CreateTaskAndNavigateParams) { InteractionManager.runAfterInteractions(() => { clearOutTaskInfo(); }); - Navigation.dismissModalWithReport({reportID: parentReportID}); + dismissModalForCurrentContext(parentReportID); } notifyNewAction(parentReportID, optimisticAddCommentReport.reportAction, true); } diff --git a/src/pages/ReportDetailsPage.tsx b/src/pages/ReportDetailsPage.tsx index cb7ad507685a..c64289673ed3 100644 --- a/src/pages/ReportDetailsPage.tsx +++ b/src/pages/ReportDetailsPage.tsx @@ -334,13 +334,13 @@ function ReportDetailsPage({policy, report, route, reportMetadata}: ReportDetail const leaveChat = useCallback(() => { if (isRootGroupChat) { - leaveGroupChat(report, quickAction?.chatReportID?.toString() === report.reportID, currentUserPersonalDetails.accountID, conciergeReportID, introSelected, betas); + leaveGroupChat(report, quickAction?.chatReportID?.toString() === report.reportID, currentUserPersonalDetails.accountID, conciergeReportID, introSelected, betas, backTo); return; } const isWorkspaceMemberLeavingWorkspaceRoom = isWorkspaceMemberLeavingWorkspaceRoomUtil(report, isPolicyEmployee, isPolicyAdmin); - leaveRoom(report, currentUserPersonalDetails.accountID, conciergeReportID, introSelected, betas, isWorkspaceMemberLeavingWorkspaceRoom); - }, [isRootGroupChat, isPolicyEmployee, isPolicyAdmin, quickAction?.chatReportID, report, currentUserPersonalDetails.accountID, conciergeReportID, introSelected, betas]); + leaveRoom(report, currentUserPersonalDetails.accountID, conciergeReportID, introSelected, betas, isWorkspaceMemberLeavingWorkspaceRoom, backTo); + }, [isRootGroupChat, isPolicyEmployee, isPolicyAdmin, quickAction?.chatReportID, report, currentUserPersonalDetails.accountID, conciergeReportID, introSelected, betas, backTo]); const showLastMemberLeavingModal = useCallback(async () => { const {action} = await showConfirmModal({ @@ -634,6 +634,7 @@ function ReportDetailsPage({policy, report, route, reportMetadata}: ReportDetail iouTransactionID, moneyRequestReport?.reportID, currentUserPersonalDetails.accountID, + currentUserPersonalDetails.email, isTaskActionable, isRootGroupChat, leaveChat, diff --git a/src/pages/inbox/ReportNavigateAwayHandler.tsx b/src/pages/inbox/ReportNavigateAwayHandler.tsx index 1022dcab9fe9..696658039ca3 100644 --- a/src/pages/inbox/ReportNavigateAwayHandler.tsx +++ b/src/pages/inbox/ReportNavigateAwayHandler.tsx @@ -8,6 +8,7 @@ import useParentReportAction from '@hooks/useParentReportAction'; import usePrevious from '@hooks/usePrevious'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; import getNonEmptyStringOnyxID from '@libs/getNonEmptyStringOnyxID'; +import isSearchTopmostFullScreenRoute from '@libs/Navigation/helpers/isSearchTopmostFullScreenRoute'; import Navigation, {navigationRef} from '@libs/Navigation/Navigation'; import type {PlatformStackRouteProp} from '@libs/Navigation/PlatformStackNavigation/types'; import {isDeletedParentAction} from '@libs/ReportActionsUtils'; @@ -204,6 +205,10 @@ function ReportNavigateAwayHandler() { // Fallback to Concierge Navigation.isNavigationReady().then(() => { + if (isSearchTopmostFullScreenRoute()) { + Navigation.dismissModal(); + return; + } navigateToConciergeChat(conciergeReportID, introSelected, currentUserAccountID, isSelfTourViewed, betas); }); }, [reportWasDeleted, isFocused, deletedReportParentID, conciergeReportID, introSelected, currentUserAccountID, isSelfTourViewed, betas]); diff --git a/src/pages/tasks/TaskAssigneeSelectorModal.tsx b/src/pages/tasks/TaskAssigneeSelectorModal.tsx index 3ca48090f11a..e07f6ecef94f 100644 --- a/src/pages/tasks/TaskAssigneeSelectorModal.tsx +++ b/src/pages/tasks/TaskAssigneeSelectorModal.tsx @@ -24,6 +24,7 @@ import {searchUserInServer} from '@libs/actions/Report'; import {canModifyTask, editTaskAssignee, setAssigneeValue} from '@libs/actions/Task'; import {READ_COMMANDS} from '@libs/API/types'; import HttpUtils from '@libs/HttpUtils'; +import dismissModalForCurrentContext from '@libs/Navigation/helpers/dismissModalForCurrentContext'; import Navigation from '@libs/Navigation/Navigation'; import type {PlatformStackRouteProp} from '@libs/Navigation/PlatformStackNavigation/types'; import {getHeaderMessage, isCurrentUser} from '@libs/OptionsListUtils'; @@ -88,7 +89,7 @@ function TaskAssigneeSelectorModal() { const reportOnyx = reports?.[`${ONYXKEYS.COLLECTION.REPORT}${route.params?.reportID}`]; if (reportOnyx && !isTaskReport(reportOnyx)) { Navigation.isNavigationReady().then(() => { - Navigation.dismissModalWithReport({reportID: reportOnyx.reportID}); + dismissModalForCurrentContext(reportOnyx.reportID); }); } return reports?.[`${ONYXKEYS.COLLECTION.REPORT}${route.params?.reportID}`]; @@ -184,7 +185,7 @@ function TaskAssigneeSelectorModal() { } // eslint-disable-next-line @typescript-eslint/no-deprecated InteractionManager.runAfterInteractions(() => { - Navigation.dismissModalWithReport({reportID: report?.reportID}); + dismissModalForCurrentContext(report?.reportID); }); // If there's no report, we're creating a new task } else if (option.accountID) { diff --git a/src/pages/tasks/TaskDescriptionPage.tsx b/src/pages/tasks/TaskDescriptionPage.tsx index 7c15678b12f4..f9394260b9b4 100644 --- a/src/pages/tasks/TaskDescriptionPage.tsx +++ b/src/pages/tasks/TaskDescriptionPage.tsx @@ -17,6 +17,7 @@ import useOnyx from '@hooks/useOnyx'; import useReportIsArchived from '@hooks/useReportIsArchived'; import useThemeStyles from '@hooks/useThemeStyles'; import {addErrorMessage} from '@libs/ErrorUtils'; +import dismissModalForCurrentContext from '@libs/Navigation/helpers/dismissModalForCurrentContext'; import Navigation from '@libs/Navigation/Navigation'; import type {PlatformStackRouteProp} from '@libs/Navigation/PlatformStackNavigation/types'; import type {ReportDescriptionNavigatorParamList} from '@libs/Navigation/types'; @@ -62,14 +63,14 @@ function TaskDescriptionPage({report, currentUserPersonalDetails}: TaskDescripti editTask(report, {description: values.description}, delegateEmail); } - Navigation.dismissModalWithReport({reportID: report?.reportID}); + dismissModalForCurrentContext(report?.reportID); }, [report, delegateEmail], ); if (!isTaskReport(report)) { Navigation.isNavigationReady().then(() => { - Navigation.dismissModalWithReport({reportID: report?.reportID}); + dismissModalForCurrentContext(report?.reportID); }); } const inputRef = useRef(null); diff --git a/src/pages/tasks/TaskTitlePage.tsx b/src/pages/tasks/TaskTitlePage.tsx index 0dd7c78efcc3..bea3dab188b4 100644 --- a/src/pages/tasks/TaskTitlePage.tsx +++ b/src/pages/tasks/TaskTitlePage.tsx @@ -17,6 +17,7 @@ import useOnyx from '@hooks/useOnyx'; import useReportIsArchived from '@hooks/useReportIsArchived'; import useThemeStyles from '@hooks/useThemeStyles'; import {addErrorMessage} from '@libs/ErrorUtils'; +import dismissModalForCurrentContext from '@libs/Navigation/helpers/dismissModalForCurrentContext'; import Navigation from '@libs/Navigation/Navigation'; import type {PlatformStackRouteProp} from '@libs/Navigation/PlatformStackNavigation/types'; import type {TaskDetailsNavigatorParamList} from '@libs/Navigation/types'; @@ -67,14 +68,14 @@ function TaskTitlePage({report, currentUserPersonalDetails}: TaskTitlePageProps) editTask(report, {title: values.title}, delegateEmail); } - Navigation.dismissModalWithReport({reportID: report?.reportID}); + dismissModalForCurrentContext(report?.reportID); }, [report, delegateEmail], ); if (!isTaskReport(report)) { Navigation.isNavigationReady().then(() => { - Navigation.dismissModalWithReport({reportID: report?.reportID}); + dismissModalForCurrentContext(report?.reportID); }); }