diff --git a/src/components/ReportActionItem/MoneyRequestView.tsx b/src/components/ReportActionItem/MoneyRequestView.tsx index 635d7e05ecf4..16d20853aa09 100644 --- a/src/components/ReportActionItem/MoneyRequestView.tsx +++ b/src/components/ReportActionItem/MoneyRequestView.tsx @@ -410,6 +410,14 @@ function MoneyRequestView({ if (!transaction?.transactionID) { return; } + + const isCreateChatErrored = !!report?.errorFields?.createChat; + if ((isCreateChatErrored || !!report.isOptimisticReport) && parentReportAction) { + const urlToNavigateBack = IOU.cleanUpMoneyRequest(transaction.transactionID, parentReportAction, true); + Navigation.goBack(urlToNavigateBack); + return; + } + if (transaction.pendingAction === CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD) { if (chatReport?.reportID && ReportUtils.getAddWorkspaceRoomOrChatReportErrors(chatReport)) { Report.navigateToConciergeChatAndDeleteReport(chatReport.reportID, true, true); diff --git a/src/libs/ReportActionsUtils.ts b/src/libs/ReportActionsUtils.ts index 1aaa5cd7bfee..add379d462b0 100644 --- a/src/libs/ReportActionsUtils.ts +++ b/src/libs/ReportActionsUtils.ts @@ -1,7 +1,7 @@ import {fastMerge} from 'expensify-common'; import _ from 'lodash'; import lodashFindLast from 'lodash/findLast'; -import type {OnyxCollection, OnyxCollectionInputValue, OnyxEntry, OnyxUpdate} from 'react-native-onyx'; +import type {NullishDeep, OnyxCollection, OnyxEntry, OnyxUpdate} from 'react-native-onyx'; import Onyx from 'react-native-onyx'; import type {ValueOf} from 'type-fest'; import CONST from '@src/CONST'; @@ -10,8 +10,8 @@ import ONYXKEYS from '@src/ONYXKEYS'; import type {OnyxInputOrEntry} from '@src/types/onyx'; import type {JoinWorkspaceResolution, OriginalMessageExportIntegration} from '@src/types/onyx/OriginalMessage'; import type Report from '@src/types/onyx/Report'; -import type {Message, OldDotReportAction, OriginalMessage, ReportActions} from '@src/types/onyx/ReportAction'; import type ReportAction from '@src/types/onyx/ReportAction'; +import type {Message, OldDotReportAction, OriginalMessage, ReportActions} from '@src/types/onyx/ReportAction'; import type ReportActionName from '@src/types/onyx/ReportActionName'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; import DateUtils from './DateUtils'; @@ -715,10 +715,12 @@ function replaceBaseURLInPolicyChangeLogAction(reportAction: ReportAction): Repo return updatedReportAction; } -function getLastVisibleAction(reportID: string, actionsToMerge: OnyxCollection | OnyxCollectionInputValue = {}): OnyxEntry { +function getLastVisibleAction(reportID: string, actionsToMerge: Record | null> = {}): OnyxEntry { let reportActions: Array = []; if (!_.isEmpty(actionsToMerge)) { - reportActions = Object.values(fastMerge(allReportActions?.[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`] ?? {}, actionsToMerge ?? {}, true)); + reportActions = Object.values(fastMerge(allReportActions?.[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`] ?? {}, actionsToMerge ?? {}, true)) as Array< + ReportAction | null | undefined + >; } else { reportActions = Object.values(allReportActions?.[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`] ?? {}); } @@ -732,7 +734,7 @@ function getLastVisibleAction(reportID: string, actionsToMerge: OnyxCollection | OnyxCollectionInputValue = {}, + actionsToMerge: Record | null> = {}, reportAction: OnyxInputOrEntry | undefined = undefined, ): LastVisibleMessage { const lastVisibleAction = reportAction ?? getLastVisibleAction(reportID, actionsToMerge); @@ -1534,92 +1536,92 @@ function getExportIntegrationActionFragments(reportAction: OnyxEntry>; const lastVisibleAction = ReportActionsUtils.getLastVisibleAction(iouReport?.reportID ?? '-1', updatedReportAction); const iouReportLastMessageText = ReportActionsUtils.getLastVisibleMessage(iouReport?.reportID ?? '-1', updatedReportAction).lastMessageText; @@ -5410,7 +5417,199 @@ function deleteMoneyRequest(transactionID: string, reportAction: OnyxTypes.Repor updatedReportPreviewAction.childMoneyRequestCount = reportPreviewAction.childMoneyRequestCount - 1; } - // STEP 5: Build Onyx data + // STEP 5: Calculate the url that the user will be navigated back to + // This depends on which page they are on and which resources were deleted + let reportIDToNavigateBack: string | undefined; + if (iouReport && isSingleTransactionView && shouldDeleteTransactionThread && !shouldDeleteIOUReport) { + reportIDToNavigateBack = iouReport.reportID; + } + + if (iouReport?.chatReportID && shouldDeleteIOUReport) { + reportIDToNavigateBack = iouReport.chatReportID; + } + + const urlToNavigateBack = reportIDToNavigateBack ? ROUTES.REPORT_WITH_ID.getRoute(reportIDToNavigateBack) : undefined; + + return { + shouldDeleteTransactionThread, + shouldDeleteIOUReport, + updatedReportAction, + updatedIOUReport, + updatedReportPreviewAction, + transactionThreadID, + transactionThread, + chatReport, + transaction, + transactionViolations, + reportPreviewAction, + iouReport, + urlToNavigateBack, + }; +} + +/** + * + * @param transactionID - The transactionID of IOU + * @param reportAction - The reportAction of the transaction in the IOU report + * @param isSingleTransactionView - whether we are in the transaction thread report + * @return the url to navigate back once the money request is deleted + */ +function cleanUpMoneyRequest(transactionID: string, reportAction: OnyxTypes.ReportAction, isSingleTransactionView = false) { + const { + shouldDeleteTransactionThread, + shouldDeleteIOUReport, + updatedReportAction, + updatedIOUReport, + updatedReportPreviewAction, + transactionThreadID, + chatReport, + iouReport, + reportPreviewAction, + urlToNavigateBack, + } = prepareToCleanUpMoneyRequest(transactionID, reportAction, isSingleTransactionView); + + // build Onyx data + + // Onyx operations to delete the transaction, update the IOU report action and chat report action + const onyxUpdates: OnyxUpdate[] = [ + { + onyxMethod: Onyx.METHOD.SET, + key: `${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`, + value: null, + }, + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${iouReport?.reportID}`, + value: { + [reportAction.reportActionID]: shouldDeleteIOUReport + ? null + : { + pendingAction: null, + }, + }, + }, + ]; + + if (reportPreviewAction?.reportActionID) { + onyxUpdates.push({ + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chatReport?.reportID}`, + value: { + [reportPreviewAction.reportActionID]: { + ...updatedReportPreviewAction, + pendingAction: null, + errors: null, + }, + }, + }); + } + + // added the operation to delete associated transaction violations + if (Permissions.canUseViolations(betas)) { + onyxUpdates.push({ + onyxMethod: Onyx.METHOD.SET, + key: `${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transactionID}`, + value: null, + }); + } + + // added the operation to delete transaction thread + if (shouldDeleteTransactionThread) { + onyxUpdates.push( + { + onyxMethod: Onyx.METHOD.SET, + key: `${ONYXKEYS.COLLECTION.REPORT}${transactionThreadID}`, + value: null, + }, + { + onyxMethod: Onyx.METHOD.SET, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${transactionThreadID}`, + value: null, + }, + ); + } + + // added operations to update IOU report and chat report + onyxUpdates.push( + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${iouReport?.reportID}`, + value: updatedReportAction, + }, + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT}${iouReport?.reportID}`, + value: updatedIOUReport, + }, + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT}${chatReport?.reportID}`, + value: ReportUtils.getOutstandingChildRequest(updatedIOUReport), + }, + ); + + if (!shouldDeleteIOUReport && updatedReportPreviewAction.childMoneyRequestCount === 0) { + onyxUpdates.push({ + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT}${chatReport?.reportID}`, + value: { + hasOutstandingChildRequest: false, + }, + }); + } + + if (shouldDeleteIOUReport) { + onyxUpdates.push( + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT}${chatReport?.reportID}`, + value: { + hasOutstandingChildRequest: false, + iouReportID: null, + lastMessageText: ReportActionsUtils.getLastVisibleMessage(iouReport?.chatReportID ?? '-1', {[reportPreviewAction?.reportActionID ?? '-1']: null})?.lastMessageText, + lastVisibleActionCreated: ReportActionsUtils.getLastVisibleAction(iouReport?.chatReportID ?? '-1', {[reportPreviewAction?.reportActionID ?? '-1']: null})?.created, + }, + }, + { + onyxMethod: Onyx.METHOD.SET, + key: `${ONYXKEYS.COLLECTION.REPORT}${iouReport?.reportID}`, + value: null, + }, + ); + } + + Onyx.update(onyxUpdates); + + return urlToNavigateBack; +} + +/** + * + * @param transactionID - The transactionID of IOU + * @param reportAction - The reportAction of the transaction in the IOU report + * @param isSingleTransactionView - whether we are in the transaction thread report + * @return the url to navigate back once the money request is deleted + */ +function deleteMoneyRequest(transactionID: string, reportAction: OnyxTypes.ReportAction, isSingleTransactionView = false) { + // STEP 1: Calculate and prepare the data + const { + shouldDeleteTransactionThread, + shouldDeleteIOUReport, + updatedReportAction, + updatedIOUReport, + updatedReportPreviewAction, + transactionThreadID, + transactionThread, + chatReport, + transaction, + transactionViolations, + iouReport, + reportPreviewAction, + urlToNavigateBack, + } = prepareToCleanUpMoneyRequest(transactionID, reportAction, isSingleTransactionView); + + // STEP 2: Build Onyx data + // The logic mostly resembles the cleanUpMoneyRequest function const optimisticData: OnyxUpdate[] = [ { onyxMethod: Onyx.METHOD.SET, @@ -5611,20 +5810,11 @@ function deleteMoneyRequest(transactionID: string, reportAction: OnyxTypes.Repor reportActionID: reportAction.reportActionID, }; - // STEP 6: Make the API request + // STEP 3: Make the API request API.write(WRITE_COMMANDS.DELETE_MONEY_REQUEST, parameters, {optimisticData, successData, failureData}); CachedPDFPaths.clearByKey(transactionID); - // STEP 7: Navigate the user depending on which page they are on and which resources were deleted - if (iouReport && isSingleTransactionView && shouldDeleteTransactionThread && !shouldDeleteIOUReport) { - // Pop the deleted report screen before navigating. This prevents navigating to the Concierge chat due to the missing report. - return ROUTES.REPORT_WITH_ID.getRoute(iouReport.reportID); - } - - if (iouReport?.chatReportID && shouldDeleteIOUReport) { - // Pop the deleted report screen before navigating. This prevents navigating to the Concierge chat due to the missing report. - return ROUTES.REPORT_WITH_ID.getRoute(iouReport.chatReportID); - } + return urlToNavigateBack; } function deleteTrackExpense(chatReportID: string, transactionID: string, reportAction: OnyxTypes.ReportAction, isSingleTransactionView = false) { @@ -7163,11 +7353,12 @@ function getIOURequestPolicyID(transaction: OnyxEntry, re } export { + adjustRemainingSplitShares, approveMoneyRequest, - unapproveExpenseReport, canApproveIOU, - canIOUBePaid, cancelPayment, + canIOUBePaid, + cleanUpMoneyRequest, clearMoneyRequest, completeSplitBill, createDistanceRequest, @@ -7175,19 +7366,24 @@ export { deleteMoneyRequest, deleteTrackExpense, detachReceipt, + dismissHoldUseExplanation, editMoneyRequest, + getIOURequestPolicyID, initMoneyRequest, navigateToStartStepIfScanFileCannotBeRead, - payMoneyRequest, payInvoice, + payMoneyRequest, putOnHold, replaceReceipt, requestMoney, + resetSplitShares, savePreferredPaymentMethod, + sendInvoice, sendMoneyElsewhere, sendMoneyWithWallet, setCustomUnitRateID, setDraftSplitTransaction, + setIndividualShare, setMoneyRequestAmount, setMoneyRequestBillable, setMoneyRequestCategory, @@ -7199,34 +7395,29 @@ export { setMoneyRequestParticipantsFromReport, setMoneyRequestPendingFields, setMoneyRequestReceipt, - setSplitPayer, setMoneyRequestTag, setMoneyRequestTaxAmount, setMoneyRequestTaxRate, - dismissHoldUseExplanation, - updateMoneyRequestDate, + setSplitPayer, setSplitShares, - resetSplitShares, - setIndividualShare, - adjustRemainingSplitShares, splitBill, splitBillAndOpenReport, startMoneyRequest, startSplitBill, submitReport, trackExpense, + unapproveExpenseReport, unholdRequest, updateDistanceRequestRate, updateMoneyRequestAmountAndCurrency, updateMoneyRequestBillable, updateMoneyRequestCategory, + updateMoneyRequestDate, updateMoneyRequestDescription, updateMoneyRequestDistance, updateMoneyRequestMerchant, updateMoneyRequestTag, updateMoneyRequestTaxAmount, updateMoneyRequestTaxRate, - sendInvoice, - getIOURequestPolicyID, }; export type {GPSPoint as GpsPoint, IOURequestType};