Skip to content
Closed
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
10 changes: 5 additions & 5 deletions config/eslint/eslint.seatbelt.tsv
Original file line number Diff line number Diff line change
Expand Up @@ -1165,13 +1165,13 @@
"../../src/pages/TransactionDuplicate/Confirmation.tsx" "react-hooks/refs" 12
"../../src/pages/TransactionDuplicate/DuplicateTransactionItem.tsx" "@typescript-eslint/no-unsafe-type-assertion" 2
"../../src/pages/TransactionDuplicate/Review.tsx" "no-restricted-imports" 1
"../../src/pages/TransactionMerge/ConfirmationPage.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1
"../../src/pages/TransactionMerge/ConfirmationPage.tsx" "no-restricted-imports" 1
"../../src/pages/TransactionMerge/DetailsReviewPage.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1
"../../src/pages/TransactionMerge/DetailsReviewPage.tsx" "no-restricted-imports" 1
"../../src/pages/TransactionMerge/DynamicConfirmationPage.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1
"../../src/pages/TransactionMerge/DynamicConfirmationPage.tsx" "no-restricted-imports" 1
"../../src/pages/TransactionMerge/DynamicDetailsReviewPage.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1
"../../src/pages/TransactionMerge/DynamicDetailsReviewPage.tsx" "no-restricted-imports" 1
"../../src/pages/TransactionMerge/MergeTransactionItem.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1
"../../src/pages/TransactionMerge/MergeTransactionsListContent.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1
"../../src/pages/TransactionMerge/ReceiptReviewPage.tsx" "no-restricted-imports" 1
"../../src/pages/TransactionMerge/DynamicReceiptReviewPage.tsx" "no-restricted-imports" 1
"../../src/pages/TransactionMerge/TransactionMergeReceipts.tsx" "no-restricted-imports" 1
"../../src/pages/Travel/DynamicDomainPermissionInfoPage.tsx" "no-restricted-imports" 1
"../../src/pages/Travel/DynamicDomainSelectorPage.tsx" "no-restricted-imports" 1
Expand Down
56 changes: 24 additions & 32 deletions src/ROUTES.ts
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,30 @@ const DYNAMIC_ROUTES = {
getRoute: (isMovingExpenses?: boolean) => `new-report-workspace-selection${isMovingExpenses ? '?isMovingExpenses=true' : ''}` as const,
queryParams: ['isMovingExpenses'],
},
MERGE_TRANSACTION_LIST_PAGE: {
path: 'merge/:transactionID',
entryScreens: [SCREENS.REPORT, SCREENS.RIGHT_MODAL.SEARCH_REPORT, SCREENS.RIGHT_MODAL.EXPENSE_REPORT, SCREENS.RIGHT_MODAL.SEARCH_MONEY_REQUEST_REPORT, SCREENS.SEARCH.ROOT],
getRoute: (transactionID: string, isOnSearch?: boolean) => getUrlWithParams(`merge/${transactionID}`, {isOnSearch: isOnSearch ? 'true' : undefined}),
queryParams: ['isOnSearch'],
},
MERGE_TRANSACTION_RECEIPT_PAGE: {
path: 'merge/:transactionID/receipt',
entryScreens: [SCREENS.REPORT, SCREENS.RIGHT_MODAL.SEARCH_REPORT, SCREENS.RIGHT_MODAL.EXPENSE_REPORT, SCREENS.RIGHT_MODAL.SEARCH_MONEY_REQUEST_REPORT, SCREENS.SEARCH.ROOT],
getRoute: (transactionID: string, isOnSearch?: boolean) => getUrlWithParams(`merge/${transactionID}/receipt`, {isOnSearch: isOnSearch ? 'true' : undefined}),
queryParams: ['isOnSearch'],
},
MERGE_TRANSACTION_DETAILS_PAGE: {
path: 'merge/:transactionID/details',
entryScreens: [SCREENS.REPORT, SCREENS.RIGHT_MODAL.SEARCH_REPORT, SCREENS.RIGHT_MODAL.EXPENSE_REPORT, SCREENS.RIGHT_MODAL.SEARCH_MONEY_REQUEST_REPORT, SCREENS.SEARCH.ROOT],
getRoute: (transactionID: string, isOnSearch?: boolean) => getUrlWithParams(`merge/${transactionID}/details`, {isOnSearch: isOnSearch ? 'true' : undefined}),
queryParams: ['isOnSearch'],
},
MERGE_TRANSACTION_CONFIRMATION_PAGE: {
path: 'merge/:transactionID/confirmation',
entryScreens: [SCREENS.REPORT, SCREENS.RIGHT_MODAL.SEARCH_REPORT, SCREENS.RIGHT_MODAL.EXPENSE_REPORT, SCREENS.RIGHT_MODAL.SEARCH_MONEY_REQUEST_REPORT, SCREENS.SEARCH.ROOT],
getRoute: (transactionID: string, isOnSearch?: boolean) => getUrlWithParams(`merge/${transactionID}/confirmation`, {isOnSearch: isOnSearch ? 'true' : undefined}),
queryParams: ['isOnSearch'],
},
NETSUITE_AUTO_SYNC: {
path: 'netsuite-autosync',
entryScreens: [SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_ADVANCED, SCREENS.WORKSPACE.ACCOUNTING.CARD_RECONCILIATION],
Expand Down Expand Up @@ -3519,38 +3543,6 @@ const ROUTES = {

getRoute: (threadReportID: string, backTo?: string) => getUrlWithBackToParam(`r/${threadReportID}/duplicates/confirm` as const, backTo),
},
MERGE_TRANSACTION_LIST_PAGE: {
route: 'merge/:transactionID',

getRoute: (transactionID: string, backTo: string, isOnSearch = false) => {
const url = getUrlWithBackToParam(`merge/${transactionID}` as const, backTo);
return isOnSearch ? (`${url}&isOnSearch=true` as const) : url;
},
},
MERGE_TRANSACTION_RECEIPT_PAGE: {
route: 'merge/:transactionID/receipt',

getRoute: (transactionID: string, backTo: string, isOnSearch = false) => {
const url = getUrlWithBackToParam(`merge/${transactionID}/receipt` as const, backTo);
return isOnSearch ? (`${url}&isOnSearch=true` as const) : url;
},
},
MERGE_TRANSACTION_DETAILS_PAGE: {
route: 'merge/:transactionID/details',

getRoute: (transactionID: string, backTo: string, isOnSearch = false) => {
const url = getUrlWithBackToParam(`merge/${transactionID}/details` as const, backTo);
return isOnSearch ? (`${url}&isOnSearch=true` as const) : url;
},
},
MERGE_TRANSACTION_CONFIRMATION_PAGE: {
route: 'merge/:transactionID/confirmation',

getRoute: (transactionID: string, backTo: string, isOnSearch = false) => {
const url = getUrlWithBackToParam(`merge/${transactionID}/confirmation` as const, backTo);
return isOnSearch ? (`${url}&isOnSearch=true` as const) : url;
},
},
POLICY_ACCOUNTING_XERO_SETUP: {
route: 'workspaces/:policyID/accounting/xero/setup',
getRoute: (policyID: string) => `workspaces/${policyID}/accounting/xero/setup` as const,
Expand Down
8 changes: 4 additions & 4 deletions src/SCREENS.ts
Original file line number Diff line number Diff line change
Expand Up @@ -393,10 +393,10 @@ const SCREENS = {
},

MERGE_TRANSACTION: {
LIST_PAGE: 'Merge_Transaction_List_Page',
RECEIPT_PAGE: 'Merge_Transaction_Receipt_Page',
DETAILS_PAGE: 'Merge_Transaction_Details_Page',
CONFIRMATION_PAGE: 'Merge_Transaction_Confirmation_Page',
DYNAMIC_LIST_PAGE: 'Dynamic_Merge_Transaction_List_Page',
DYNAMIC_RECEIPT_PAGE: 'Dynamic_Merge_Transaction_Receipt_Page',
DYNAMIC_DETAILS_PAGE: 'Dynamic_Merge_Transaction_Details_Page',
DYNAMIC_CONFIRMATION_PAGE: 'Dynamic_Merge_Transaction_Confirmation_Page',
},

IOU_SEND: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1152,10 +1152,10 @@ const TransactionDuplicateStackNavigator = createModalStackNavigator<Transaction
});

const MergeTransactionStackNavigator = createModalStackNavigator<MergeTransactionNavigatorParamList>({
[SCREENS.MERGE_TRANSACTION.LIST_PAGE]: () => require<ReactComponentModule>('../../../../pages/TransactionMerge/MergeTransactionsListPage').default,
[SCREENS.MERGE_TRANSACTION.RECEIPT_PAGE]: () => require<ReactComponentModule>('../../../../pages/TransactionMerge/ReceiptReviewPage').default,
[SCREENS.MERGE_TRANSACTION.DETAILS_PAGE]: () => require<ReactComponentModule>('../../../../pages/TransactionMerge/DetailsReviewPage').default,
[SCREENS.MERGE_TRANSACTION.CONFIRMATION_PAGE]: () => require<ReactComponentModule>('../../../../pages/TransactionMerge/ConfirmationPage').default,
[SCREENS.MERGE_TRANSACTION.DYNAMIC_LIST_PAGE]: () => require<ReactComponentModule>('../../../../pages/TransactionMerge/DynamicMergeTransactionsListPage').default,
[SCREENS.MERGE_TRANSACTION.DYNAMIC_RECEIPT_PAGE]: () => require<ReactComponentModule>('../../../../pages/TransactionMerge/DynamicReceiptReviewPage').default,
[SCREENS.MERGE_TRANSACTION.DYNAMIC_DETAILS_PAGE]: () => require<ReactComponentModule>('../../../../pages/TransactionMerge/DynamicDetailsReviewPage').default,
[SCREENS.MERGE_TRANSACTION.DYNAMIC_CONFIRMATION_PAGE]: () => require<ReactComponentModule>('../../../../pages/TransactionMerge/DynamicConfirmationPage').default,
});

const SearchReportActionsModalStackNavigator = createModalStackNavigator<SearchReportActionsParamList>({
Expand Down
8 changes: 4 additions & 4 deletions src/libs/Navigation/linkingConfig/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1859,10 +1859,10 @@ const config: LinkingOptions<RootNavigatorParamList>['config'] = {
},
[SCREENS.RIGHT_MODAL.MERGE_TRANSACTION]: {
screens: {
[SCREENS.MERGE_TRANSACTION.LIST_PAGE]: ROUTES.MERGE_TRANSACTION_LIST_PAGE.route,
[SCREENS.MERGE_TRANSACTION.RECEIPT_PAGE]: ROUTES.MERGE_TRANSACTION_RECEIPT_PAGE.route,
[SCREENS.MERGE_TRANSACTION.DETAILS_PAGE]: ROUTES.MERGE_TRANSACTION_DETAILS_PAGE.route,
[SCREENS.MERGE_TRANSACTION.CONFIRMATION_PAGE]: ROUTES.MERGE_TRANSACTION_CONFIRMATION_PAGE.route,
[SCREENS.MERGE_TRANSACTION.DYNAMIC_LIST_PAGE]: DYNAMIC_ROUTES.MERGE_TRANSACTION_LIST_PAGE.path,
[SCREENS.MERGE_TRANSACTION.DYNAMIC_RECEIPT_PAGE]: DYNAMIC_ROUTES.MERGE_TRANSACTION_RECEIPT_PAGE.path,
[SCREENS.MERGE_TRANSACTION.DYNAMIC_DETAILS_PAGE]: DYNAMIC_ROUTES.MERGE_TRANSACTION_DETAILS_PAGE.path,
[SCREENS.MERGE_TRANSACTION.DYNAMIC_CONFIRMATION_PAGE]: DYNAMIC_ROUTES.MERGE_TRANSACTION_CONFIRMATION_PAGE.path,
},
},
[SCREENS.RIGHT_MODAL.SPLIT_DETAILS]: {
Expand Down
16 changes: 4 additions & 12 deletions src/libs/Navigation/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2549,28 +2549,20 @@ type TransactionDuplicateNavigatorParamList = {
};

type MergeTransactionNavigatorParamList = {
[SCREENS.MERGE_TRANSACTION.LIST_PAGE]: {
[SCREENS.MERGE_TRANSACTION.DYNAMIC_LIST_PAGE]: {
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?: Routes;
isOnSearch?: boolean;
};
[SCREENS.MERGE_TRANSACTION.RECEIPT_PAGE]: {
[SCREENS.MERGE_TRANSACTION.DYNAMIC_RECEIPT_PAGE]: {
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?: Routes;
isOnSearch?: boolean;
};
[SCREENS.MERGE_TRANSACTION.DETAILS_PAGE]: {
[SCREENS.MERGE_TRANSACTION.DYNAMIC_DETAILS_PAGE]: {
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?: Routes;
isOnSearch?: boolean;
};
[SCREENS.MERGE_TRANSACTION.CONFIRMATION_PAGE]: {
[SCREENS.MERGE_TRANSACTION.DYNAMIC_CONFIRMATION_PAGE]: {
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?: Routes;
isOnSearch?: boolean;
};
};
Expand Down
24 changes: 19 additions & 5 deletions src/libs/actions/MergeTransaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
shouldNavigateToReceiptReview,
} from '@libs/MergeTransactionUtils';
import type {MergeFieldKey, MergeTransactionUpdateValues} from '@libs/MergeTransactionUtils';
import createDynamicRoute from '@libs/Navigation/helpers/dynamicRoutesUtils/createDynamicRoute';
import Navigation from '@libs/Navigation/Navigation';
import {isPaidGroupPolicy, isPolicyAdmin} from '@libs/PolicyUtils';
import {getIOUActionForReportID, getReportAction, getTrackExpenseActionableWhisper} from '@libs/ReportActionsUtils';
Expand All @@ -30,7 +31,7 @@ import {
import CONST from '@src/CONST';
import {isDistanceRequest, isTransactionPendingDelete} from '@src/libs/TransactionUtils';
import ONYXKEYS from '@src/ONYXKEYS';
import ROUTES from '@src/ROUTES';
import {DYNAMIC_ROUTES} from '@src/ROUTES';
import type {CardList, MergeTransaction, Policy, PolicyCategories, PolicyTagLists, Report, ReportNextStepDeprecated, Transaction, TransactionViolations} from '@src/types/onyx';

import type {OnyxCollection, OnyxEntry, OnyxMergeInput, OnyxUpdate} from 'react-native-onyx';
Expand Down Expand Up @@ -68,16 +69,22 @@ function setupMergeTransactionDataAndNavigate(
isSelectingSourceTransaction?: boolean,
isOnSearch?: boolean,
policies?: Array<OnyxEntry<Policy>>,
basePath?: string,
) {
if (!transactions.length || transactions.length > 2) {
return;
}

// The dynamic merge routes are appended to the screen the flow started from. When advancing between steps
// (e.g. from the list page after selecting a source transaction) the caller passes the base path so the
// suffix isn't appended to the current merge URL. Otherwise fall back to the active route.
const base = basePath ?? Navigation.getActiveRoute();

if (transactions.length === 1) {
const transaction = transactions.at(0);
if (transaction) {
setupMergeTransactionData(navigationTransactionID, {targetTransactionID: transaction.transactionID});
Navigation.navigate(ROUTES.MERGE_TRANSACTION_LIST_PAGE.getRoute(transaction.transactionID, Navigation.getActiveRoute(), isOnSearch));
Navigation.navigate(createDynamicRoute(DYNAMIC_ROUTES.MERGE_TRANSACTION_LIST_PAGE.getRoute(transaction.transactionID, isOnSearch), base));
return;
}
}
Expand All @@ -98,9 +105,16 @@ function setupMergeTransactionDataAndNavigate(
} else {
setupMergeTransactionData(navigationTransactionID, setupData);
}

// When advancing from the list page (after selecting a source), the merge RHP modal is already open, so we must
// replace the current dynamic screen rather than pushing a new one. Pushing a second dynamic merge screen makes
// getPathFromState concatenate both suffixes into an invalid doubled URL (e.g. .../merge/ID/merge/ID/receipt).
// Fresh entries (bulk selection) open the modal normally.
const navigationOptions = isSelectingSourceTransaction ? {forceReplace: true} : undefined;

if (shouldNavigateToReceiptReview([targetTransaction, sourceTransaction])) {
// Navigate to the receipt review page if both transactions have a receipt
Navigation.navigate(ROUTES.MERGE_TRANSACTION_RECEIPT_PAGE.getRoute(navigationTransactionID, Navigation.getActiveRoute(), isOnSearch));
Navigation.navigate(createDynamicRoute(DYNAMIC_ROUTES.MERGE_TRANSACTION_RECEIPT_PAGE.getRoute(navigationTransactionID, isOnSearch), base), navigationOptions);
} else {
const receipt = targetTransaction.receipt?.receiptID ? targetTransaction.receipt : sourceTransaction.receipt;
if (receipt) {
Expand All @@ -120,11 +134,11 @@ function setupMergeTransactionDataAndNavigate(
if (!conflictFields.length) {
// If there are no conflict fields, we should set mergeable data and navigate to the confirmation page
setMergeTransactionKey(navigationTransactionID, mergeableData);
Navigation.navigate(ROUTES.MERGE_TRANSACTION_CONFIRMATION_PAGE.getRoute(navigationTransactionID, Navigation.getActiveRoute(), isOnSearch));
Navigation.navigate(createDynamicRoute(DYNAMIC_ROUTES.MERGE_TRANSACTION_CONFIRMATION_PAGE.getRoute(navigationTransactionID, isOnSearch), base), navigationOptions);
return;
}

Navigation.navigate(ROUTES.MERGE_TRANSACTION_DETAILS_PAGE.getRoute(navigationTransactionID, Navigation.getActiveRoute(), isOnSearch));
Navigation.navigate(createDynamicRoute(DYNAMIC_ROUTES.MERGE_TRANSACTION_DETAILS_PAGE.getRoute(navigationTransactionID, isOnSearch), base), navigationOptions);
}
}

Expand Down
Loading
Loading