diff --git a/src/components/MoneyReportHeader.tsx b/src/components/MoneyReportHeader.tsx index 23c508db316fd..bf79e8b41abbb 100644 --- a/src/components/MoneyReportHeader.tsx +++ b/src/components/MoneyReportHeader.tsx @@ -87,6 +87,7 @@ import { isExported as isExportedUtils, isInvoiceReport as isInvoiceReportUtil, isOpenExpenseReport, + isOpenReport, isProcessingReport, isReportOwner, navigateOnDeleteExpense, @@ -97,6 +98,7 @@ import { import {shouldRestrictUserBillableActions} from '@libs/SubscriptionUtils'; import { allHavePendingRTERViolation, + getChildTransactions, getOriginalTransactionWithSplitInfo, hasCustomUnitOutOfPolicyViolation as hasCustomUnitOutOfPolicyViolationTransactionUtils, hasDuplicateTransactions, @@ -367,6 +369,17 @@ function MoneyReportHeader({ const theme = useTheme(); const {isOffline} = useNetwork(); const {isExpenseSplit} = getOriginalTransactionWithSplitInfo(transaction, originalTransaction); + const [allTransactions] = useOnyx(ONYXKEYS.COLLECTION.TRANSACTION); + const [allReports] = useOnyx(ONYXKEYS.COLLECTION.REPORT); + const hasMultipleSplits = useMemo(() => { + if (!transaction?.comment?.originalTransactionID) { + return false; + } + const children = getChildTransactions(allTransactions, allReports, transaction.comment.originalTransactionID); + return children.length > 1; + }, [allTransactions, allReports, transaction?.comment?.originalTransactionID]); + const isReportOpen = isOpenReport(moneyRequestReport); + const shouldShowSplitIndicator = isExpenseSplit && (hasMultipleSplits || isReportOpen); const [policies] = useOnyx(ONYXKEYS.COLLECTION.POLICY); const [isDuplicateActive, temporarilyDisableDuplicateAction] = useThrottledButtonState(); @@ -1409,7 +1422,7 @@ function MoneyReportHeader({ }, }, [CONST.REPORT.SECONDARY_ACTIONS.SPLIT]: { - text: isExpenseSplit ? translate('iou.editSplits') : translate('iou.split'), + text: shouldShowSplitIndicator ? translate('iou.editSplits') : translate('iou.split'), icon: expensifyIcons.ArrowSplit, value: CONST.REPORT.SECONDARY_ACTIONS.SPLIT, sentryLabel: CONST.SENTRY_LABEL.MORE_MENU.SPLIT, @@ -1776,7 +1789,7 @@ function MoneyReportHeader({ } return option; }); - }, [originalSelectedTransactionsOptions, showDeleteModal, dismissedRejectUseExplanation]); + }, [originalSelectedTransactionsOptions, showDeleteModal, dismissedRejectUseExplanation, isDelegateAccessRestricted, showDelegateNoAccessModal]); const shouldShowSelectedTransactionsButton = !!selectedTransactionsOptions.length && !transactionThreadReportID; diff --git a/src/components/MoneyRequestHeader.tsx b/src/components/MoneyRequestHeader.tsx index e4e908c72239e..ef18e83b7db17 100644 --- a/src/components/MoneyRequestHeader.tsx +++ b/src/components/MoneyRequestHeader.tsx @@ -43,6 +43,7 @@ import { getPolicyExpenseChat, isCurrentUserSubmitter, isDM, + isOpenReport, isSelfDM, navigateToDetailsPage, rejectMoneyRequestReason, @@ -51,6 +52,7 @@ import {getReviewNavigationRoute} from '@libs/TransactionPreviewUtils'; import { getOriginalTransactionWithSplitInfo, hasCustomUnitOutOfPolicyViolation as hasCustomUnitOutOfPolicyViolationTransactionUtils, + hasMultipleSplitChildren, hasPendingRTERViolation as hasPendingRTERViolationTransactionUtils, isDuplicate as isDuplicateTransactionUtils, isExpensifyCardTransaction, @@ -163,6 +165,14 @@ function MoneyRequestHeader({report, parentReportAction, policy, onBackButtonPre const {currentSearchHash} = useSearchStateContext(); const {removeTransaction} = useSearchActionsContext(); const {isExpenseSplit} = getOriginalTransactionWithSplitInfo(transaction, originalTransaction); + const [allTransactions] = useOnyx(ONYXKEYS.COLLECTION.TRANSACTION); + const [allReports] = useOnyx(ONYXKEYS.COLLECTION.REPORT); + const hasMultipleSplits = useMemo( + () => hasMultipleSplitChildren(allTransactions, allReports, transaction?.comment?.originalTransactionID), + [allTransactions, allReports, transaction?.comment?.originalTransactionID], + ); + const isReportOpen = isOpenReport(parentReport); + const shouldShowSplitIndicator = isExpenseSplit && (hasMultipleSplits || isReportOpen); const [cardList] = useOnyx(ONYXKEYS.CARD_LIST); const [transactionDrafts] = useOnyx(ONYXKEYS.COLLECTION.TRANSACTION_DRAFT, {selector: validTransactionDraftsSelector}); const draftTransactionIDs = Object.keys(transactionDrafts ?? {}); @@ -464,7 +474,7 @@ function MoneyRequestHeader({report, parentReportAction, policy, onBackButtonPre }, }, [CONST.REPORT.TRANSACTION_SECONDARY_ACTIONS.SPLIT]: { - text: isExpenseSplit ? translate('iou.editSplits') : translate('iou.split'), + text: shouldShowSplitIndicator ? translate('iou.editSplits') : translate('iou.split'), icon: expensifyIcons.ArrowSplit, value: CONST.REPORT.SECONDARY_ACTIONS.SPLIT, onSelected: () => { diff --git a/src/components/ReportActionItem/MoneyRequestView.tsx b/src/components/ReportActionItem/MoneyRequestView.tsx index 3a1818b29edc4..a1eef161e8860 100644 --- a/src/components/ReportActionItem/MoneyRequestView.tsx +++ b/src/components/ReportActionItem/MoneyRequestView.tsx @@ -1,5 +1,5 @@ import {Str} from 'expensify-common'; -import React, {useCallback, useState} from 'react'; +import React, {useCallback, useMemo, useState} from 'react'; import {View} from 'react-native'; import type {OnyxCollection, OnyxEntry} from 'react-native-onyx'; import type {ValueOf} from 'type-fest'; @@ -69,6 +69,7 @@ import { getTripIDFromTransactionParentReportID, isExpenseReport, isInvoiceReport, + isOpenReport, isPaidGroupPolicy, isReportApproved, isReportInGroupPolicy, @@ -90,6 +91,7 @@ import { getTagForDisplay, getTaxName, hasMissingSmartscanFields, + hasMultipleSplitChildren, hasReservationList, hasRoute as hasRouteTransactionUtils, isFromCreditCardImport as isCardTransactionTransactionUtils, @@ -329,6 +331,14 @@ function MoneyRequestView({ const [originalTransaction] = useOnyx(`${ONYXKEYS.COLLECTION.TRANSACTION}${getNonEmptyStringOnyxID(transaction?.comment?.originalTransactionID)}`); const {isExpenseSplit} = getOriginalTransactionWithSplitInfo(transaction, originalTransaction); const [transactionReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${transaction?.reportID}`); + const [allTransactions] = useOnyx(ONYXKEYS.COLLECTION.TRANSACTION); + const [allReports] = useOnyx(ONYXKEYS.COLLECTION.REPORT); + const hasMultipleSplits = useMemo( + () => hasMultipleSplitChildren(allTransactions, allReports, transaction?.comment?.originalTransactionID), + [allTransactions, allReports, transaction?.comment?.originalTransactionID], + ); + const isReportOpen = isOpenReport(moneyRequestReport); + const shouldShowSplitIndicator = isExpenseSplit && (hasMultipleSplits || isReportOpen); const isSplitAvailable = moneyRequestReport && transaction && @@ -338,7 +348,7 @@ function MoneyRequestView({ const canEditAmount = !isGPSDistanceRequest && isEditable && - (canEditFieldOfMoneyRequest(parentReportAction, CONST.EDIT_REQUEST_FIELD.AMOUNT, undefined, isChatReportArchived) || (isExpenseSplit && isSplitAvailable)); + (canEditFieldOfMoneyRequest(parentReportAction, CONST.EDIT_REQUEST_FIELD.AMOUNT, undefined, isChatReportArchived) || (shouldShowSplitIndicator && isSplitAvailable)); const canEditMerchant = isEditable && canEditFieldOfMoneyRequest(parentReportAction, CONST.EDIT_REQUEST_FIELD.MERCHANT, undefined, isChatReportArchived, undefined, transaction, moneyRequestReport, policy); @@ -505,7 +515,7 @@ function MoneyRequestView({ } else if (shouldShowPaid) { amountDescription += ` ${CONST.DOT_SEPARATOR} ${translate('iou.settledExpensify')}`; } - if (isExpenseSplit) { + if (shouldShowSplitIndicator) { amountDescription += ` ${CONST.DOT_SEPARATOR} ${translate('iou.split')}`; } if (shouldShowConvertedAmount) { @@ -836,7 +846,7 @@ function MoneyRequestView({ return; } - if (isExpenseSplit && isSplitAvailable) { + if (shouldShowSplitIndicator && isSplitAvailable) { initSplitExpense(transaction, policy); return; } diff --git a/src/libs/TransactionUtils/index.ts b/src/libs/TransactionUtils/index.ts index d5b97a98683cd..ec96216d43d7c 100644 --- a/src/libs/TransactionUtils/index.ts +++ b/src/libs/TransactionUtils/index.ts @@ -2702,6 +2702,16 @@ function getChildTransactions(transactions: OnyxCollection, reports }); } +/** + * Checks if a split transaction has more than one child transaction. + */ +function hasMultipleSplitChildren(transactions: OnyxCollection, reports: OnyxCollection, originalTransactionID: string | undefined): boolean { + if (!originalTransactionID) { + return false; + } + return getChildTransactions(transactions, reports, originalTransactionID).length > 1; +} + /** * Determines whether a report should display the expense breakdown. */ @@ -2902,6 +2912,7 @@ export { getTransactionPendingAction, isTransactionPendingDelete, getChildTransactions, + hasMultipleSplitChildren, createUnreportedExpenses, isDemoTransaction, shouldShowViolation, diff --git a/src/libs/actions/SplitExpenses.ts b/src/libs/actions/SplitExpenses.ts index 1864a34cf65c0..d641caa0064cb 100644 --- a/src/libs/actions/SplitExpenses.ts +++ b/src/libs/actions/SplitExpenses.ts @@ -5,7 +5,7 @@ import {calculateAmount} from '@libs/IOUUtils'; import isSearchTopmostFullScreenRoute from '@libs/Navigation/helpers/isSearchTopmostFullScreenRoute'; import Navigation from '@libs/Navigation/Navigation'; import {rand64} from '@libs/NumberUtils'; -import {getTransactionDetails} from '@libs/ReportUtils'; +import {getTransactionDetails, isOpenReport} from '@libs/ReportUtils'; import {buildOptimisticTransaction, getChildTransactions, getOriginalTransactionWithSplitInfo, isDistanceRequest} from '@libs/TransactionUtils'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; @@ -47,9 +47,13 @@ function initSplitExpense(transaction: OnyxEntry, policy?: OnyxEntr const originalTransactionID = transaction?.comment?.originalTransactionID; const originalTransaction = allTransactions?.[`${ONYXKEYS.COLLECTION.TRANSACTION}${originalTransactionID}`]; const {isExpenseSplit} = getOriginalTransactionWithSplitInfo(transaction, originalTransaction); + const relatedTransactions = getChildTransactions(allTransactions, allReports, originalTransactionID); + const hasMultipleSplits = relatedTransactions.length > 1; + const transactionReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${transaction?.reportID}`]; + const isReportOpen = isOpenReport(transactionReport); + const shouldShowSplitIndicator = isExpenseSplit && (hasMultipleSplits || isReportOpen); - if (isExpenseSplit) { - const relatedTransactions = getChildTransactions(allTransactions, allReports, originalTransactionID); + if (isExpenseSplit && shouldShowSplitIndicator) { const transactionDetails = getTransactionDetails(originalTransaction); const splitExpenses = relatedTransactions.map((currentTransaction) => { const currentTransactionReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${currentTransaction?.reportID}`]; @@ -81,7 +85,6 @@ function initSplitExpense(transaction: OnyxEntry, policy?: OnyxEntr const transactionDetails = getTransactionDetails(transaction); const transactionDetailsAmount = transactionDetails?.amount ?? 0; - const transactionReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${transaction?.reportID}`]; const splitAmounts = [ calculateAmount(1, transactionDetailsAmount, transactionDetails?.currency ?? '', false),