diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index d4e49f9d1bc5..7fde47c73e58 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -217,6 +217,40 @@ type MoneyRequestInformationParams = { existingTransaction?: OnyxEntry; }; +type MoneyRequestOptimisticParams = { + chat: { + report: OnyxTypes.OnyxInputOrEntry; + createdAction: OptimisticCreatedReportAction; + reportPreviewAction: ReportAction; + }; + iou: { + report: OnyxTypes.Report; + createdAction: OptimisticCreatedReportAction; + action: OptimisticIOUReportAction; + }; + transactionParams: { + transaction: OnyxTypes.Transaction; + transactionThreadReport: OptimisticChatReport | null; + transactionThreadCreatedReportAction: OptimisticCreatedReportAction | null; + }; + policyRecentlyUsed: { + categories?: string[]; + tags?: OnyxTypes.RecentlyUsedTags; + currencies?: string[]; + }; + personalDetailListAction?: OnyxTypes.PersonalDetailsList; + nextStep?: OnyxTypes.ReportNextStep | null; +}; + +type BuildOnyxDataForMoneyRequestParams = { + isNewChatReport: boolean; + shouldCreateNewMoneyRequestReport: boolean; + isOneOnOneSplit?: boolean; + existingTransactionThreadReportID?: string; + policyParams?: RequestMoneyPolicyParams; + optimisticParams: MoneyRequestOptimisticParams; +}; + let allPersonalDetails: OnyxTypes.PersonalDetailsList = {}; Onyx.connect({ key: ONYXKEYS.PERSONAL_DETAILS_LIST, @@ -569,31 +603,20 @@ function getFieldViolationsOnyxData(iouReport: OnyxTypes.Report): SetRequired, - iouReport: OnyxTypes.Report, - transaction: OnyxTypes.Transaction, - chatCreatedAction: OptimisticCreatedReportAction, - iouCreatedAction: OptimisticCreatedReportAction, - iouAction: OptimisticIOUReportAction, - optimisticPersonalDetailListAction: OnyxTypes.PersonalDetailsList, - reportPreviewAction: ReportAction, - optimisticPolicyRecentlyUsedCategories: string[], - optimisticPolicyRecentlyUsedTags: OnyxTypes.RecentlyUsedTags, - isNewChatReport: boolean, - transactionThreadReport: OptimisticChatReport | null, - transactionThreadCreatedReportAction: OptimisticCreatedReportAction | null, - shouldCreateNewMoneyRequestReport: boolean, - policy?: OnyxTypes.OnyxInputOrEntry, - policyTagList?: OnyxTypes.OnyxInputOrEntry, - policyCategories?: OnyxTypes.OnyxInputOrEntry, - optimisticNextStep?: OnyxTypes.ReportNextStep | null, - isOneOnOneSplit = false, - existingTransactionThreadReportID?: string, - optimisticRecentlyUsedCurrencies?: string[], -): [OnyxUpdate[], OnyxUpdate[], OnyxUpdate[]] { +function buildOnyxDataForMoneyRequest(moneyRequestParams: BuildOnyxDataForMoneyRequestParams): [OnyxUpdate[], OnyxUpdate[], OnyxUpdate[]] { + const {isNewChatReport, shouldCreateNewMoneyRequestReport, isOneOnOneSplit = false, existingTransactionThreadReportID, policyParams = {}, optimisticParams} = moneyRequestParams; + const {policy, policyCategories, policyTagList} = policyParams; + const { + chat, + iou, + transactionParams: {transaction, transactionThreadReport, transactionThreadCreatedReportAction}, + policyRecentlyUsed, + personalDetailListAction, + nextStep, + } = optimisticParams; + const isScanRequest = TransactionUtils.isScanRequest(transaction); - const outstandingChildRequest = ReportUtils.getOutstandingChildRequest(iouReport); + const outstandingChildRequest = ReportUtils.getOutstandingChildRequest(iou.report); const clearedPendingFields = Object.fromEntries(Object.keys(transaction.pendingFields ?? {}).map((key) => [key, null])); const optimisticData: OnyxUpdate[] = []; const successData: OnyxUpdate[] = []; @@ -603,16 +626,16 @@ function buildOnyxDataForMoneyRequest( } const existingTransactionThreadReport = ReportConnection.getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${existingTransactionThreadReportID}`] ?? null; - if (chatReport) { + if (chat.report) { optimisticData.push({ // Use SET for new reports because it doesn't exist yet, is faster and we need the data to be available when we navigate to the chat page onyxMethod: isNewChatReport ? Onyx.METHOD.SET : Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT}${chatReport.reportID}`, + key: `${ONYXKEYS.COLLECTION.REPORT}${chat.report.reportID}`, value: { - ...chatReport, + ...chat.report, lastReadTime: DateUtils.getDBTime(), lastMessageTranslationKey: '', - iouReportID: iouReport.reportID, + iouReportID: iou.report.reportID, ...outstandingChildRequest, ...(isNewChatReport ? {pendingFields: {createChat: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD}} : {}), }, @@ -622,12 +645,12 @@ function buildOnyxDataForMoneyRequest( optimisticData.push( { onyxMethod: shouldCreateNewMoneyRequestReport ? Onyx.METHOD.SET : Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT}${iouReport.reportID}`, + key: `${ONYXKEYS.COLLECTION.REPORT}${iou.report.reportID}`, value: { - ...iouReport, - lastMessageText: ReportActionsUtils.getReportActionText(iouAction), - lastMessageHtml: ReportActionsUtils.getReportActionHtml(iouAction), - lastVisibleActionCreated: iouAction.created, + ...iou.report, + lastMessageText: ReportActionsUtils.getReportActionText(iou.action), + lastMessageHtml: ReportActionsUtils.getReportActionHtml(iou.action), + lastVisibleActionCreated: iou.action.created, pendingFields: { ...(shouldCreateNewMoneyRequestReport ? {createChat: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD} : {preview: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE}), }, @@ -641,33 +664,33 @@ function buildOnyxDataForMoneyRequest( isNewChatReport ? { onyxMethod: Onyx.METHOD.SET, - key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chatReport?.reportID}`, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chat.report?.reportID}`, value: { - [chatCreatedAction.reportActionID]: chatCreatedAction, - [reportPreviewAction.reportActionID]: reportPreviewAction, + [chat.createdAction.reportActionID]: chat.createdAction, + [chat.reportPreviewAction.reportActionID]: chat.reportPreviewAction, }, } : { onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chatReport?.reportID}`, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chat.report?.reportID}`, value: { - [reportPreviewAction.reportActionID]: reportPreviewAction, + [chat.reportPreviewAction.reportActionID]: chat.reportPreviewAction, }, }, shouldCreateNewMoneyRequestReport ? { onyxMethod: Onyx.METHOD.SET, - key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${iouReport.reportID}`, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${iou.report.reportID}`, value: { - [iouCreatedAction.reportActionID]: iouCreatedAction as OnyxTypes.ReportAction, - [iouAction.reportActionID]: iouAction as OnyxTypes.ReportAction, + [iou.createdAction.reportActionID]: iou.createdAction as OnyxTypes.ReportAction, + [iou.action.reportActionID]: iou.action as OnyxTypes.ReportAction, }, } : { onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${iouReport.reportID}`, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${iou.report.reportID}`, value: { - [iouAction.reportActionID]: iouAction as OnyxTypes.ReportAction, + [iou.action.reportActionID]: iou.action as OnyxTypes.ReportAction, }, }, { @@ -690,36 +713,36 @@ function buildOnyxDataForMoneyRequest( }); } - if (optimisticPolicyRecentlyUsedCategories.length) { + if (policyRecentlyUsed.categories?.length) { optimisticData.push({ onyxMethod: Onyx.METHOD.SET, - key: `${ONYXKEYS.COLLECTION.POLICY_RECENTLY_USED_CATEGORIES}${iouReport.policyID}`, - value: optimisticPolicyRecentlyUsedCategories, + key: `${ONYXKEYS.COLLECTION.POLICY_RECENTLY_USED_CATEGORIES}${iou.report.policyID}`, + value: policyRecentlyUsed.categories, }); } - if (optimisticRecentlyUsedCurrencies?.length) { + if (policyRecentlyUsed.currencies?.length) { optimisticData.push({ onyxMethod: Onyx.METHOD.SET, key: ONYXKEYS.RECENTLY_USED_CURRENCIES, - value: optimisticRecentlyUsedCurrencies, + value: policyRecentlyUsed.currencies, }); } - if (!isEmptyObject(optimisticPolicyRecentlyUsedTags)) { + if (!isEmptyObject(policyRecentlyUsed.tags)) { optimisticData.push({ onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.POLICY_RECENTLY_USED_TAGS}${iouReport.policyID}`, - value: optimisticPolicyRecentlyUsedTags, + key: `${ONYXKEYS.COLLECTION.POLICY_RECENTLY_USED_TAGS}${iou.report.policyID}`, + value: policyRecentlyUsed.tags, }); } const redundantParticipants: Record = {}; - if (!isEmptyObject(optimisticPersonalDetailListAction)) { + if (!isEmptyObject(personalDetailListAction)) { const successPersonalDetailListAction: Record = {}; // BE will send different participants. We clear the optimistic ones to avoid duplicated entries - Object.keys(optimisticPersonalDetailListAction).forEach((accountIDKey) => { + Object.keys(personalDetailListAction).forEach((accountIDKey) => { const accountID = Number(accountIDKey); successPersonalDetailListAction[accountID] = null; redundantParticipants[accountID] = null; @@ -728,7 +751,7 @@ function buildOnyxDataForMoneyRequest( optimisticData.push({ onyxMethod: Onyx.METHOD.MERGE, key: ONYXKEYS.PERSONAL_DETAILS_LIST, - value: optimisticPersonalDetailListAction, + value: personalDetailListAction, }); successData.push({ onyxMethod: Onyx.METHOD.MERGE, @@ -737,11 +760,11 @@ function buildOnyxDataForMoneyRequest( }); } - if (!isEmptyObject(optimisticNextStep)) { + if (!isEmptyObject(nextStep)) { optimisticData.push({ onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.NEXT_STEP}${iouReport.reportID}`, - value: optimisticNextStep, + key: `${ONYXKEYS.COLLECTION.NEXT_STEP}${iou.report.reportID}`, + value: nextStep, }); } @@ -749,7 +772,7 @@ function buildOnyxDataForMoneyRequest( successData.push( { onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT}${chatReport?.reportID}`, + key: `${ONYXKEYS.COLLECTION.REPORT}${chat.report?.reportID}`, value: { participants: redundantParticipants, pendingFields: null, @@ -758,7 +781,7 @@ function buildOnyxDataForMoneyRequest( }, { onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT_METADATA}${chatReport?.reportID}`, + key: `${ONYXKEYS.COLLECTION.REPORT_METADATA}${chat.report?.reportID}`, value: { isOptimisticReport: false, }, @@ -769,7 +792,7 @@ function buildOnyxDataForMoneyRequest( successData.push( { onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT}${iouReport.reportID}`, + key: `${ONYXKEYS.COLLECTION.REPORT}${iou.report.reportID}`, value: { participants: redundantParticipants, pendingFields: null, @@ -778,7 +801,7 @@ function buildOnyxDataForMoneyRequest( }, { onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT_METADATA}${iouReport.reportID}`, + key: `${ONYXKEYS.COLLECTION.REPORT_METADATA}${iou.report.reportID}`, value: { isOptimisticReport: false, }, @@ -814,34 +837,34 @@ function buildOnyxDataForMoneyRequest( { onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chatReport?.reportID}`, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chat.report?.reportID}`, value: { ...(isNewChatReport ? { - [chatCreatedAction.reportActionID]: { + [chat.createdAction.reportActionID]: { pendingAction: null, errors: null, }, } : {}), - [reportPreviewAction.reportActionID]: { + [chat.reportPreviewAction.reportActionID]: { pendingAction: null, }, }, }, { onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${iouReport.reportID}`, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${iou.report.reportID}`, value: { ...(shouldCreateNewMoneyRequestReport ? { - [iouCreatedAction.reportActionID]: { + [iou.createdAction.reportActionID]: { pendingAction: null, errors: null, }, } : {}), - [iouAction.reportActionID]: { + [iou.action.reportActionID]: { pendingAction: null, errors: null, }, @@ -867,12 +890,12 @@ function buildOnyxDataForMoneyRequest( const failureData: OnyxUpdate[] = [ { onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT}${chatReport?.reportID}`, + key: `${ONYXKEYS.COLLECTION.REPORT}${chat.report?.reportID}`, value: { - iouReportID: chatReport?.iouReportID, - lastReadTime: chatReport?.lastReadTime, + iouReportID: chat.report?.iouReportID, + lastReadTime: chat.report?.lastReadTime, pendingFields: null, - hasOutstandingChildRequest: chatReport?.hasOutstandingChildRequest, + hasOutstandingChildRequest: chat.report?.hasOutstandingChildRequest, ...(isNewChatReport ? { errorFields: { @@ -884,7 +907,7 @@ function buildOnyxDataForMoneyRequest( }, { onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT}${iouReport.reportID}`, + key: `${ONYXKEYS.COLLECTION.REPORT}${iou.report.reportID}`, value: { pendingFields: null, errorFields: { @@ -916,21 +939,21 @@ function buildOnyxDataForMoneyRequest( }, { onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${iouReport.reportID}`, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${iou.report.reportID}`, value: { ...(shouldCreateNewMoneyRequestReport ? { - [iouCreatedAction.reportActionID]: { + [iou.createdAction.reportActionID]: { // Disabling this line since transaction.filename can be an empty string // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing errors: getReceiptError(transaction.receipt, transaction.filename || transaction.receipt?.filename, isScanRequest, errorKey), }, - [iouAction.reportActionID]: { + [iou.action.reportActionID]: { errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('iou.error.genericCreateFailureMessage'), }, } : { - [iouAction.reportActionID]: { + [iou.action.reportActionID]: { // Disabling this line since transaction.filename can be an empty string // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing errors: getReceiptError(transaction.receipt, transaction.filename || transaction.receipt?.filename, isScanRequest, errorKey), @@ -946,7 +969,7 @@ function buildOnyxDataForMoneyRequest( key: ONYXKEYS.NVP_QUICK_ACTION_GLOBAL_CREATE, value: { action: newQuickAction, - chatReportID: chatReport?.reportID, + chatReportID: chat.report?.reportID, isFirstQuickAction: isEmptyObject(quickAction), }, }); @@ -2215,7 +2238,7 @@ function getMoneyRequestInformation(moneyRequestInformation: MoneyRequestInforma const optimisticPolicyRecentlyUsedCategories = Category.buildOptimisticPolicyRecentlyUsedCategories(iouReport.policyID, category); const optimisticPolicyRecentlyUsedTags = Tag.buildOptimisticPolicyRecentlyUsedTags(iouReport.policyID, tag); - const optimisticPolicyRecentluUsedCurrencies = Policy.buildOptimisticRecentlyUsedCurrencies(currency); + const optimisticPolicyRecentlyUsedCurrencies = Policy.buildOptimisticRecentlyUsedCurrencies(currency); // If there is an existing transaction (which is the case for distance requests), then the data from the existing transaction // needs to be manually merged into the optimistic transaction. This is because buildOnyxDataForMoneyRequest() uses `Onyx.set()` for the transaction @@ -2284,29 +2307,39 @@ function getMoneyRequestInformation(moneyRequestInformation: MoneyRequestInforma const optimisticNextStep = NextStepUtils.buildNextStep(iouReport, predictedNextStatus); // STEP 5: Build Onyx Data - const [optimisticData, successData, failureData] = buildOnyxDataForMoneyRequest( - chatReport, - iouReport, - optimisticTransaction, - optimisticCreatedActionForChat, - optimisticCreatedActionForIOUReport, - iouAction, - optimisticPersonalDetailListAction, - reportPreviewAction, - optimisticPolicyRecentlyUsedCategories, - optimisticPolicyRecentlyUsedTags, + const [optimisticData, successData, failureData] = buildOnyxDataForMoneyRequest({ isNewChatReport, - optimisticTransactionThread ?? {}, - optimisticCreatedActionForTransactionThread, shouldCreateNewMoneyRequestReport, - policy, - policyTagList, - policyCategories, - optimisticNextStep, - undefined, - undefined, - optimisticPolicyRecentluUsedCurrencies, - ); + policyParams: { + policy, + policyCategories, + policyTagList, + }, + optimisticParams: { + chat: { + report: chatReport, + createdAction: optimisticCreatedActionForChat, + reportPreviewAction, + }, + iou: { + report: iouReport, + createdAction: optimisticCreatedActionForIOUReport, + action: iouAction, + }, + transactionParams: { + transaction: optimisticTransaction, + transactionThreadReport: optimisticTransactionThread, + transactionThreadCreatedReportAction: optimisticCreatedActionForTransactionThread, + }, + policyRecentlyUsed: { + categories: optimisticPolicyRecentlyUsedCategories, + tags: optimisticPolicyRecentlyUsedTags, + currencies: optimisticPolicyRecentlyUsedCurrencies, + }, + personalDetailListAction: optimisticPersonalDetailListAction, + nextStep: optimisticNextStep, + }, + }); return { payerAccountID, @@ -4446,29 +4479,34 @@ function createSplitsAndOnyxData( const optimisticPolicyRecentlyUsedTags = isPolicyExpenseChat ? Tag.buildOptimisticPolicyRecentlyUsedTags(participant.policyID, tag) : {}; // STEP 5: Build Onyx Data - const [oneOnOneOptimisticData, oneOnOneSuccessData, oneOnOneFailureData] = buildOnyxDataForMoneyRequest( - oneOnOneChatReport, - oneOnOneIOUReport, - oneOnOneTransaction, - oneOnOneCreatedActionForChat, - oneOnOneCreatedActionForIOU, - oneOnOneIOUAction, - oneOnOnePersonalDetailListAction, - oneOnOneReportPreviewAction, - optimisticPolicyRecentlyUsedCategories, - optimisticPolicyRecentlyUsedTags, - isNewOneOnOneChatReport, - optimisticTransactionThread, - optimisticCreatedActionForTransactionThread, - shouldCreateNewOneOnOneIOUReport, - null, - null, - null, - null, - true, - undefined, - optimisticRecentlyUsedCurrencies, - ); + const [oneOnOneOptimisticData, oneOnOneSuccessData, oneOnOneFailureData] = buildOnyxDataForMoneyRequest({ + isNewChatReport: isNewOneOnOneChatReport, + shouldCreateNewMoneyRequestReport: shouldCreateNewOneOnOneIOUReport, + isOneOnOneSplit: true, + optimisticParams: { + chat: { + report: oneOnOneChatReport, + createdAction: oneOnOneCreatedActionForChat, + reportPreviewAction: oneOnOneReportPreviewAction, + }, + iou: { + report: oneOnOneIOUReport, + createdAction: oneOnOneCreatedActionForIOU, + action: oneOnOneIOUAction, + }, + transactionParams: { + transaction: oneOnOneTransaction, + transactionThreadReport: optimisticTransactionThread, + transactionThreadCreatedReportAction: optimisticCreatedActionForTransactionThread, + }, + policyRecentlyUsed: { + categories: optimisticPolicyRecentlyUsedCategories, + tags: optimisticPolicyRecentlyUsedTags, + currencies: optimisticRecentlyUsedCurrencies, + }, + personalDetailListAction: oneOnOnePersonalDetailListAction, + }, + }); const individualSplit = { email, @@ -5174,27 +5212,29 @@ function completeSplitBill(chatReportID: string, reportAction: OnyxTypes.ReportA oneOnOneReportPreviewAction = ReportUtils.buildOptimisticReportPreview(oneOnOneChatReport, oneOnOneIOUReport, '', oneOnOneTransaction); } - const [oneOnOneOptimisticData, oneOnOneSuccessData, oneOnOneFailureData] = buildOnyxDataForMoneyRequest( - oneOnOneChatReport, - oneOnOneIOUReport, - oneOnOneTransaction, - oneOnOneCreatedActionForChat, - oneOnOneCreatedActionForIOU, - oneOnOneIOUAction, - {}, - oneOnOneReportPreviewAction, - [], - {}, - isNewOneOnOneChatReport, - optimisticTransactionThread, - optimisticCreatedActionForTransactionThread, - shouldCreateNewOneOnOneIOUReport, - null, - null, - null, - null, - true, - ); + const [oneOnOneOptimisticData, oneOnOneSuccessData, oneOnOneFailureData] = buildOnyxDataForMoneyRequest({ + isNewChatReport: isNewOneOnOneChatReport, + isOneOnOneSplit: true, + shouldCreateNewMoneyRequestReport: shouldCreateNewOneOnOneIOUReport, + optimisticParams: { + chat: { + report: oneOnOneChatReport, + createdAction: oneOnOneCreatedActionForChat, + reportPreviewAction: oneOnOneReportPreviewAction, + }, + iou: { + report: oneOnOneIOUReport, + createdAction: oneOnOneCreatedActionForIOU, + action: oneOnOneIOUAction, + }, + transactionParams: { + transaction: oneOnOneTransaction, + transactionThreadReport: optimisticTransactionThread, + transactionThreadCreatedReportAction: optimisticCreatedActionForTransactionThread, + }, + policyRecentlyUsed: {}, + }, + }); splits.push({ email: participant.email,