diff --git a/src/CONST.ts b/src/CONST.ts index d2be946cdb2b..c47439bfc200 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -151,6 +151,7 @@ const CONST = { DISPLAY_NAME: { MAX_LENGTH: 50, RESERVED_NAMES: ['Expensify', 'Concierge'], + EXPENSIFY_CONCIERGE: 'Expensify Concierge', }, GPS: { @@ -3747,7 +3748,7 @@ const CONST = { ONBOARDING_INTRODUCTION: 'Let’s get you set up 🔧', ONBOARDING_CHOICES: {...onboardingChoices}, - + ACTIONABLE_TRACK_EXPENSE_WHISPER_MESSAGE: 'What would you like to do with this expense?', ONBOARDING_CONCIERGE: { [onboardingChoices.EMPLOYER]: '# Expensify is the fastest way to get paid back!\n' + diff --git a/src/libs/API/parameters/TrackExpenseParams.ts b/src/libs/API/parameters/TrackExpenseParams.ts index 5f15a6a3f521..d5e1de2e625b 100644 --- a/src/libs/API/parameters/TrackExpenseParams.ts +++ b/src/libs/API/parameters/TrackExpenseParams.ts @@ -26,6 +26,7 @@ type TrackExpenseParams = { transactionThreadReportID: string; createdReportActionIDForThread: string; waypoints?: string; + actionableWhisperReportActionID?: string; }; export default TrackExpenseParams; diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 2290484ffec5..9bc5ff592956 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -4117,6 +4117,45 @@ function buildOptimisticReportPreview(chatReport: OnyxEntry, iouReport: }; } +/** + * Builds an optimistic ACTIONABLETRACKEXPENSEWHISPER action with a randomly generated reportActionID. + */ +function buildOptimisticActionableTrackExpenseWhisper(iouAction: OptimisticIOUReportAction, transactionID: string): ReportAction { + const currentTime = DateUtils.getDBTime(); + const targetEmail = CONST.EMAIL.CONCIERGE; + const actorAccountID = PersonalDetailsUtils.getAccountIDsByLogins([targetEmail])[0]; + const reportActionID = NumberUtils.rand64(); + return { + actionName: CONST.REPORT.ACTIONS.TYPE.ACTIONABLE_TRACK_EXPENSE_WHISPER, + actorAccountID, + avatar: UserUtils.getDefaultAvatarURL(actorAccountID), + created: DateUtils.addMillisecondsFromDateTime(currentTime, 1), + lastModified: DateUtils.addMillisecondsFromDateTime(currentTime, 1), + message: [ + { + html: CONST.ACTIONABLE_TRACK_EXPENSE_WHISPER_MESSAGE, + text: CONST.ACTIONABLE_TRACK_EXPENSE_WHISPER_MESSAGE, + whisperedTo: [], + type: CONST.REPORT.MESSAGE.TYPE.COMMENT, + }, + ], + originalMessage: { + lastModified: DateUtils.addMillisecondsFromDateTime(currentTime, 1), + transactionID, + }, + person: [ + { + text: CONST.DISPLAY_NAME.EXPENSIFY_CONCIERGE, + type: 'TEXT', + }, + ], + previousReportActionID: iouAction?.reportActionID, + reportActionID, + shouldShow: true, + pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, + }; +} + /** * Builds an optimistic modified expense action with a randomly generated reportActionID. */ @@ -6702,6 +6741,7 @@ export { buildOptimisticMovedTrackedExpenseModifiedReportAction, buildOptimisticRenamedRoomReportAction, buildOptimisticReportPreview, + buildOptimisticActionableTrackExpenseWhisper, buildOptimisticSubmittedReportAction, buildOptimisticTaskCommentReportAction, buildOptimisticTaskReport, diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 028c7bbcf70a..6f642b424c34 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -93,6 +93,7 @@ type TrackExpenseInformation = { reportPreviewAction?: OnyxTypes.ReportAction; transactionThreadReportID: string; createdReportActionIDForThread: string; + actionableWhisperReportActionIDParam?: string; onyxData: OnyxData; }; @@ -1150,6 +1151,7 @@ function buildOnyxDataForTrackExpense( policyTagList?: OnyxEntry, policyCategories?: OnyxEntry, existingTransactionThreadReportID?: string, + actionableTrackExpenseWhisper?: OnyxEntry, ): [OnyxUpdate[], OnyxUpdate[], OnyxUpdate[]] { const isScanRequest = TransactionUtils.isScanRequest(transaction); const isDistanceRequest = TransactionUtils.isDistanceRequest(transaction); @@ -1189,6 +1191,36 @@ function buildOnyxDataForTrackExpense( }, }, ); + + if (actionableTrackExpenseWhisper && !iouReport) { + optimisticData.push({ + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chatReport?.reportID}`, + value: { + [actionableTrackExpenseWhisper.reportActionID]: actionableTrackExpenseWhisper, + }, + }); + optimisticData.push({ + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT}${chatReport.reportID}`, + value: { + lastVisibleActionCreated: actionableTrackExpenseWhisper.created, + lastMessageText: CONST.ACTIONABLE_TRACK_EXPENSE_WHISPER_MESSAGE, + }, + }); + successData.push({ + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chatReport?.reportID}`, + value: { + [actionableTrackExpenseWhisper.reportActionID]: {pendingAction: null, errors: null}, + }, + }); + failureData.push({ + onyxMethod: Onyx.METHOD.SET, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chatReport?.reportID}`, + value: {[actionableTrackExpenseWhisper.reportActionID]: {} as ReportAction}, + }); + } } if (iouReport) { @@ -2156,6 +2188,11 @@ function getTrackExpenseInformation( } } + let actionableTrackExpenseWhisper: OnyxEntry = null; + if (!isPolicyExpenseChat) { + actionableTrackExpenseWhisper = ReportUtils.buildOptimisticActionableTrackExpenseWhisper(iouAction, optimisticTransaction.transactionID); + } + // STEP 5: Build Onyx Data const trackExpenseOnyxData = buildOnyxDataForTrackExpense( chatReport, @@ -2170,6 +2207,8 @@ function getTrackExpenseInformation( policy, policyTagList, policyCategories, + undefined, + actionableTrackExpenseWhisper, ); return { @@ -2183,6 +2222,7 @@ function getTrackExpenseInformation( reportPreviewAction: reportPreviewAction ?? undefined, transactionThreadReportID: optimisticTransactionThread.reportID, createdReportActionIDForThread: optimisticCreatedActionForTransactionThread.reportActionID, + actionableWhisperReportActionIDParam: actionableTrackExpenseWhisper?.reportActionID ?? '', onyxData: { optimisticData: [...optimisticData, ...trackExpenseOnyxData[0]], successData: [...successData, ...trackExpenseOnyxData[1]], @@ -3526,6 +3566,7 @@ function trackExpense( reportPreviewAction, transactionThreadReportID, createdReportActionIDForThread, + actionableWhisperReportActionIDParam, onyxData, } = getTrackExpenseInformation( currentChatReport, @@ -3642,7 +3683,9 @@ function trackExpense( createdReportActionIDForThread, waypoints: validWaypoints ? JSON.stringify(validWaypoints) : undefined, }; - + if (actionableWhisperReportActionIDParam) { + parameters.actionableWhisperReportActionID = actionableWhisperReportActionIDParam; + } API.write(WRITE_COMMANDS.TRACK_EXPENSE, parameters, onyxData); } } diff --git a/src/pages/home/report/ContextMenu/ContextMenuActions.tsx b/src/pages/home/report/ContextMenu/ContextMenuActions.tsx index afb3d69d3330..7c7dec1317dd 100644 --- a/src/pages/home/report/ContextMenu/ContextMenuActions.tsx +++ b/src/pages/home/report/ContextMenu/ContextMenuActions.tsx @@ -361,7 +361,7 @@ const ContextMenuActions: ContextMenuAction[] = [ const mentionWhisperMessage = ReportActionsUtils.getActionableMentionWhisperMessage(reportAction); setClipboardMessage(mentionWhisperMessage); } else if (ReportActionsUtils.isActionableTrackExpense(reportAction)) { - setClipboardMessage('What would you like to do with this expense?'); + setClipboardMessage(CONST.ACTIONABLE_TRACK_EXPENSE_WHISPER_MESSAGE); } else if (reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.HOLD) { Clipboard.setString(Localize.translateLocal('iou.heldExpense')); } else if (reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.UNHOLD) {