diff --git a/config/eslint/eslint.seatbelt.tsv b/config/eslint/eslint.seatbelt.tsv index 675bd99f5f86..42b3460c6f86 100644 --- a/config/eslint/eslint.seatbelt.tsv +++ b/config/eslint/eslint.seatbelt.tsv @@ -68,7 +68,7 @@ "../../src/Expensify.tsx" "react-hooks/set-state-in-effect" 1 "../../src/GlobalModals.tsx" "no-restricted-syntax" 2 "../../src/ONYXKEYS.ts" "no-restricted-syntax" 2 -"../../src/ROUTES.ts" "@typescript-eslint/no-deprecated/getUrlWithBackToParam" 128 +"../../src/ROUTES.ts" "@typescript-eslint/no-deprecated/getUrlWithBackToParam" 123 "../../src/ROUTES.ts" "@typescript-eslint/no-unsafe-type-assertion" 3 "../../src/TIMEZONES.ts" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/components/AccountingConnectionConfirmationModal.tsx" "@typescript-eslint/no-deprecated/ConfirmModal" 1 @@ -1089,8 +1089,9 @@ "../../src/pages/TransactionMerge/MergeTransactionsListContent.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/pages/Travel/DynamicTravelTerms.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/pages/Travel/DynamicTravelUpgrade.tsx" "no-restricted-imports" 1 +"../../src/pages/Travel/DynamicWorkspaceAddressForTravelPage.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 +"../../src/pages/Travel/DynamicWorkspaceConfirmationForTravelPage.tsx" "@typescript-eslint/no-unsafe-type-assertion" 2 "../../src/pages/Travel/TravelUpgrade.tsx" "react-hooks/set-state-in-effect" 1 -"../../src/pages/Travel/WorkspaceConfirmationForTravelPage.tsx" "@typescript-eslint/no-unsafe-type-assertion" 2 "../../src/pages/UnreportedExpenseListItem.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/pages/ValidateLoginPage/index.web.tsx" "react-hooks/set-state-in-effect" 1 "../../src/pages/domain/Groups/PreferredWorkspaceToggle.tsx" "@typescript-eslint/no-deprecated/ConfirmModal" 1 diff --git a/src/ROUTES.ts b/src/ROUTES.ts index 5df7e70352c3..e6424980abdb 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -462,7 +462,7 @@ const DYNAMIC_ROUTES = { SCREENS.WORKSPACE.DYNAMIC_WORKSPACE_OVERVIEW_ADDRESS, SCREENS.SETTINGS.WALLET.CARDS_DIGITAL_DETAILS_UPDATE_ADDRESS, SCREENS.DOMAIN_CARD.DOMAIN_CARD_UPDATE_ADDRESS, - SCREENS.TRAVEL.WORKSPACE_ADDRESS, + SCREENS.TRAVEL.DYNAMIC_WORKSPACE_ADDRESS, SCREENS.SETTINGS.ADD_US_BANK_ACCOUNT, ], getRoute: (country = '') => `country?country=${country}`, @@ -794,8 +794,8 @@ const DYNAMIC_ROUTES = { SCREENS.WORKSPACE.TRAVEL, SCREENS.SEARCH.ROOT, SCREENS.TRAVEL.DYNAMIC_DOMAIN_SELECTOR, - SCREENS.TRAVEL.WORKSPACE_ADDRESS, - SCREENS.TRAVEL.VERIFY_ACCOUNT, + SCREENS.TRAVEL.DYNAMIC_WORKSPACE_ADDRESS, + SCREENS.TRAVEL.DYNAMIC_VERIFY_ACCOUNT, ], getRoute: (domain: string, policyID?: string) => `terms/${domain}/accept${policyID ? `/${policyID}` : ''}`, }, @@ -803,6 +803,16 @@ const DYNAMIC_ROUTES = { path: 'domain-permission-info', entryScreens: [SCREENS.TRAVEL.DYNAMIC_TCS], }, + TRAVEL_WORKSPACE_ADDRESS: { + path: 'workspace-address/:domain/:policyID?', + entryScreens: [SCREENS.TRAVEL.MY_TRIPS, SCREENS.WORKSPACE.TRAVEL, SCREENS.SEARCH.ROOT, SCREENS.TRAVEL.DYNAMIC_DOMAIN_SELECTOR], + getRoute: (domain: string, policyID?: string) => `workspace-address/${domain}${policyID ? `/${policyID}` : ''}`, + }, + TRAVEL_VERIFY_ACCOUNT: { + path: 'verify-account/:domain/:policyID?', + entryScreens: [SCREENS.TRAVEL.MY_TRIPS, SCREENS.WORKSPACE.TRAVEL, SCREENS.SEARCH.ROOT, SCREENS.TRAVEL.DYNAMIC_DOMAIN_SELECTOR, SCREENS.TRAVEL.DYNAMIC_WORKSPACE_ADDRESS], + getRoute: (domain: string, policyID?: string) => `verify-account/${domain}${policyID ? `/${policyID}` : ''}`, + }, TRAVEL_DOMAIN_SELECTOR: { path: 'domain-selector', entryScreens: [SCREENS.TRAVEL.MY_TRIPS, SCREENS.WORKSPACE.TRAVEL, SCREENS.SEARCH.ROOT], @@ -813,6 +823,20 @@ const DYNAMIC_ROUTES = { path: 'travel-upgrade', entryScreens: [SCREENS.TRAVEL.MY_TRIPS, SCREENS.WORKSPACE.TRAVEL, SCREENS.SEARCH.ROOT], }, + TRAVEL_WORKSPACE_CONFIRMATION: { + path: 'workspace-confirmation', + entryScreens: [SCREENS.TRAVEL.DYNAMIC_UPGRADE], + }, + TRAVEL_TRIP_SUMMARY: { + path: 'trip/:transactionID', + entryScreens: [SCREENS.REPORT], + getRoute: (transactionID: string) => `trip/${transactionID}` as const, + }, + TRAVEL_TRIP_DETAILS: { + path: 'trip/:transactionID/:pnr/:sequenceIndex', + entryScreens: [SCREENS.REPORT], + getRoute: (transactionID: string, pnr: string, sequenceIndex: number | string) => `trip/${transactionID}/${pnr}/${sequenceIndex}` as const, + }, REPORT_CHANGE_APPROVER: { path: 'change-approver', entryScreens: [SCREENS.REPORT, SCREENS.RIGHT_MODAL.SEARCH_REPORT, SCREENS.RIGHT_MODAL.EXPENSE_REPORT, SCREENS.RIGHT_MODAL.SEARCH_MONEY_REQUEST_REPORT], @@ -3269,41 +3293,6 @@ const ROUTES = { }, }, TRACK_TRAINING_MODAL: 'track-training', - TRAVEL_TRIP_SUMMARY: { - route: 'r/:reportID/trip/:transactionID', - getRoute: (reportID: string | undefined, transactionID: string | undefined, backTo?: string) => { - if (!reportID || !transactionID) { - Log.warn('Invalid reportID or transactionID is used to build the TRAVEL_TRIP_SUMMARY route'); - } - - return getUrlWithBackToParam(`r/${reportID}/trip/${transactionID}`, backTo); - }, - }, - TRAVEL_TRIP_DETAILS: { - route: 'r/:reportID/trip/:transactionID/:pnr/:sequenceIndex', - getRoute: (reportID: string | undefined, transactionID: string | undefined, pnr: string | undefined, sequenceIndex: number, backTo?: string) => { - if (!reportID || !transactionID || !pnr) { - Log.warn('Invalid reportID, transactionID or pnr is used to build the TRAVEL_TRIP_DETAILS route'); - } - - return getUrlWithBackToParam(`r/${reportID}/trip/${transactionID}/${pnr}/${sequenceIndex}`, backTo); - }, - }, - TRAVEL_WORKSPACE_CONFIRMATION: { - route: 'travel/upgrade/workspace/confirmation', - - getRoute: (backTo?: string) => getUrlWithBackToParam(`travel/upgrade/workspace/confirmation`, backTo), - }, - TRAVEL_WORKSPACE_ADDRESS: { - route: 'travel/:domain/workspace-address', - - getRoute: (domain: string, policyID?: string, backTo?: string) => getUrlWithBackToParam(`travel/${domain}/workspace-address?${policyID ? `policyID=${policyID}` : ''}`, backTo), - }, - TRAVEL_VERIFY_ACCOUNT: { - route: `travel/${VERIFY_ACCOUNT}`, - - getRoute: (domain?: string, policyID?: string, backTo?: string) => getUrlWithBackToParam(getUrlWithParams(`travel/${VERIFY_ACCOUNT}`, {domain, policyID}), backTo), - }, ONBOARDING_ROOT: { route: 'onboarding', diff --git a/src/SCREENS.ts b/src/SCREENS.ts index 76215625daca..733386ac61c0 100644 --- a/src/SCREENS.ts +++ b/src/SCREENS.ts @@ -33,14 +33,14 @@ const SCREENS = { DYNAMIC_TCS: 'Dynamic_Travel_TCS', DYNAMIC_UPGRADE: 'Dynamic_Travel_Upgrade', DYNAMIC_DOMAIN_PERMISSION_INFO: 'Dynamic_Travel_DomainPermissionInfo', - TRIP_SUMMARY: 'Travel_TripSummary', - TRIP_DETAILS: 'Travel_TripDetails', + DYNAMIC_TRIP_SUMMARY: 'Dynamic_Travel_TripSummary', + DYNAMIC_TRIP_DETAILS: 'Dynamic_Travel_TripDetails', DYNAMIC_DOMAIN_SELECTOR: 'Dynamic_Travel_DomainSelector', DYNAMIC_PUBLIC_DOMAIN_ERROR: 'Dynamic_Travel_PublicDomainError', - WORKSPACE_CONFIRMATION: 'Travel_WorkspaceConfirmation', - WORKSPACE_ADDRESS: 'Travel_WorkspaceAddress', + DYNAMIC_WORKSPACE_CONFIRMATION: 'Dynamic_Travel_WorkspaceConfirmation', + DYNAMIC_WORKSPACE_ADDRESS: 'Dynamic_Travel_WorkspaceAddress', TRAVEL_DOT_LINK_WEB_VIEW: 'Travel_DotLinkWebView', - VERIFY_ACCOUNT: 'Travel_VerifyAccount', + DYNAMIC_VERIFY_ACCOUNT: 'Dynamic_Travel_VerifyAccount', MISSING_PERSONAL_DETAILS_CONFIRM_MAGIC_CODE: 'Travel_MissingPersonalDetails_ConfirmMagicCode', }, SEARCH: { diff --git a/src/components/BookTravelButton.tsx b/src/components/BookTravelButton.tsx index 6a088fd51931..976de0bfa719 100644 --- a/src/components/BookTravelButton.tsx +++ b/src/components/BookTravelButton.tsx @@ -53,7 +53,7 @@ const navigateToAcceptTerms = (domain: string, isUserValidated?: boolean, policy Navigation.navigate(createDynamicRoute(DYNAMIC_ROUTES.TRAVEL_TCS.getRoute(domain, policyID))); return; } - Navigation.navigate(ROUTES.TRAVEL_VERIFY_ACCOUNT.getRoute(domain, policyID, Navigation.getActiveRoute())); + Navigation.navigate(createDynamicRoute(DYNAMIC_ROUTES.TRAVEL_VERIFY_ACCOUNT.getRoute(domain, policyID))); }; const hasPolicyIDInActiveRoute = () => getSearchParamFromPath(Navigation.getActiveRoute(), CONST.SEARCH.SYNTAX_FILTER_KEYS.POLICY_ID) !== null; @@ -164,7 +164,7 @@ function BookTravelButton({ navigateToAcceptTerms(CONST.TRAVEL.DEFAULT_DOMAIN, undefined, activePolicyID ?? undefined); } else if (!isBetaEnabled(CONST.BETAS.IS_TRAVEL_VERIFIED)) { if (!isUserValidated) { - Navigation.navigate(ROUTES.TRAVEL_VERIFY_ACCOUNT.getRoute(undefined, activePolicyID, Navigation.getActiveRoute())); + Navigation.navigate(createDynamicRoute(DYNAMIC_ROUTES.TRAVEL_VERIFY_ACCOUNT.getRoute(CONST.TRAVEL.DEFAULT_DOMAIN, activePolicyID))); return; } if (shouldShowVerifyAccountModal) { @@ -194,15 +194,15 @@ function BookTravelButton({ if (!isUserValidated) { // Determine where to redirect after OTP validation const nextStep = isEmptyObject(policy?.address) - ? ROUTES.TRAVEL_WORKSPACE_ADDRESS.getRoute(domain, activePolicyID, Navigation.getActiveRoute()) + ? createDynamicRoute(DYNAMIC_ROUTES.TRAVEL_WORKSPACE_ADDRESS.getRoute(domain, activePolicyID)) : createDynamicRoute(DYNAMIC_ROUTES.TRAVEL_TCS.getRoute(domain, activePolicyID)); setTravelProvisioningNextStep(nextStep); - Navigation.navigate(ROUTES.TRAVEL_VERIFY_ACCOUNT.getRoute(domain, activePolicyID, Navigation.getActiveRoute())); + Navigation.navigate(createDynamicRoute(DYNAMIC_ROUTES.TRAVEL_VERIFY_ACCOUNT.getRoute(domain, activePolicyID))); return; } if (isEmptyObject(policy?.address)) { // Spotnana requires an address anytime an entity is created for a policy - Navigation.navigate(ROUTES.TRAVEL_WORKSPACE_ADDRESS.getRoute(domain, activePolicyID, Navigation.getActiveRoute())); + Navigation.navigate(createDynamicRoute(DYNAMIC_ROUTES.TRAVEL_WORKSPACE_ADDRESS.getRoute(domain, activePolicyID))); } else { navigateToAcceptTerms(domain, !!isUserValidated, activePolicyID ?? undefined); } diff --git a/src/components/ReportActionItem/MoneyRequestView.tsx b/src/components/ReportActionItem/MoneyRequestView.tsx index b191f9062552..c60763ad8b6a 100644 --- a/src/components/ReportActionItem/MoneyRequestView.tsx +++ b/src/components/ReportActionItem/MoneyRequestView.tsx @@ -57,6 +57,7 @@ import DistanceRequestUtils from '@libs/DistanceRequestUtils'; import getNonEmptyStringOnyxID from '@libs/getNonEmptyStringOnyxID'; import {getRateFromMerchant} from '@libs/MergeTransactionUtils'; import {isBillableEnabledOnPolicy, isSingleTransactionReport} from '@libs/MoneyRequestReportUtils'; +import createDynamicRoute from '@libs/Navigation/helpers/dynamicRoutesUtils/createDynamicRoute'; import {hasEnabledOptions} from '@libs/OptionsListUtils'; import Parser from '@libs/Parser'; import { @@ -133,7 +134,7 @@ import AnimatedEmptyStateBackground from '@pages/inbox/report/AnimatedEmptyState import CONST from '@src/CONST'; import type {TranslationPaths} from '@src/languages/types'; import ONYXKEYS from '@src/ONYXKEYS'; -import ROUTES from '@src/ROUTES'; +import ROUTES, {DYNAMIC_ROUTES} from '@src/ROUTES'; import type * as OnyxTypes from '@src/types/onyx'; import type {TransactionPendingFieldsKey} from '@src/types/onyx/Transaction'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; @@ -1515,10 +1516,17 @@ function MoneyRequestView({ icon={icons.Suitcase} onPress={() => { const reservations = transaction?.receipt?.reservationList?.length ?? 0; + const reportID = transactionThreadReport?.reportID; if (reservations > 1) { - Navigation.navigate(ROUTES.TRAVEL_TRIP_SUMMARY.getRoute(transactionThreadReport?.reportID, transaction.transactionID, getReportRHPActiveRoute())); + if (!reportID) { + return; + } + Navigation.navigate(createDynamicRoute(DYNAMIC_ROUTES.TRAVEL_TRIP_SUMMARY.getRoute(transaction.transactionID), ROUTES.REPORT_WITH_ID.getRoute(reportID))); + } + if (!reportID) { + return; } - Navigation.navigate(ROUTES.TRAVEL_TRIP_DETAILS.getRoute(transactionThreadReport?.reportID, transaction.transactionID, '0', 0, getReportRHPActiveRoute())); + Navigation.navigate(createDynamicRoute(DYNAMIC_ROUTES.TRAVEL_TRIP_DETAILS.getRoute(transaction.transactionID, '0', 0), ROUTES.REPORT_WITH_ID.getRoute(reportID))); }} /> )} diff --git a/src/components/ReportActionItem/TripDetailsView.tsx b/src/components/ReportActionItem/TripDetailsView.tsx index 235a37d7f52d..da9d4d06d012 100644 --- a/src/components/ReportActionItem/TripDetailsView.tsx +++ b/src/components/ReportActionItem/TripDetailsView.tsx @@ -17,13 +17,14 @@ import useStyleUtils from '@hooks/useStyleUtils'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; import DateUtils from '@libs/DateUtils'; +import createDynamicRoute from '@libs/Navigation/helpers/dynamicRoutesUtils/createDynamicRoute'; import Navigation from '@libs/Navigation/Navigation'; import StringUtils from '@libs/StringUtils'; import variables from '@styles/variables'; import CONST from '@src/CONST'; import type {ReservationData} from '@src/libs/TripReservationUtils'; import {formatCancelledDescription, formatTransitLocationLabel, getPNRReservationDataFromTripReport, getTripReservationCode, getTripReservationIcon} from '@src/libs/TripReservationUtils'; -import ROUTES from '@src/ROUTES'; +import ROUTES, {DYNAMIC_ROUTES} from '@src/ROUTES'; import type {Report} from '@src/types/onyx'; import type {Reservation} from '@src/types/onyx/Transaction'; import type Transaction from '@src/types/onyx/Transaction'; @@ -166,7 +167,10 @@ function ReservationView({reservation, transactionID, tripRoomReportID, sequence secondaryIconFill={theme.icon} onPress={() => Navigation.navigate( - ROUTES.TRAVEL_TRIP_DETAILS.getRoute(tripRoomReportID, transactionID, String(reservation.reservationID), sequenceIndex, Navigation.getReportRHPActiveRoute()), + createDynamicRoute( + DYNAMIC_ROUTES.TRAVEL_TRIP_DETAILS.getRoute(transactionID, String(reservation.reservationID), sequenceIndex), + ROUTES.REPORT_WITH_ID.getRoute(tripRoomReportID), + ), ) } /> diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx index 90483d2d70f9..149ff7e1ecc5 100644 --- a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx +++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx @@ -85,10 +85,10 @@ const OPTIONS_PER_SCREEN: Partial [SCREENS.SEARCH.TRANSACTIONS_CHANGE_REPORT_SEARCH_RHP]: { animation: Animations.NONE, }, - [SCREENS.TRAVEL.VERIFY_ACCOUNT]: { + [SCREENS.TRAVEL.DYNAMIC_VERIFY_ACCOUNT]: { animationTypeForReplace: 'push', }, - [SCREENS.TRAVEL.WORKSPACE_ADDRESS]: { + [SCREENS.TRAVEL.DYNAMIC_WORKSPACE_ADDRESS]: { animationTypeForReplace: 'push', }, [SCREENS.MULTIFACTOR_AUTHENTICATION.REVOKE]: { @@ -231,14 +231,14 @@ const TravelModalStackNavigator = createModalStackNavigator require('../../../../pages/Travel/TravelDotLinkWebview').default, [SCREENS.TRAVEL.DYNAMIC_TCS]: () => require('../../../../pages/Travel/DynamicTravelTerms').default, [SCREENS.TRAVEL.DYNAMIC_UPGRADE]: () => require('../../../../pages/Travel/DynamicTravelUpgrade').default, - [SCREENS.TRAVEL.TRIP_SUMMARY]: () => require('../../../../pages/Travel/TripSummaryPage').default, - [SCREENS.TRAVEL.TRIP_DETAILS]: () => require('../../../../pages/Travel/TripDetailsPage').default, + [SCREENS.TRAVEL.DYNAMIC_TRIP_SUMMARY]: () => require('../../../../pages/Travel/DynamicTripSummaryPage').default, + [SCREENS.TRAVEL.DYNAMIC_TRIP_DETAILS]: () => require('../../../../pages/Travel/DynamicTripDetailsPage').default, [SCREENS.TRAVEL.DYNAMIC_DOMAIN_SELECTOR]: () => require('../../../../pages/Travel/DynamicDomainSelectorPage').default, [SCREENS.TRAVEL.DYNAMIC_DOMAIN_PERMISSION_INFO]: () => require('../../../../pages/Travel/DynamicDomainPermissionInfoPage').default, [SCREENS.TRAVEL.DYNAMIC_PUBLIC_DOMAIN_ERROR]: () => require('../../../../pages/Travel/DynamicPublicDomainErrorPage').default, - [SCREENS.TRAVEL.WORKSPACE_CONFIRMATION]: () => require('../../../../pages/Travel/WorkspaceConfirmationForTravelPage').default, - [SCREENS.TRAVEL.WORKSPACE_ADDRESS]: () => require('../../../../pages/Travel/WorkspaceAddressForTravelPage').default, - [SCREENS.TRAVEL.VERIFY_ACCOUNT]: () => require('../../../../pages/Travel/VerifyAccountPage').default, + [SCREENS.TRAVEL.DYNAMIC_WORKSPACE_CONFIRMATION]: () => require('../../../../pages/Travel/DynamicWorkspaceConfirmationForTravelPage').default, + [SCREENS.TRAVEL.DYNAMIC_WORKSPACE_ADDRESS]: () => require('../../../../pages/Travel/DynamicWorkspaceAddressForTravelPage').default, + [SCREENS.TRAVEL.DYNAMIC_VERIFY_ACCOUNT]: () => require('../../../../pages/Travel/DynamicVerifyAccountPage').default, }); const SplitDetailsModalStackNavigator = createModalStackNavigator({ diff --git a/src/libs/Navigation/linkingConfig/config.ts b/src/libs/Navigation/linkingConfig/config.ts index 4af188881270..1a0b82248780 100644 --- a/src/libs/Navigation/linkingConfig/config.ts +++ b/src/libs/Navigation/linkingConfig/config.ts @@ -1922,19 +1922,14 @@ const config: LinkingOptions['config'] = { [SCREENS.TRAVEL.TRAVEL_DOT_LINK_WEB_VIEW]: ROUTES.TRAVEL_DOT_LINK_WEB_VIEW.route, [SCREENS.TRAVEL.DYNAMIC_UPGRADE]: DYNAMIC_ROUTES.TRAVEL_UPGRADE.path, [SCREENS.TRAVEL.DYNAMIC_TCS]: DYNAMIC_ROUTES.TRAVEL_TCS.path, - [SCREENS.TRAVEL.TRIP_SUMMARY]: ROUTES.TRAVEL_TRIP_SUMMARY.route, - [SCREENS.TRAVEL.TRIP_DETAILS]: { - path: ROUTES.TRAVEL_TRIP_DETAILS.route, - parse: { - reservationIndex: (reservationIndex: string) => parseInt(reservationIndex, 10), - }, - }, + [SCREENS.TRAVEL.DYNAMIC_TRIP_SUMMARY]: DYNAMIC_ROUTES.TRAVEL_TRIP_SUMMARY.path, + [SCREENS.TRAVEL.DYNAMIC_TRIP_DETAILS]: DYNAMIC_ROUTES.TRAVEL_TRIP_DETAILS.path, [SCREENS.TRAVEL.DYNAMIC_DOMAIN_SELECTOR]: DYNAMIC_ROUTES.TRAVEL_DOMAIN_SELECTOR.path, [SCREENS.TRAVEL.DYNAMIC_DOMAIN_PERMISSION_INFO]: DYNAMIC_ROUTES.TRAVEL_DOMAIN_PERMISSION_INFO.path, [SCREENS.TRAVEL.DYNAMIC_PUBLIC_DOMAIN_ERROR]: DYNAMIC_ROUTES.TRAVEL_PUBLIC_DOMAIN_ERROR.path, - [SCREENS.TRAVEL.WORKSPACE_CONFIRMATION]: ROUTES.TRAVEL_WORKSPACE_CONFIRMATION.route, - [SCREENS.TRAVEL.WORKSPACE_ADDRESS]: ROUTES.TRAVEL_WORKSPACE_ADDRESS.route, - [SCREENS.TRAVEL.VERIFY_ACCOUNT]: ROUTES.TRAVEL_VERIFY_ACCOUNT.route, + [SCREENS.TRAVEL.DYNAMIC_WORKSPACE_CONFIRMATION]: DYNAMIC_ROUTES.TRAVEL_WORKSPACE_CONFIRMATION.path, + [SCREENS.TRAVEL.DYNAMIC_WORKSPACE_ADDRESS]: DYNAMIC_ROUTES.TRAVEL_WORKSPACE_ADDRESS.path, + [SCREENS.TRAVEL.DYNAMIC_VERIFY_ACCOUNT]: DYNAMIC_ROUTES.TRAVEL_VERIFY_ACCOUNT.path, }, }, [SCREENS.RIGHT_MODAL.SEARCH_COLUMNS]: { diff --git a/src/libs/Navigation/types.ts b/src/libs/Navigation/types.ts index b8dfb6d7739e..30a22fd746ca 100644 --- a/src/libs/Navigation/types.ts +++ b/src/libs/Navigation/types.ts @@ -2629,19 +2629,15 @@ type TravelNavigatorParamList = { isTestAccount?: string; redirectUrl?: string; }; - [SCREENS.TRAVEL.TRIP_SUMMARY]: { + [SCREENS.TRAVEL.DYNAMIC_TRIP_SUMMARY]: { reportID: string; transactionID: string; - // eslint-disable-next-line no-restricted-syntax -- `backTo` usages in this file are legacy. Do not add new `backTo` params to screens. See contributingGuides/NAVIGATION.md - backTo?: string; }; - [SCREENS.TRAVEL.TRIP_DETAILS]: { + [SCREENS.TRAVEL.DYNAMIC_TRIP_DETAILS]: { reportID: string; transactionID: string; - sequenceIndex: number; + sequenceIndex: string; pnr: string; - // eslint-disable-next-line no-restricted-syntax -- `backTo` usages in this file are legacy. Do not add new `backTo` params to screens. See contributingGuides/NAVIGATION.md - backTo?: string; }; [SCREENS.TRAVEL.DYNAMIC_TCS]: { domain?: string; @@ -2651,14 +2647,9 @@ type TravelNavigatorParamList = { domain: string; policyID?: string; }; - [SCREENS.TRAVEL.WORKSPACE_CONFIRMATION]: { - // eslint-disable-next-line no-restricted-syntax -- `backTo` usages in this file are legacy. Do not add new `backTo` params to screens. See contributingGuides/NAVIGATION.md - backTo?: Routes; - }; - [SCREENS.TRAVEL.WORKSPACE_ADDRESS]: { + [SCREENS.TRAVEL.DYNAMIC_WORKSPACE_CONFIRMATION]: undefined; + [SCREENS.TRAVEL.DYNAMIC_WORKSPACE_ADDRESS]: { domain: string; - // eslint-disable-next-line no-restricted-syntax -- `backTo` usages in this file are legacy. Do not add new `backTo` params to screens. See contributingGuides/NAVIGATION.md - backTo?: Routes; policyID?: string; }; [SCREENS.TRAVEL.DYNAMIC_PUBLIC_DOMAIN_ERROR]: { @@ -2668,11 +2659,9 @@ type TravelNavigatorParamList = { [SCREENS.TRAVEL.DYNAMIC_DOMAIN_SELECTOR]: { policyID?: string; }; - [SCREENS.TRAVEL.VERIFY_ACCOUNT]: { - domain?: string; + [SCREENS.TRAVEL.DYNAMIC_VERIFY_ACCOUNT]: { + domain: string; policyID?: string; - // eslint-disable-next-line no-restricted-syntax -- `backTo` usages in this file are legacy. Do not add new `backTo` params to screens. See contributingGuides/NAVIGATION.md - backTo?: Routes; }; }; diff --git a/src/pages/Travel/DynamicDomainSelectorPage.tsx b/src/pages/Travel/DynamicDomainSelectorPage.tsx index 8f2bf62f6db1..7fd52deb552b 100644 --- a/src/pages/Travel/DynamicDomainSelectorPage.tsx +++ b/src/pages/Travel/DynamicDomainSelectorPage.tsx @@ -22,7 +22,7 @@ import {getAdminsPrivateEmailDomains, getMostFrequentEmailDomain} from '@libs/Po import AccessOrNotFoundWrapper from '@pages/workspace/AccessOrNotFoundWrapper'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; -import ROUTES, {DYNAMIC_ROUTES} from '@src/ROUTES'; +import {DYNAMIC_ROUTES} from '@src/ROUTES'; import type SCREENS from '@src/SCREENS'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; @@ -65,15 +65,15 @@ function DynamicDomainSelectorPage({route}: DomainSelectorPageProps) { if (!isUserValidated) { // Determine where to redirect after OTP validation const nextStep = isEmptyObject(policy?.address) - ? ROUTES.TRAVEL_WORKSPACE_ADDRESS.getRoute(domain, policyID, Navigation.getActiveRoute()) + ? createDynamicRoute(DYNAMIC_ROUTES.TRAVEL_WORKSPACE_ADDRESS.getRoute(domain, policyID)) : createDynamicRoute(DYNAMIC_ROUTES.TRAVEL_TCS.getRoute(domain, policyID)); setTravelProvisioningNextStep(nextStep); - Navigation.navigate(ROUTES.TRAVEL_VERIFY_ACCOUNT.getRoute(domain, policyID)); + Navigation.navigate(createDynamicRoute(DYNAMIC_ROUTES.TRAVEL_VERIFY_ACCOUNT.getRoute(domain, policyID))); return; } if (isEmptyObject(policy?.address)) { // Spotnana requires an address anytime an entity is created for a policy - Navigation.navigate(ROUTES.TRAVEL_WORKSPACE_ADDRESS.getRoute(domain, policyID, Navigation.getActiveRoute())); + Navigation.navigate(createDynamicRoute(DYNAMIC_ROUTES.TRAVEL_WORKSPACE_ADDRESS.getRoute(domain, policyID))); } else { cleanupTravelProvisioningSession(); Navigation.navigate(createDynamicRoute(DYNAMIC_ROUTES.TRAVEL_TCS.getRoute(domain, policyID))); diff --git a/src/pages/Travel/DynamicTravelUpgrade.tsx b/src/pages/Travel/DynamicTravelUpgrade.tsx index 8969f7ff7f03..80bfde1f3a9b 100644 --- a/src/pages/Travel/DynamicTravelUpgrade.tsx +++ b/src/pages/Travel/DynamicTravelUpgrade.tsx @@ -8,13 +8,14 @@ import useLocalize from '@hooks/useLocalize'; import useNetwork from '@hooks/useNetwork'; import useOnyx from '@hooks/useOnyx'; import useThemeStyles from '@hooks/useThemeStyles'; +import createDynamicRoute from '@libs/Navigation/helpers/dynamicRoutesUtils/createDynamicRoute'; import Navigation from '@libs/Navigation/Navigation'; import {getActivePolicies, isPaidGroupPolicy} from '@libs/PolicyUtils'; import UpgradeConfirmation from '@pages/workspace/upgrade/UpgradeConfirmation'; import UpgradeIntro from '@pages/workspace/upgrade/UpgradeIntro'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; -import ROUTES, {DYNAMIC_ROUTES} from '@src/ROUTES'; +import {DYNAMIC_ROUTES} from '@src/ROUTES'; function DynamicTravelUpgrade() { const styles = useThemeStyles(); @@ -29,7 +30,7 @@ function DynamicTravelUpgrade() { const isUpgraded = groupPaidPolicies.length > 0; const openWorkspaceConfirmation = () => { - Navigation.navigate(ROUTES.TRAVEL_WORKSPACE_CONFIRMATION.getRoute(Navigation.getActiveRoute())); + Navigation.navigate(createDynamicRoute(DYNAMIC_ROUTES.TRAVEL_WORKSPACE_CONFIRMATION.path)); }; return ( diff --git a/src/pages/Travel/TripDetailsPage.tsx b/src/pages/Travel/DynamicTripDetailsPage.tsx similarity index 93% rename from src/pages/Travel/TripDetailsPage.tsx rename to src/pages/Travel/DynamicTripDetailsPage.tsx index af373c201276..f987b947eb5d 100644 --- a/src/pages/Travel/TripDetailsPage.tsx +++ b/src/pages/Travel/DynamicTripDetailsPage.tsx @@ -6,6 +6,7 @@ import HeaderWithBackButton from '@components/HeaderWithBackButton'; import MenuItem from '@components/MenuItem'; import ScreenWrapper from '@components/ScreenWrapper'; import ScrollView from '@components/ScrollView'; +import useDynamicBackPath from '@hooks/useDynamicBackPath'; import {useMemoizedLazyExpensifyIcons} from '@hooks/useLazyAsset'; import useLocalize from '@hooks/useLocalize'; import useNetwork from '@hooks/useNetwork'; @@ -15,6 +16,7 @@ import useStyleUtils from '@hooks/useStyleUtils'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; import getNonEmptyStringOnyxID from '@libs/getNonEmptyStringOnyxID'; +import Navigation from '@libs/Navigation/Navigation'; import type {TravelNavigatorParamList} from '@libs/Navigation/types'; import {getTripIDFromTransactionParentReportID} from '@libs/ReportUtils'; import {formatCancelledDescription, getReservationDetailsFromSequence, getReservationsFromTripReport} from '@libs/TripReservationUtils'; @@ -22,6 +24,7 @@ import {openTravelDotLink} from '@userActions/Link'; import CONFIG from '@src/CONFIG'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; +import {DYNAMIC_ROUTES} from '@src/ROUTES'; import type SCREENS from '@src/SCREENS'; import type {PersonalDetailsList} from '@src/types/onyx'; import type {Reservation} from '@src/types/onyx/Transaction'; @@ -34,9 +37,9 @@ function pickTravelerPersonalDetails(personalDetails: OnyxEntry personalDetail?.login === reservation?.travelerPersonalInfo?.email); } -type TripDetailsPageProps = StackScreenProps; +type DynamicTripDetailsPageProps = StackScreenProps; -function TripDetailsPage({route}: TripDetailsPageProps) { +function DynamicTripDetailsPage({route}: DynamicTripDetailsPageProps) { const icons = useMemoizedLazyExpensifyIcons([ 'NewWindow', 'Plane', @@ -58,6 +61,7 @@ function TripDetailsPage({route}: TripDetailsPageProps) { const {isBetaEnabled} = usePermissions(); const isBlockedFromSpotnanaTravel = isBetaEnabled(CONST.BETAS.PREVENT_SPOTNANA_TRAVEL); const {isOffline} = useNetwork(); + const backPath = useDynamicBackPath(DYNAMIC_ROUTES.TRAVEL_TRIP_DETAILS.path); const [isModifyTripLoading, setIsModifyTripLoading] = useState(false); const [isTripSupportLoading, setIsTripSupportLoading] = useState(false); @@ -83,7 +87,7 @@ function TripDetailsPage({route}: TripDetailsPageProps) { includeSafeAreaPaddingBottom shouldEnablePickerAvoiding={false} shouldEnableMaxHeight - testID="TripDetailsPage" + testID="DynamicTripDetailsPage" shouldShowOfflineIndicatorInWideScreen > Navigation.goBack(backPath)} /> {!!reservation && reservationType === CONST.RESERVATION_TYPE.FLIGHT && ( @@ -164,4 +169,4 @@ function TripDetailsPage({route}: TripDetailsPageProps) { ); } -export default TripDetailsPage; +export default DynamicTripDetailsPage; diff --git a/src/pages/Travel/TripSummaryPage.tsx b/src/pages/Travel/DynamicTripSummaryPage.tsx similarity index 80% rename from src/pages/Travel/TripSummaryPage.tsx rename to src/pages/Travel/DynamicTripSummaryPage.tsx index 3f3ae47cffdc..e5904a56ab92 100644 --- a/src/pages/Travel/TripSummaryPage.tsx +++ b/src/pages/Travel/DynamicTripSummaryPage.tsx @@ -6,19 +6,23 @@ import OfflineWithFeedback from '@components/OfflineWithFeedback'; import {ReservationView} from '@components/ReportActionItem/TripDetailsView'; import ScreenWrapper from '@components/ScreenWrapper'; import ScrollView from '@components/ScrollView'; +import useDynamicBackPath from '@hooks/useDynamicBackPath'; import useLocalize from '@hooks/useLocalize'; import useOnyx from '@hooks/useOnyx'; import getNonEmptyStringOnyxID from '@libs/getNonEmptyStringOnyxID'; +import Navigation from '@libs/Navigation/Navigation'; import type {TravelNavigatorParamList} from '@libs/Navigation/types'; import CONFIG from '@src/CONFIG'; import * as TripReservationUtils from '@src/libs/TripReservationUtils'; import ONYXKEYS from '@src/ONYXKEYS'; +import {DYNAMIC_ROUTES} from '@src/ROUTES'; import type SCREENS from '@src/SCREENS'; -type TripSummaryPageProps = StackScreenProps; +type DynamicTripSummaryPageProps = StackScreenProps; -function TripSummaryPage({route}: TripSummaryPageProps) { +function DynamicTripSummaryPage({route}: DynamicTripSummaryPageProps) { const {translate} = useLocalize(); + const backPath = useDynamicBackPath(DYNAMIC_ROUTES.TRAVEL_TRIP_SUMMARY.path); const [report] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${route.params.reportID}`); const [transaction] = useOnyx(`${ONYXKEYS.COLLECTION.TRANSACTION}${getNonEmptyStringOnyxID(route.params.transactionID)}`); @@ -29,7 +33,7 @@ function TripSummaryPage({route}: TripSummaryPageProps) { includeSafeAreaPaddingBottom={false} shouldEnablePickerAvoiding={false} shouldEnableMaxHeight - testID="TripSummaryPage" + testID="DynamicTripSummaryPage" shouldShowOfflineIndicatorInWideScreen > Navigation.goBack(backPath)} /> {reservationsData.map(({reservation, transactionID, sequenceIndex, isCancelled}) => { @@ -60,4 +65,4 @@ function TripSummaryPage({route}: TripSummaryPageProps) { ); } -export default TripSummaryPage; +export default DynamicTripSummaryPage; diff --git a/src/pages/Travel/VerifyAccountPage.tsx b/src/pages/Travel/DynamicVerifyAccountPage.tsx similarity index 77% rename from src/pages/Travel/VerifyAccountPage.tsx rename to src/pages/Travel/DynamicVerifyAccountPage.tsx index 8d39b594decf..c19eb61896f8 100644 --- a/src/pages/Travel/VerifyAccountPage.tsx +++ b/src/pages/Travel/DynamicVerifyAccountPage.tsx @@ -1,5 +1,6 @@ import type {StackScreenProps} from '@react-navigation/stack'; import React, {useCallback, useEffect} from 'react'; +import useDynamicBackPath from '@hooks/useDynamicBackPath'; import useOnyx from '@hooks/useOnyx'; import usePermissions from '@hooks/usePermissions'; import {requestTravelAccess, setTravelProvisioningNextStep} from '@libs/actions/Travel'; @@ -12,10 +13,11 @@ import ONYXKEYS from '@src/ONYXKEYS'; import {DYNAMIC_ROUTES} from '@src/ROUTES'; import type SCREENS from '@src/SCREENS'; -type VerifyAccountPageProps = StackScreenProps; +type DynamicVerifyAccountPageProps = StackScreenProps; -function VerifyAccountPage({route}: VerifyAccountPageProps) { - const {domain, backTo, policyID} = route.params; +function DynamicVerifyAccountPage({route}: DynamicVerifyAccountPageProps) { + const {domain, policyID} = route.params; + const backPath = useDynamicBackPath(DYNAMIC_ROUTES.TRAVEL_VERIFY_ACCOUNT.path); const [travelProvisioning] = useOnyx(ONYXKEYS.TRAVEL_PROVISIONING); const {isBetaEnabled} = usePermissions(); @@ -36,12 +38,12 @@ function VerifyAccountPage({route}: VerifyAccountPageProps) { }, []); const handleClose = useCallback(() => { - Navigation.goBack(backTo); - }, [backTo]); + Navigation.goBack(backPath); + }, [backPath]); return ( ; +type DynamicWorkspaceAddressForTravelPageProps = PlatformStackScreenProps; -function WorkspaceAddressForTravelPage({route}: WorkspaceAddressForTravelPageProps) { +function DynamicWorkspaceAddressForTravelPage({route}: DynamicWorkspaceAddressForTravelPageProps) { const {translate} = useLocalize(); + const backPath = useDynamicBackPath(DYNAMIC_ROUTES.TRAVEL_WORKSPACE_ADDRESS.path); const {policyID} = route.params; const policy = usePolicy(policyID); const [isUserValidated] = useOnyx(ONYXKEYS.ACCOUNT, {selector: isUserValidatedSelector}); @@ -33,9 +36,8 @@ function WorkspaceAddressForTravelPage({route}: WorkspaceAddressForTravelPagePro // Always validate OTP first before allowing address submission if (!isUserValidated) { // After OTP validation, redirect back to this address page - const currentRoute = ROUTES.TRAVEL_WORKSPACE_ADDRESS.getRoute(route.params.domain, policyID, route.params.backTo); - setTravelProvisioningNextStep(currentRoute); - Navigation.navigate(ROUTES.TRAVEL_VERIFY_ACCOUNT.getRoute(route.params.domain, policyID)); + setTravelProvisioningNextStep(Navigation.getActiveRoute() as Route); + Navigation.navigate(createDynamicRoute(DYNAMIC_ROUTES.TRAVEL_VERIFY_ACCOUNT.getRoute(route.params.domain, policyID))); return; } @@ -56,10 +58,10 @@ function WorkspaceAddressForTravelPage({route}: WorkspaceAddressForTravelPagePro isLoadingApp={false} updateAddress={updatePolicyAddress} title={translate('common.companyAddress')} - backTo={route.params.backTo} + backTo={backPath} /> ); } -export default WorkspaceAddressForTravelPage; +export default DynamicWorkspaceAddressForTravelPage; diff --git a/src/pages/Travel/WorkspaceConfirmationForTravelPage.tsx b/src/pages/Travel/DynamicWorkspaceConfirmationForTravelPage.tsx similarity index 76% rename from src/pages/Travel/WorkspaceConfirmationForTravelPage.tsx rename to src/pages/Travel/DynamicWorkspaceConfirmationForTravelPage.tsx index e8a5acfd9c57..3575b8c2470c 100644 --- a/src/pages/Travel/WorkspaceConfirmationForTravelPage.tsx +++ b/src/pages/Travel/DynamicWorkspaceConfirmationForTravelPage.tsx @@ -1,4 +1,3 @@ -import type {StackScreenProps} from '@react-navigation/stack'; import {hasSeenTourSelector} from '@selectors/Onboarding'; import React from 'react'; import ScreenWrapper from '@components/ScreenWrapper'; @@ -6,20 +5,17 @@ import WorkspaceConfirmationForm from '@components/WorkspaceConfirmationForm'; import type {WorkspaceConfirmationSubmitFunctionParams} from '@components/WorkspaceConfirmationForm'; import useActivePolicy from '@hooks/useActivePolicy'; import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails'; +import useDynamicBackPath from '@hooks/useDynamicBackPath'; import useHasActiveAdminPolicies from '@hooks/useHasActiveAdminPolicies'; import useOnyx from '@hooks/useOnyx'; import {createDraftWorkspace, createWorkspace} from '@libs/actions/Policy/Policy'; -import createDynamicRoute from '@libs/Navigation/helpers/dynamicRoutesUtils/createDynamicRoute'; import Navigation from '@libs/Navigation/Navigation'; -import type {TravelNavigatorParamList} from '@libs/Navigation/types'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; -import ROUTES, {DYNAMIC_ROUTES} from '@src/ROUTES'; -import type SCREENS from '@src/SCREENS'; +import {DYNAMIC_ROUTES} from '@src/ROUTES'; -type WorkspaceConfirmationForTravelPageProps = StackScreenProps; - -function WorkspaceConfirmationForTravelPage({route}: WorkspaceConfirmationForTravelPageProps) { +function DynamicWorkspaceConfirmationForTravelPage() { + const backPath = useDynamicBackPath(DYNAMIC_ROUTES.TRAVEL_WORKSPACE_CONFIRMATION.path); const [introSelected] = useOnyx(ONYXKEYS.NVP_INTRO_SELECTED); const [betas] = useOnyx(ONYXKEYS.BETAS); const [isSelfTourViewed] = useOnyx(ONYXKEYS.NVP_ONBOARDING, {selector: hasSeenTourSelector}); @@ -29,7 +25,7 @@ function WorkspaceConfirmationForTravelPage({route}: WorkspaceConfirmationForTra const hasActiveAdminPolicies = useHasActiveAdminPolicies(); const goBack = () => { - Navigation.goBack(route.params?.backTo ?? createDynamicRoute(DYNAMIC_ROUTES.TRAVEL_UPGRADE.path, ROUTES.TRAVEL_MY_TRIPS.route)); + Navigation.goBack(backPath); }; const onSubmit = (params: WorkspaceConfirmationSubmitFunctionParams) => { @@ -62,7 +58,7 @@ function WorkspaceConfirmationForTravelPage({route}: WorkspaceConfirmationForTra return ( { - Navigation.navigate(ROUTES.TRAVEL_TRIP_DETAILS.getRoute(reportID, transactionID, reservation.reservationID, sequenceIndex)); + if (!reportID || !transactionID || !reservation.reservationID) { + return; + } + Navigation.navigate( + createDynamicRoute(DYNAMIC_ROUTES.TRAVEL_TRIP_DETAILS.getRoute(transactionID, String(reservation.reservationID), sequenceIndex), ROUTES.REPORT_WITH_ID.getRoute(reportID)), + ); }; return (