From a9fedf4df0364c03b083c695762c56ea971b8d9d Mon Sep 17 00:00:00 2001 From: nkdengineer Date: Fri, 12 Apr 2024 16:17:34 +0700 Subject: [PATCH 01/45] feture: Stop using reportAction.originalMessage or reportAction.message.text --- .../ReportActionItem/ReportPreview.tsx | 2 +- src/libs/ReportActionsUtils.ts | 17 ++++++++++++-- src/libs/ReportUtils.ts | 9 +++++--- src/libs/TaskUtils.ts | 3 ++- src/libs/actions/IOU.ts | 22 +++++++++---------- src/libs/actions/Report.ts | 4 ++-- src/libs/actions/Task.ts | 2 +- src/pages/home/report/ReportActionItem.tsx | 2 +- tests/actions/IOUTest.ts | 2 +- tests/ui/UnreadIndicatorsTest.tsx | 3 ++- 10 files changed, 42 insertions(+), 24 deletions(-) diff --git a/src/components/ReportActionItem/ReportPreview.tsx b/src/components/ReportActionItem/ReportPreview.tsx index 190343e48abd..4dabab867523 100644 --- a/src/components/ReportActionItem/ReportPreview.tsx +++ b/src/components/ReportActionItem/ReportPreview.tsx @@ -170,7 +170,7 @@ function ReportPreview({ // If iouReport is not available, get amount from the action message (Ex: "Domain20821's Workspace owes $33.00" or "paid ₫60" or "paid -₫60 elsewhere") let displayAmount = ''; - const actionMessage = action.message?.[0]?.text ?? ''; + const actionMessage = ReportActionUtils.getReportActionText(action); const splits = actionMessage.split(' '); splits.forEach((split) => { diff --git a/src/libs/ReportActionsUtils.ts b/src/libs/ReportActionsUtils.ts index 69917ce35c6b..f0774955726c 100644 --- a/src/libs/ReportActionsUtils.ts +++ b/src/libs/ReportActionsUtils.ts @@ -1,3 +1,4 @@ +import ExpensiMark from 'expensify-common/lib/ExpensiMark'; import fastMerge from 'expensify-common/lib/fastMerge'; import _ from 'lodash'; import lodashFindLast from 'lodash/findLast'; @@ -27,7 +28,7 @@ import * as Localize from './Localize'; import Log from './Log'; import type {MessageElementBase, MessageTextElement} from './MessageElement'; import * as PersonalDetailsUtils from './PersonalDetailsUtils'; -import type {OptimisticIOUReportAction} from './ReportUtils'; +import type {OptimisticIOUReportAction, PartialReportAction} from './ReportUtils'; type LastVisibleMessage = { lastMessageTranslationKey?: string; @@ -915,6 +916,16 @@ function getMemberChangeMessageElements(reportAction: OnyxEntry): ]; } +function getReportActionHtml(reportAction: PartialReportAction): string | undefined { + return reportAction?.message?.[0]?.html; +} + +function getReportActionText(reportAction: PartialReportAction): string { + const html = getReportActionHtml(reportAction); + const parser = new ExpensiMark(); + return html ? parser.htmlToText(html) : ''; +} + function getMemberChangeMessageFragment(reportAction: OnyxEntry): Message { const messageElements: readonly MemberChangeMessageElement[] = getMemberChangeMessageElements(reportAction); const html = messageElements @@ -932,7 +943,7 @@ function getMemberChangeMessageFragment(reportAction: OnyxEntry): return { html: `${html}`, - text: reportAction?.message?.[0] ? reportAction?.message?.[0]?.text : '', + text: reportAction?.message?.[0] ? getReportActionText(reportAction) : '', type: CONST.REPORT.MESSAGE.TYPE.COMMENT, }; } @@ -1151,6 +1162,8 @@ export { isCurrentActionUnread, isActionableJoinRequest, isActionableJoinRequestPending, + getReportActionText, + getReportActionHtml, }; export type {LastVisibleMessage}; diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 6197a29cd4a6..57b404d66d68 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -192,6 +192,8 @@ type OptimisticIOUReportAction = Pick< | 'childReportID' >; +type PartialReportAction = OnyxEntry | Partial | OptimisticIOUReportAction | OptimisticApprovedReportAction | OptimisticSubmittedReportAction | undefined; + type ReportRouteParams = { reportID: string; isSubReportPageRoute: boolean; @@ -2890,7 +2892,7 @@ function getReportName(report: OnyxEntry, policy: OnyxEntry = nu const parentReportActionMessage = ( ReportActionsUtils.isApprovedOrSubmittedReportAction(parentReportAction) ? ReportActionsUtils.getReportActionMessageText(parentReportAction) - : parentReportAction?.message?.[0]?.text ?? '' + : ReportActionsUtils.getReportActionText(parentReportAction) ).replace(/(\r\n|\n|\r)/gm, ' '); if (isAttachment && parentReportActionMessage) { return `[${Localize.translateLocal('common.attachment')}]`; @@ -4646,7 +4648,7 @@ function canFlagReportAction(reportAction: OnyxEntry, reportID: st reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.CHRONOSOOOLIST; if (ReportActionsUtils.isWhisperAction(reportAction)) { // Allow flagging welcome message whispers as they can be set by any room creator - if (report?.description && !isCurrentUserAction && isOriginalMessageHaveHtml && reportAction?.originalMessage?.html === report.description) { + if (report?.description && !isCurrentUserAction && isOriginalMessageHaveHtml && ReportActionsUtils.getReportActionHtml(reportAction) === report.description) { return true; } @@ -5199,7 +5201,7 @@ function getTaskAssigneeChatOnyxData( // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing const displayname = allPersonalDetails?.[assigneeAccountID]?.displayName || allPersonalDetails?.[assigneeAccountID]?.login || ''; optimisticAssigneeAddComment = buildOptimisticTaskCommentReportAction(taskReportID, title, assigneeAccountID, `assigned to ${displayname}`, parentReportID); - const lastAssigneeCommentText = formatReportLastMessageText(optimisticAssigneeAddComment.reportAction.message?.[0]?.text ?? ''); + const lastAssigneeCommentText = formatReportLastMessageText(ReportActionsUtils.getReportActionText(optimisticAssigneeAddComment.reportAction as ReportAction)); const optimisticAssigneeReport = { lastVisibleActionCreated: currentTime, lastMessageText: lastAssigneeCommentText, @@ -6038,4 +6040,5 @@ export type { Ancestor, OptimisticIOUReportAction, TransactionDetails, + PartialReportAction, }; diff --git a/src/libs/TaskUtils.ts b/src/libs/TaskUtils.ts index 19e1025a09c8..c60110527a60 100644 --- a/src/libs/TaskUtils.ts +++ b/src/libs/TaskUtils.ts @@ -6,6 +6,7 @@ import type {Report} from '@src/types/onyx'; import type {Message} from '@src/types/onyx/ReportAction'; import type ReportAction from '@src/types/onyx/ReportAction'; import * as Localize from './Localize'; +import {getReportActionText} from './ReportActionsUtils'; let allReports: OnyxCollection = {}; Onyx.connect({ @@ -29,7 +30,7 @@ function getTaskReportActionMessage(action: OnyxEntry): Pick; } else if (action.actionName === CONST.REPORT.ACTIONS.TYPE.HOLDCOMMENT) { - children = ; + children = ; } else if (action.actionName === CONST.REPORT.ACTIONS.TYPE.UNHOLD) { children = ; } else { diff --git a/tests/actions/IOUTest.ts b/tests/actions/IOUTest.ts index c8c74d4198ab..76ef36e710c5 100644 --- a/tests/actions/IOUTest.ts +++ b/tests/actions/IOUTest.ts @@ -2886,7 +2886,7 @@ describe('actions/IOU', () => { const ioupreview = ReportActionsUtils.getReportPreviewAction(chatReport?.reportID ?? '', iouReport?.reportID ?? ''); expect(ioupreview).toBeTruthy(); - expect(ioupreview?.message?.[0]?.text).toBe('rory@expensifail.com owes $300.00'); + expect(ReportActionsUtils.getReportActionText(ioupreview)).toBe('rory@expensifail.com owes $300.00'); // When we delete the first money request // @ts-expect-error TODO: Remove this once TestHelper (https://github.com/Expensify/App/issues/25318) is migrated to TypeScript. diff --git a/tests/ui/UnreadIndicatorsTest.tsx b/tests/ui/UnreadIndicatorsTest.tsx index 2aeee2cc77bf..7747441bb2b4 100644 --- a/tests/ui/UnreadIndicatorsTest.tsx +++ b/tests/ui/UnreadIndicatorsTest.tsx @@ -15,6 +15,7 @@ import LocalNotification from '@libs/Notification/LocalNotification'; import * as NumberUtils from '@libs/NumberUtils'; import * as Pusher from '@libs/Pusher/pusher'; import PusherConnectionManager from '@libs/PusherConnectionManager'; +import {getReportActionText} from '@libs/ReportActionsUtils'; import FontUtils from '@styles/utils/FontUtils'; import * as AppActions from '@userActions/App'; import * as Report from '@userActions/Report'; @@ -604,7 +605,7 @@ describe('Unread Indicators', () => { // Simulate the response from the server so that the comment can be deleted in this test lastReportAction = reportActions ? CollectionUtils.lastItem(reportActions) : undefined; Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT}${REPORT_ID}`, { - lastMessageText: lastReportAction?.message?.[0]?.text, + lastMessageText: getReportActionText(lastReportAction), lastVisibleActionCreated: DateUtils.getDBTime(lastReportAction?.timestamp), lastActorAccountID: lastReportAction?.actorAccountID, reportID: REPORT_ID, From 9c9cd8459b79a3aaa3aa1230cf73a3586598c6de Mon Sep 17 00:00:00 2001 From: nkdengineer Date: Sat, 13 Apr 2024 17:21:53 +0700 Subject: [PATCH 02/45] refactor using getReportActionMessage --- .../extractAttachmentsFromReport.ts | 4 +-- src/libs/ReportActionsUtils.ts | 36 ++++++++++++------- src/libs/ReportUtils.ts | 20 +++++------ src/libs/TaskUtils.ts | 4 +-- src/libs/actions/IOU.ts | 28 +++++++-------- src/libs/actions/Report.ts | 12 +++---- src/libs/actions/ReportActions.ts | 2 +- src/pages/home/report/ReportActionItem.tsx | 2 +- .../home/report/ReportActionItemMessage.tsx | 2 +- .../report/ReportActionItemMessageEdit.tsx | 2 +- .../home/report/ReportActionItemSingle.tsx | 3 +- src/pages/home/sidebar/SidebarLinksData.tsx | 3 +- tests/actions/IOUTest.ts | 4 +-- tests/perf-test/SidebarUtils.perf-test.ts | 3 +- 14 files changed, 70 insertions(+), 55 deletions(-) diff --git a/src/components/Attachments/AttachmentCarousel/extractAttachmentsFromReport.ts b/src/components/Attachments/AttachmentCarousel/extractAttachmentsFromReport.ts index d1185f88ccd5..d62ee6fefdeb 100644 --- a/src/components/Attachments/AttachmentCarousel/extractAttachmentsFromReport.ts +++ b/src/components/Attachments/AttachmentCarousel/extractAttachmentsFromReport.ts @@ -76,9 +76,9 @@ function extractAttachmentsFromReport(parentReportAction?: OnyxEntry', `data-flagged="${hasBeenFlagged}" data-id="${action.reportActionID}"/>`); + const html = (ReportActionsUtils.getReportActionMessage(action)?.html ?? '').replace('/>', `data-flagged="${hasBeenFlagged}" data-id="${action.reportActionID}"/>`); htmlParser.write(html); }); htmlParser.end(); diff --git a/src/libs/ReportActionsUtils.ts b/src/libs/ReportActionsUtils.ts index f0774955726c..6e8d03861383 100644 --- a/src/libs/ReportActionsUtils.ts +++ b/src/libs/ReportActionsUtils.ts @@ -17,7 +17,7 @@ import type { OriginalMessageReimbursementDequeued, } from '@src/types/onyx/OriginalMessage'; import type Report from '@src/types/onyx/Report'; -import type {Message, ReportActionBase, ReportActions} from '@src/types/onyx/ReportAction'; +import type {Message, OriginalMessage, ReportActionBase, ReportActions} from '@src/types/onyx/ReportAction'; import type ReportAction from '@src/types/onyx/ReportAction'; import type {EmptyObject} from '@src/types/utils/EmptyObject'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; @@ -108,19 +108,23 @@ function isDeletedAction(reportAction: OnyxEntry): boolean { - return (reportAction?.message?.[0]?.isDeletedParentAction ?? false) && (reportAction?.childVisibleActionCount ?? 0) > 0; + return (getReportActionMessage(reportAction)?.isDeletedParentAction ?? false) && (reportAction?.childVisibleActionCount ?? 0) > 0; } function isReversedTransaction(reportAction: OnyxEntry) { - return (reportAction?.message?.[0]?.isReversedTransaction ?? false) && ((reportAction as ReportAction)?.childVisibleActionCount ?? 0) > 0; + return (getReportActionMessage(reportAction)?.isReversedTransaction ?? false) && ((reportAction as ReportAction)?.childVisibleActionCount ?? 0) > 0; } function isPendingRemove(reportAction: OnyxEntry | EmptyObject): boolean { if (isEmptyObject(reportAction)) { return false; } - return reportAction?.message?.[0]?.moderationDecision?.decision === CONST.MODERATION.MODERATOR_DECISION_PENDING_REMOVE; + return getReportActionMessage(reportAction)?.moderationDecision?.decision === CONST.MODERATION.MODERATOR_DECISION_PENDING_REMOVE; } function isMoneyRequestAction(reportAction: OnyxEntry): reportAction is ReportAction & OriginalMessageIOU { @@ -381,7 +385,7 @@ function getMostRecentIOURequestActionID(reportActions: ReportAction[] | null): * Returns array of links inside a given report action */ function extractLinksFromMessageHtml(reportAction: OnyxEntry): string[] { - const htmlContent = reportAction?.message?.[0]?.html; + const htmlContent = getReportActionMessage(reportAction)?.html; // Regex to get link in href prop inside of component const regex = /]*?\s+)?href="([^"]*)"/gi; @@ -582,7 +586,7 @@ function replaceBaseURLInPolicyChangeLogAction(reportAction: ReportAction): Repo } if (updatedReportAction.message[0]) { - updatedReportAction.message[0].html = reportAction.message?.[0]?.html?.replace('%baseURL', environmentURL); + updatedReportAction.message[0].html = getReportActionMessage(reportAction)?.html?.replace('%baseURL', environmentURL); } return updatedReportAction; @@ -600,7 +604,7 @@ function getLastVisibleAction(reportID: string, actionsToMerge: OnyxCollection = {}, reportAction: OnyxEntry | undefined = undefined): LastVisibleMessage { const lastVisibleAction = reportAction ?? getLastVisibleAction(reportID, actionsToMerge); - const message = lastVisibleAction?.message?.[0]; + const message = getReportActionMessage(lastVisibleAction); if (message && isReportMessageAttachment(message)) { return { @@ -786,7 +790,7 @@ function isCreatedTaskReportAction(reportAction: OnyxEntry): boole * A helper method to identify if the message is deleted or not. */ function isMessageDeleted(reportAction: OnyxEntry): boolean { - return reportAction?.message?.[0]?.isDeletedParentAction ?? false; + return getReportActionMessage(reportAction)?.isDeletedParentAction ?? false; } /** @@ -836,7 +840,7 @@ function getAllReportActions(reportID: string): ReportActions { * */ function isReportActionAttachment(reportAction: OnyxEntry): boolean { - const message = reportAction?.message?.[0]; + const message = getReportActionMessage(reportAction); if (reportAction && ('isAttachment' in reportAction || 'attachmentInfo' in reportAction)) { return reportAction?.isAttachment ?? !!reportAction?.attachmentInfo ?? false; @@ -916,8 +920,10 @@ function getMemberChangeMessageElements(reportAction: OnyxEntry): ]; } -function getReportActionHtml(reportAction: PartialReportAction): string | undefined { - return reportAction?.message?.[0]?.html; +function getReportActionHtml(reportAction: PartialReportAction) { + // @ts-expect-error Handle refactor not using message array, will remove when Back End is changed complete https://github.com/Expensify/App/issues/39797 + // eslint-disable-next-line @typescript-eslint/no-unsafe-return + return reportAction?.message?.html || reportAction?.message?.[0]?.html; } function getReportActionText(reportAction: PartialReportAction): string { @@ -926,6 +932,10 @@ function getReportActionText(reportAction: PartialReportAction): string { return html ? parser.htmlToText(html) : ''; } +function getReportActionOriginalMessage(reportAction: PartialReportAction) { + return (reportAction?.originalMessage ?? reportAction?.message?.[0] ?? reportAction?.message) as OriginalMessage; +} + function getMemberChangeMessageFragment(reportAction: OnyxEntry): Message { const messageElements: readonly MemberChangeMessageElement[] = getMemberChangeMessageElements(reportAction); const html = messageElements @@ -943,7 +953,7 @@ function getMemberChangeMessageFragment(reportAction: OnyxEntry): return { html: `${html}`, - text: reportAction?.message?.[0] ? getReportActionText(reportAction) : '', + text: getReportActionMessage(reportAction) ? getReportActionText(reportAction) : '', type: CONST.REPORT.MESSAGE.TYPE.COMMENT, }; } @@ -1164,6 +1174,8 @@ export { isActionableJoinRequestPending, getReportActionText, getReportActionHtml, + getReportActionMessage, + getReportActionOriginalMessage, }; export type {LastVisibleMessage}; diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 57b404d66d68..cefe340ab51f 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -711,7 +711,7 @@ function isTaskReport(report: OnyxEntry): boolean { * In this case, we have added the key to the report itself */ function isCanceledTaskReport(report: OnyxEntry | EmptyObject = {}, parentReportAction: OnyxEntry | EmptyObject = {}): boolean { - if (!isEmptyObject(parentReportAction) && (parentReportAction?.message?.[0]?.isDeletedParentAction ?? false)) { + if (!isEmptyObject(parentReportAction) && (ReportActionsUtils.getReportActionMessage(parentReportAction)?.isDeletedParentAction ?? false)) { return true; } @@ -2612,7 +2612,7 @@ function getReportPreviewMessage( isForListPreview = false, originalReportAction: OnyxEntry | EmptyObject = iouReportAction, ): string { - const reportActionMessage = iouReportAction?.message?.[0]?.html ?? ''; + const reportActionMessage = ReportActionsUtils.getReportActionMessage(iouReportAction)?.html ?? ''; if (isEmptyObject(report) || !report?.reportID) { // The iouReport is not found locally after SignIn because the OpenApp API won't return iouReports if they're settled @@ -2884,7 +2884,7 @@ function getReportName(report: OnyxEntry, policy: OnyxEntry = nu return formattedName; } - if (parentReportAction?.message?.[0]?.isDeletedParentAction) { + if (ReportActionsUtils.getReportActionMessage(parentReportAction)?.isDeletedParentAction) { return Localize.translateLocal('parentReportAction.deletedMessage'); } @@ -2898,9 +2898,9 @@ function getReportName(report: OnyxEntry, policy: OnyxEntry = nu return `[${Localize.translateLocal('common.attachment')}]`; } if ( - parentReportAction?.message?.[0]?.moderationDecision?.decision === CONST.MODERATION.MODERATOR_DECISION_PENDING_HIDE || - parentReportAction?.message?.[0]?.moderationDecision?.decision === CONST.MODERATION.MODERATOR_DECISION_HIDDEN || - parentReportAction?.message?.[0]?.moderationDecision?.decision === CONST.MODERATION.MODERATOR_DECISION_PENDING_REMOVE + ReportActionsUtils.getReportActionMessage(parentReportAction)?.moderationDecision?.decision === CONST.MODERATION.MODERATOR_DECISION_PENDING_HIDE || + ReportActionsUtils.getReportActionMessage(parentReportAction)?.moderationDecision?.decision === CONST.MODERATION.MODERATOR_DECISION_HIDDEN || + ReportActionsUtils.getReportActionMessage(parentReportAction)?.moderationDecision?.decision === CONST.MODERATION.MODERATOR_DECISION_PENDING_REMOVE ) { return Localize.translateLocal('parentReportAction.hiddenMessage'); } @@ -3207,15 +3207,15 @@ function updateOptimisticParentReportAction(parentReportAction: OnyxEntry = {}; Onyx.connect({ @@ -31,7 +31,7 @@ function getTaskReportActionMessage(action: OnyxEntry): Pick 0) { @@ -4402,7 +4402,7 @@ function getSendMoneyParams( value: { ...optimisticIOUReport, lastMessageText: ReportActionsUtils.getReportActionText(optimisticIOUReportAction), - lastMessageHtml: optimisticIOUReportAction.message?.[0]?.html, + lastMessageHtml: ReportActionsUtils.getReportActionMessage(optimisticIOUReportAction)?.html, }, }; const optimisticTransactionThreadData: OnyxUpdate = { @@ -4642,7 +4642,7 @@ function getPayMoneyRequestParams( hasOutstandingChildRequest: false, iouReportID: null, lastMessageText: ReportActionsUtils.getReportActionText(optimisticIOUReportAction), - lastMessageHtml: optimisticIOUReportAction.message?.[0]?.html, + lastMessageHtml: ReportActionsUtils.getReportActionMessage(optimisticIOUReportAction)?.html, }, }, { @@ -4661,7 +4661,7 @@ function getPayMoneyRequestParams( value: { ...iouReport, lastMessageText: ReportActionsUtils.getReportActionText(optimisticIOUReportAction), - lastMessageHtml: optimisticIOUReportAction.message?.[0]?.html, + lastMessageHtml: ReportActionsUtils.getReportActionMessage(optimisticIOUReportAction)?.html, hasOutstandingChildRequest: false, statusNum: CONST.REPORT.STATUS_NUM.REIMBURSED, pendingFields: { @@ -4883,7 +4883,7 @@ function approveMoneyRequest(expenseReport: OnyxTypes.Report | EmptyObject, full value: { ...expenseReport, lastMessageText: ReportActionsUtils.getReportActionText(optimisticApprovedReportAction), - lastMessageHtml: optimisticApprovedReportAction.message?.[0]?.html, + lastMessageHtml: ReportActionsUtils.getReportActionMessage(optimisticApprovedReportAction)?.html, stateNum: CONST.REPORT.STATE_NUM.APPROVED, statusNum: CONST.REPORT.STATUS_NUM.APPROVED, pendingFields: { @@ -4992,7 +4992,7 @@ function submitReport(expenseReport: OnyxTypes.Report) { value: { ...expenseReport, lastMessageText: ReportActionsUtils.getReportActionText(optimisticSubmittedReportAction), - lastMessageHtml: optimisticSubmittedReportAction.message?.[0]?.html ?? '', + lastMessageHtml: ReportActionsUtils.getReportActionMessage(optimisticSubmittedReportAction)?.html ?? '', stateNum: CONST.REPORT.STATE_NUM.SUBMITTED, statusNum: CONST.REPORT.STATUS_NUM.SUBMITTED, }, @@ -5118,7 +5118,7 @@ function cancelPayment(expenseReport: OnyxTypes.Report, chatReport: OnyxTypes.Re value: { ...expenseReport, lastMessageText: ReportActionsUtils.getReportActionText(optimisticReportAction), - lastMessageHtml: optimisticReportAction.message?.[0]?.html, + lastMessageHtml: ReportActionsUtils.getReportActionMessage(optimisticReportAction)?.html, stateNum, statusNum, }, diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index a1a2dca64f7d..abc27d2a49f6 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -400,7 +400,7 @@ function addActions(reportID: string, text = '', file?: FileObject) { // Always prefer the file as the last action over text const lastAction = attachmentAction ?? reportCommentAction; const currentTime = DateUtils.getDBTimeWithSkew(); - const lastComment = lastAction?.message?.[0]; + const lastComment = ReportActionsUtils.getReportActionMessage(lastAction); const lastCommentText = ReportUtils.formatReportLastMessageText(lastComment?.text ?? ''); const optimisticReport: Partial = { @@ -1302,7 +1302,7 @@ function editReportComment(reportID: string, originalReportAction: OnyxEntry = { [reportActionID]: { pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE, @@ -2606,7 +2606,7 @@ function openLastOpenedPublicRoom(lastOpenedPublicRoomID: string) { /** Flag a comment as offensive */ function flagComment(reportID: string, reportAction: OnyxEntry, severity: string) { const originalReportID = ReportUtils.getOriginalReportID(reportID, reportAction); - const message = reportAction?.message?.[0]; + const message = ReportActionsUtils.getReportActionMessage(reportAction); if (!message) { return; @@ -2794,7 +2794,7 @@ function completeEngagementModal(text: string, choice: ValueOf, resolution: ValueOf) { - const message = reportAction?.message?.[0]; + const message = ReportActionsUtils.getReportActionMessage(reportAction); if (!message) { return; } diff --git a/src/libs/actions/ReportActions.ts b/src/libs/actions/ReportActions.ts index ae886e0309dc..3416a99b41ce 100644 --- a/src/libs/actions/ReportActions.ts +++ b/src/libs/actions/ReportActions.ts @@ -28,7 +28,7 @@ function clearReportActionErrors(reportID: string, reportAction: ReportAction, k } // Delete the failed task report too - const taskReportID = reportAction.message?.[0]?.taskReportID; + const taskReportID = ReportActionUtils.getReportActionMessage(reportAction)?.taskReportID; if (taskReportID && ReportActionUtils.isCreatedTaskReportAction(reportAction)) { Report.deleteReport(taskReportID); } diff --git a/src/pages/home/report/ReportActionItem.tsx b/src/pages/home/report/ReportActionItem.tsx index 1318bfa803c2..4a2712ced35f 100644 --- a/src/pages/home/report/ReportActionItem.tsx +++ b/src/pages/home/report/ReportActionItem.tsx @@ -277,7 +277,7 @@ function ReportActionItem({ // Hide the message if it is being moderated for a higher offense, or is hidden by a moderator // Removed messages should not be shown anyway and should not need this flow - const latestDecision = action.message?.[0]?.moderationDecision?.decision ?? ''; + const latestDecision = ReportActionsUtils.getReportActionMessage(action)?.moderationDecision?.decision ?? ''; useEffect(() => { if (action.actionName !== CONST.REPORT.ACTIONS.TYPE.ADDCOMMENT) { return; diff --git a/src/pages/home/report/ReportActionItemMessage.tsx b/src/pages/home/report/ReportActionItemMessage.tsx index b2f120f16ef4..891bf2820681 100644 --- a/src/pages/home/report/ReportActionItemMessage.tsx +++ b/src/pages/home/report/ReportActionItemMessage.tsx @@ -100,7 +100,7 @@ function ReportActionItemMessage({action, transaction, displayAsGroup, reportID, // to decide if the fragment should be from left to right for RTL display names e.g. Arabic for proper // formatting. isFragmentContainingDisplayName={index === 0} - moderationDecision={action.message?.[0]?.moderationDecision?.decision} + moderationDecision={ReportActionsUtils.getReportActionMessage(action)?.moderationDecision?.decision} /> )); diff --git a/src/pages/home/report/ReportActionItemMessageEdit.tsx b/src/pages/home/report/ReportActionItemMessageEdit.tsx index fc3c92434fc4..680e6e41bf35 100644 --- a/src/pages/home/report/ReportActionItemMessageEdit.tsx +++ b/src/pages/home/report/ReportActionItemMessageEdit.tsx @@ -118,7 +118,7 @@ function ReportActionItemMessageEdit( useEffect(() => { const parser = new ExpensiMark(); - const originalMessage = parser.htmlToMarkdown(action.message?.[0]?.html ?? ''); + const originalMessage = parser.htmlToMarkdown(ReportActionsUtils.getReportActionMessage(action)?.html ?? ''); if ( ReportActionsUtils.isDeletedAction(action) || Boolean(action.message && draftMessage === originalMessage) || diff --git a/src/pages/home/report/ReportActionItemSingle.tsx b/src/pages/home/report/ReportActionItemSingle.tsx index 1e0dc432b3fc..fd09f8c13fc0 100644 --- a/src/pages/home/report/ReportActionItemSingle.tsx +++ b/src/pages/home/report/ReportActionItemSingle.tsx @@ -18,6 +18,7 @@ import useThemeStyles from '@hooks/useThemeStyles'; import ControlSelection from '@libs/ControlSelection'; import DateUtils from '@libs/DateUtils'; import Navigation from '@libs/Navigation/Navigation'; +import {getReportActionMessage} from '@libs/ReportActionsUtils'; import * as ReportUtils from '@libs/ReportUtils'; import * as UserUtils from '@libs/UserUtils'; import CONST from '@src/CONST'; @@ -245,7 +246,7 @@ function ReportActionItemSingle({ delegateAccountID={action?.delegateAccountID} isSingleLine actorIcon={icon} - moderationDecision={action?.message?.[0]?.moderationDecision?.decision} + moderationDecision={getReportActionMessage(action)?.moderationDecision?.decision} /> ))} diff --git a/src/pages/home/sidebar/SidebarLinksData.tsx b/src/pages/home/sidebar/SidebarLinksData.tsx index e56962a331a2..4e5b7ab3c690 100644 --- a/src/pages/home/sidebar/SidebarLinksData.tsx +++ b/src/pages/home/sidebar/SidebarLinksData.tsx @@ -16,6 +16,7 @@ import useNetwork from '@hooks/useNetwork'; import usePrevious from '@hooks/usePrevious'; import useThemeStyles from '@hooks/useThemeStyles'; import {getPolicyMembersByIdWithoutCurrentUser} from '@libs/PolicyUtils'; +import {getReportActionMessage} from '@libs/ReportActionsUtils'; import * as ReportUtils from '@libs/ReportUtils'; import SidebarUtils from '@libs/SidebarUtils'; import * as Policy from '@userActions/Policy'; @@ -226,7 +227,7 @@ const reportActionsSelector = (reportActions: OnyxEntry (reportActions && Object.values(reportActions).map((reportAction) => { const {reportActionID, actionName, errors = [], originalMessage} = reportAction; - const decision = reportAction.message?.[0]?.moderationDecision?.decision; + const decision = getReportActionMessage(reportAction)?.moderationDecision?.decision; return { reportActionID, diff --git a/tests/actions/IOUTest.ts b/tests/actions/IOUTest.ts index 76ef36e710c5..c2539ae0c2e6 100644 --- a/tests/actions/IOUTest.ts +++ b/tests/actions/IOUTest.ts @@ -2832,7 +2832,7 @@ describe('actions/IOU', () => { callback: (reportActionsForReport) => { Onyx.disconnect(connectionID); createIOUAction = Object.values(reportActionsForReport ?? {}).find((reportAction) => reportAction.actionName === CONST.REPORT.ACTIONS.TYPE.IOU) ?? null; - expect(createIOUAction?.message?.[0]?.isDeletedParentAction).toBeTruthy(); + expect(ReportActionsUtils.getReportActionMessage(createIOUAction)?.isDeletedParentAction).toBeTruthy(); resolve(); }, }); @@ -2851,7 +2851,7 @@ describe('actions/IOU', () => { callback: (reportActionsForReport) => { Onyx.disconnect(connectionID); createIOUAction = Object.values(reportActionsForReport ?? {}).find((reportAction) => reportAction.actionName === CONST.REPORT.ACTIONS.TYPE.IOU) ?? null; - expect(createIOUAction?.message?.[0]?.isDeletedParentAction).toBeTruthy(); + expect(ReportActionsUtils.getReportActionMessage(createIOUAction)?.isDeletedParentAction).toBeTruthy(); resolve(); }, }); diff --git a/tests/perf-test/SidebarUtils.perf-test.ts b/tests/perf-test/SidebarUtils.perf-test.ts index 8566abb97c7f..06073483f86d 100644 --- a/tests/perf-test/SidebarUtils.perf-test.ts +++ b/tests/perf-test/SidebarUtils.perf-test.ts @@ -2,6 +2,7 @@ import {rand} from '@ngneat/falso'; import type {OnyxCollection} from 'react-native-onyx'; import Onyx from 'react-native-onyx'; import {measureFunction} from 'reassure'; +import {getReportActionMessage} from '@libs/ReportActionsUtils'; import SidebarUtils from '@libs/SidebarUtils'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; @@ -60,7 +61,7 @@ const allReportActions = Object.fromEntries( message: [ { moderationDecision: { - decision: reportActions[key].message?.[0]?.moderationDecision?.decision, + decision: getReportActionMessage(reportActions[key])?.moderationDecision?.decision, }, }, ], From 342f51f7fe97848a7e7df77d3c85e21a63689bd3 Mon Sep 17 00:00:00 2001 From: nkdengineer Date: Wed, 8 May 2024 15:07:16 +0700 Subject: [PATCH 03/45] fix ts check --- src/libs/actions/Report.ts | 4 ++-- src/pages/home/report/ReportActionItem.tsx | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index 8ae0a35a5509..42f3203a911e 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -2895,7 +2895,7 @@ function flagComment(reportID: string, reportAction: OnyxEntry, se const originalReportID = ReportUtils.getOriginalReportID(reportID, reportAction); const message = ReportActionsUtils.getReportActionMessage(reportAction); - if (!message) { + if (!message || !reportAction) { return; } @@ -3604,7 +3604,7 @@ function clearNewRoomFormError() { function resolveActionableMentionWhisper(reportId: string, reportAction: OnyxEntry, resolution: ValueOf) { const message = ReportActionsUtils.getReportActionMessage(reportAction); - if (!message) { + if (!message || !reportAction) { return; } diff --git a/src/pages/home/report/ReportActionItem.tsx b/src/pages/home/report/ReportActionItem.tsx index e669d31c7d99..811dc55a6f60 100644 --- a/src/pages/home/report/ReportActionItem.tsx +++ b/src/pages/home/report/ReportActionItem.tsx @@ -616,8 +616,8 @@ function ReportActionItem({ // This handles all historical actions from OldDot that we just want to display the message text children = ; } else if (action.actionName === CONST.REPORT.ACTIONS.TYPE.HOLD) { - children = ; - } else if (action.actionName === CONST.REPORT.ACTIONS.TYPE.HOLDCOMMENT) { + children = ; + } else if (action.actionName === CONST.REPORT.ACTIONS.TYPE.HOLD_COMMENT) { children = ; } else if (action.actionName === CONST.REPORT.ACTIONS.TYPE.UNHOLD) { children = ; From 11961e4289ec4735f0f6f28f17acb1167498e7a3 Mon Sep 17 00:00:00 2001 From: nkdengineer Date: Mon, 27 May 2024 12:24:10 +0700 Subject: [PATCH 04/45] start removing originalMessage --- src/components/ArchivedReportFooter.tsx | 3 ++- src/components/AttachmentModal.tsx | 6 +++++- src/components/LHNOptionsList/LHNOptionsList.tsx | 8 ++++++-- src/components/MoneyReportHeader.tsx | 12 +++++++++--- src/components/MoneyRequestHeader.tsx | 12 ++++++++---- src/libs/ReportActionsUtils.ts | 4 ++-- 6 files changed, 32 insertions(+), 13 deletions(-) diff --git a/src/components/ArchivedReportFooter.tsx b/src/components/ArchivedReportFooter.tsx index 9713e40136a2..6bc1784310fd 100644 --- a/src/components/ArchivedReportFooter.tsx +++ b/src/components/ArchivedReportFooter.tsx @@ -11,6 +11,7 @@ import * as ReportUtils from '@libs/ReportUtils'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import type {PersonalDetailsList, Report, ReportAction} from '@src/types/onyx'; +import {Closed} from '@src/types/onyx/OriginalMessage'; import Banner from './Banner'; type ArchivedReportFooterOnyxProps = { @@ -30,7 +31,7 @@ function ArchivedReportFooter({report, reportClosedAction, personalDetails = {}} const styles = useThemeStyles(); const {translate} = useLocalize(); - const originalMessage = reportClosedAction?.actionName === CONST.REPORT.ACTIONS.TYPE.CLOSED ? reportClosedAction.originalMessage : null; + const originalMessage = reportClosedAction?.actionName === CONST.REPORT.ACTIONS.TYPE.CLOSED ? ReportActionsUtils.getReportActionOriginalMessage(reportClosedAction) : null; const archiveReason = originalMessage?.reason ?? CONST.REPORT.ARCHIVE_REASON.DEFAULT; const actorPersonalDetails = personalDetails?.[reportClosedAction?.actorAccountID ?? 0]; let displayName = PersonalDetailsUtils.getDisplayNameOrDefault(actorPersonalDetails); diff --git a/src/components/AttachmentModal.tsx b/src/components/AttachmentModal.tsx index de98ba79d23c..d5b7457a6dd1 100644 --- a/src/components/AttachmentModal.tsx +++ b/src/components/AttachmentModal.tsx @@ -25,6 +25,7 @@ import type {TranslationPaths} from '@src/languages/types'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import type * as OnyxTypes from '@src/types/onyx'; +import {IOUMessage} from '@src/types/onyx/OriginalMessage'; import type {EmptyObject} from '@src/types/utils/EmptyObject'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; import type ModalType from '@src/types/utils/ModalType'; @@ -604,7 +605,10 @@ export default withOnyx({ transaction: { key: ({report}) => { const parentReportAction = ReportActionsUtils.getReportAction(report?.parentReportID ?? '', report?.parentReportActionID ?? ''); - const transactionID = parentReportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.IOU ? parentReportAction?.originalMessage.IOUTransactionID ?? '0' : '0'; + const transactionID = + parentReportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.IOU + ? ReportActionsUtils.getReportActionOriginalMessage(parentReportAction).IOUTransactionID ?? '0' + : '0'; return `${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`; }, }, diff --git a/src/components/LHNOptionsList/LHNOptionsList.tsx b/src/components/LHNOptionsList/LHNOptionsList.tsx index 8c43ae542932..7a85d5302854 100644 --- a/src/components/LHNOptionsList/LHNOptionsList.tsx +++ b/src/components/LHNOptionsList/LHNOptionsList.tsx @@ -22,6 +22,7 @@ import * as ReportActionsUtils from '@libs/ReportActionsUtils'; import variables from '@styles/variables'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; +import {IOUMessage} from '@src/types/onyx/OriginalMessage'; import OptionRowLHNData from './OptionRowLHNData'; import type {LHNOptionsListOnyxProps, LHNOptionsListProps, RenderItemProps} from './types'; @@ -111,7 +112,10 @@ function LHNOptionsList({ const itemParentReportActions = reportActions?.[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${itemFullReport?.parentReportID}`] ?? null; const itemParentReportAction = itemParentReportActions?.[itemFullReport?.parentReportActionID ?? ''] ?? null; const itemPolicy = policy?.[`${ONYXKEYS.COLLECTION.POLICY}${itemFullReport?.policyID}`] ?? null; - const transactionID = itemParentReportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.IOU ? itemParentReportAction.originalMessage.IOUTransactionID ?? '' : ''; + const transactionID = + itemParentReportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.IOU + ? ReportActionsUtils.getReportActionOriginalMessage(itemParentReportAction).IOUTransactionID ?? '' + : ''; const itemTransaction = transactions?.[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`] ?? null; const hasDraftComment = DraftCommentUtils.isValidDraftComment(draftComments?.[`${ONYXKEYS.COLLECTION.REPORT_DRAFT_COMMENT}${reportID}`]); const sortedReportActions = ReportActionsUtils.getSortedReportActionsForDisplay(itemReportActions); @@ -121,7 +125,7 @@ function LHNOptionsList({ let lastReportActionTransactionID = ''; if (lastReportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.IOU) { - lastReportActionTransactionID = lastReportAction.originalMessage?.IOUTransactionID ?? ''; + lastReportActionTransactionID = ReportActionsUtils.getReportActionOriginalMessage(lastReportAction)?.IOUTransactionID ?? ''; } const lastReportActionTransaction = transactions?.[`${ONYXKEYS.COLLECTION.TRANSACTION}${lastReportActionTransactionID}`] ?? {}; diff --git a/src/components/MoneyReportHeader.tsx b/src/components/MoneyReportHeader.tsx index c9e73a125fee..e257cdb14dd9 100644 --- a/src/components/MoneyReportHeader.tsx +++ b/src/components/MoneyReportHeader.tsx @@ -18,7 +18,7 @@ import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import type * as OnyxTypes from '@src/types/onyx'; -import type {PaymentMethodType} from '@src/types/onyx/OriginalMessage'; +import type {IOUMessage, PaymentMethodType} from '@src/types/onyx/OriginalMessage'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; import Button from './Button'; import ConfirmModal from './ConfirmModal'; @@ -160,7 +160,10 @@ function MoneyReportHeader({ const deleteTransaction = useCallback(() => { if (requestParentReportAction) { - const iouTransactionID = requestParentReportAction.actionName === CONST.REPORT.ACTIONS.TYPE.IOU ? requestParentReportAction.originalMessage?.IOUTransactionID ?? '' : ''; + const iouTransactionID = + requestParentReportAction.actionName === CONST.REPORT.ACTIONS.TYPE.IOU + ? ReportActionsUtils.getReportActionOriginalMessage(requestParentReportAction)?.IOUTransactionID ?? '' + : ''; if (ReportActionsUtils.isTrackExpenseAction(requestParentReportAction)) { IOU.deleteTrackExpense(moneyRequestReport?.reportID ?? '', iouTransactionID, requestParentReportAction, true); return; @@ -175,7 +178,10 @@ function MoneyReportHeader({ if (!requestParentReportAction) { return; } - const iouTransactionID = requestParentReportAction.actionName === CONST.REPORT.ACTIONS.TYPE.IOU ? requestParentReportAction.originalMessage?.IOUTransactionID ?? '' : ''; + const iouTransactionID = + requestParentReportAction.actionName === CONST.REPORT.ACTIONS.TYPE.IOU + ? ReportActionsUtils.getReportActionOriginalMessage(requestParentReportAction)?.IOUTransactionID ?? '' + : ''; const reportID = transactionThreadReport?.reportID ?? ''; TransactionActions.markAsCash(iouTransactionID, reportID); diff --git a/src/components/MoneyRequestHeader.tsx b/src/components/MoneyRequestHeader.tsx index 13e8eb7be432..d3c43e04c337 100644 --- a/src/components/MoneyRequestHeader.tsx +++ b/src/components/MoneyRequestHeader.tsx @@ -19,7 +19,7 @@ import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import type {Policy, Report, ReportAction, ReportActions, Session, Transaction, TransactionViolations} from '@src/types/onyx'; -import type {OriginalMessageIOU} from '@src/types/onyx/OriginalMessage'; +import type {IOUMessage, OriginalMessageIOU} from '@src/types/onyx/OriginalMessage'; import type IconAsset from '@src/types/utils/IconAsset'; import Button from './Button'; import ConfirmModal from './ConfirmModal'; @@ -101,7 +101,10 @@ function MoneyRequestHeader({ const deleteTransaction = useCallback(() => { if (parentReportAction) { - const iouTransactionID = parentReportAction.actionName === CONST.REPORT.ACTIONS.TYPE.IOU ? parentReportAction.originalMessage?.IOUTransactionID ?? '' : ''; + const iouTransactionID = + parentReportAction.actionName === CONST.REPORT.ACTIONS.TYPE.IOU + ? ReportActionsUtils.getReportActionOriginalMessage(parentReportAction)?.IOUTransactionID ?? '' + : ''; if (ReportActionsUtils.isTrackExpenseAction(parentReportAction)) { IOU.deleteTrackExpense(parentReport?.reportID ?? '', iouTransactionID, parentReportAction, true); return; @@ -125,7 +128,8 @@ function MoneyRequestHeader({ const canDeleteRequest = isActionOwner && (ReportUtils.canAddOrDeleteTransactions(moneyRequestReport) || ReportUtils.isTrackExpenseReport(report)) && !isDeletedParentAction; const changeMoneyRequestStatus = () => { - const iouTransactionID = parentReportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.IOU ? parentReportAction.originalMessage?.IOUTransactionID ?? '' : ''; + const iouTransactionID = + parentReportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.IOU ? ReportActionsUtils.getReportActionOriginalMessage(parentReportAction)?.IOUTransactionID ?? '' : ''; if (isOnHold) { IOU.unholdRequest(iouTransactionID, report?.reportID); @@ -302,7 +306,7 @@ const MoneyRequestHeaderWithTransaction = withOnyx { const parentReportAction = (report.parentReportActionID && parentReportActions ? parentReportActions[report.parentReportActionID] : {}) as ReportAction & OriginalMessageIOU; - return `${ONYXKEYS.COLLECTION.TRANSACTION}${parentReportAction?.originalMessage?.IOUTransactionID ?? 0}`; + return `${ONYXKEYS.COLLECTION.TRANSACTION}${ReportActionsUtils.getReportActionOriginalMessage(parentReportAction)?.IOUTransactionID ?? 0}`; }, }, shownHoldUseExplanation: { diff --git a/src/libs/ReportActionsUtils.ts b/src/libs/ReportActionsUtils.ts index acfe19184726..202597315835 100644 --- a/src/libs/ReportActionsUtils.ts +++ b/src/libs/ReportActionsUtils.ts @@ -1018,8 +1018,8 @@ function getReportActionText(reportAction: PartialReportAction): string { return html ? parser.htmlToText(html) : ''; } -function getReportActionOriginalMessage(reportAction: PartialReportAction) { - return (reportAction?.originalMessage ?? reportAction?.message?.[0] ?? reportAction?.message) as OriginalMessage; +function getReportActionOriginalMessage(reportAction: PartialReportAction) { + return (reportAction?.originalMessage ?? reportAction?.message?.[0] ?? reportAction?.message) as T; } function getMemberChangeMessageFragment(reportAction: OnyxEntry): Message { From 04d072e131cc530e8c25f1c68c54f2197a84ebc6 Mon Sep 17 00:00:00 2001 From: nkdengineer Date: Mon, 27 May 2024 12:36:07 +0700 Subject: [PATCH 05/45] fix lint --- src/components/ArchivedReportFooter.tsx | 2 +- src/components/AttachmentModal.tsx | 2 +- src/components/LHNOptionsList/LHNOptionsList.tsx | 2 +- src/components/ReportActionItem/ChronosOOOListActions.tsx | 3 ++- src/components/ReportActionItem/MoneyRequestView.tsx | 8 ++++++-- src/libs/ReportActionsUtils.ts | 6 +++--- 6 files changed, 14 insertions(+), 9 deletions(-) diff --git a/src/components/ArchivedReportFooter.tsx b/src/components/ArchivedReportFooter.tsx index 6bc1784310fd..aee7f6140626 100644 --- a/src/components/ArchivedReportFooter.tsx +++ b/src/components/ArchivedReportFooter.tsx @@ -11,7 +11,7 @@ import * as ReportUtils from '@libs/ReportUtils'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import type {PersonalDetailsList, Report, ReportAction} from '@src/types/onyx'; -import {Closed} from '@src/types/onyx/OriginalMessage'; +import type {Closed} from '@src/types/onyx/OriginalMessage'; import Banner from './Banner'; type ArchivedReportFooterOnyxProps = { diff --git a/src/components/AttachmentModal.tsx b/src/components/AttachmentModal.tsx index d5b7457a6dd1..e3b0ddc03875 100644 --- a/src/components/AttachmentModal.tsx +++ b/src/components/AttachmentModal.tsx @@ -25,7 +25,7 @@ import type {TranslationPaths} from '@src/languages/types'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import type * as OnyxTypes from '@src/types/onyx'; -import {IOUMessage} from '@src/types/onyx/OriginalMessage'; +import type {IOUMessage} from '@src/types/onyx/OriginalMessage'; import type {EmptyObject} from '@src/types/utils/EmptyObject'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; import type ModalType from '@src/types/utils/ModalType'; diff --git a/src/components/LHNOptionsList/LHNOptionsList.tsx b/src/components/LHNOptionsList/LHNOptionsList.tsx index 7a85d5302854..4e528c842e92 100644 --- a/src/components/LHNOptionsList/LHNOptionsList.tsx +++ b/src/components/LHNOptionsList/LHNOptionsList.tsx @@ -22,7 +22,7 @@ import * as ReportActionsUtils from '@libs/ReportActionsUtils'; import variables from '@styles/variables'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; -import {IOUMessage} from '@src/types/onyx/OriginalMessage'; +import type {IOUMessage} from '@src/types/onyx/OriginalMessage'; import OptionRowLHNData from './OptionRowLHNData'; import type {LHNOptionsListOnyxProps, LHNOptionsListProps, RenderItemProps} from './types'; diff --git a/src/components/ReportActionItem/ChronosOOOListActions.tsx b/src/components/ReportActionItem/ChronosOOOListActions.tsx index 52e0c52873d6..38b220b4551c 100644 --- a/src/components/ReportActionItem/ChronosOOOListActions.tsx +++ b/src/components/ReportActionItem/ChronosOOOListActions.tsx @@ -6,6 +6,7 @@ import Text from '@components/Text'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import DateUtils from '@libs/DateUtils'; +import * as ReportActionsUtils from '@libs/ReportActionsUtils'; import * as Chronos from '@userActions/Chronos'; import type {OriginalMessageChronosOOOList} from '@src/types/onyx/OriginalMessage'; import type {ReportActionBase} from '@src/types/onyx/ReportAction'; @@ -23,7 +24,7 @@ function ChronosOOOListActions({reportID, action}: ChronosOOOListActionsProps) { const {translate, preferredLocale} = useLocalize(); - const events = action.originalMessage?.events ?? []; + const events = ReportActionsUtils.getReportActionOriginalMessage(action)?.events ?? []; if (!events.length) { return ( diff --git a/src/components/ReportActionItem/MoneyRequestView.tsx b/src/components/ReportActionItem/MoneyRequestView.tsx index 37836580b740..af7da5c95068 100644 --- a/src/components/ReportActionItem/MoneyRequestView.tsx +++ b/src/components/ReportActionItem/MoneyRequestView.tsx @@ -29,6 +29,7 @@ import * as OptionsListUtils from '@libs/OptionsListUtils'; import * as PolicyUtils from '@libs/PolicyUtils'; import {isTaxTrackingEnabled} from '@libs/PolicyUtils'; import * as ReceiptUtils from '@libs/ReceiptUtils'; +import * as ReportActionsUtils from '@libs/ReportActionsUtils'; import * as ReportUtils from '@libs/ReportUtils'; import * as TransactionUtils from '@libs/TransactionUtils'; import ViolationsUtils from '@libs/Violations/ViolationsUtils'; @@ -41,6 +42,7 @@ import type {TranslationPaths} from '@src/languages/types'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import type * as OnyxTypes from '@src/types/onyx'; +import type {IOUMessage} from '@src/types/onyx/OriginalMessage'; import type {TransactionPendingFieldsKey} from '@src/types/onyx/Transaction'; import ReportActionItemImage from './ReportActionItemImage'; @@ -586,7 +588,8 @@ export default withOnyx { const parentReportAction = parentReportActions?.[report.parentReportActionID ?? '']; - const originalMessage = parentReportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.IOU ? parentReportAction.originalMessage : undefined; + const originalMessage = + parentReportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.IOU ? ReportActionsUtils.getReportActionOriginalMessage(parentReportAction) : undefined; const transactionID = originalMessage?.IOUTransactionID ?? 0; return `${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`; }, @@ -594,7 +597,8 @@ export default withOnyx { const parentReportAction = parentReportActions?.[report.parentReportActionID ?? '']; - const originalMessage = parentReportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.IOU ? parentReportAction.originalMessage : undefined; + const originalMessage = + parentReportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.IOU ? ReportActionsUtils.getReportActionOriginalMessage(parentReportAction) : undefined; const transactionID = originalMessage?.IOUTransactionID ?? 0; return `${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transactionID}`; }, diff --git a/src/libs/ReportActionsUtils.ts b/src/libs/ReportActionsUtils.ts index 202597315835..c54bce1ffe62 100644 --- a/src/libs/ReportActionsUtils.ts +++ b/src/libs/ReportActionsUtils.ts @@ -21,7 +21,7 @@ import type { OriginalMessageReimbursementDequeued, } from '@src/types/onyx/OriginalMessage'; import type Report from '@src/types/onyx/Report'; -import type {Message, OriginalMessage, ReportActionBase, ReportActionMessageJSON, ReportActions} from '@src/types/onyx/ReportAction'; +import type {Message, ReportActionBase, ReportActionMessageJSON, ReportActions} from '@src/types/onyx/ReportAction'; import type ReportAction from '@src/types/onyx/ReportAction'; import type {EmptyObject} from '@src/types/utils/EmptyObject'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; @@ -1006,10 +1006,10 @@ function getMemberChangeMessageElements(reportAction: OnyxEntry): ]; } -function getReportActionHtml(reportAction: PartialReportAction) { +function getReportActionHtml(reportAction: PartialReportAction): string { // @ts-expect-error Handle refactor not using message array, will remove when Back End is changed complete https://github.com/Expensify/App/issues/39797 // eslint-disable-next-line @typescript-eslint/no-unsafe-return - return reportAction?.message?.html || reportAction?.message?.[0]?.html; + return (reportAction?.message?.html as string) || reportAction?.message?.[0]?.html; } function getReportActionText(reportAction: PartialReportAction): string { From de34018a22fd2141e95b8e7473d06f2268063996 Mon Sep 17 00:00:00 2001 From: nkdengineer Date: Mon, 27 May 2024 12:55:46 +0700 Subject: [PATCH 06/45] remove originalMessage in ReportActionsUtils --- .../MoneyRequestPreviewContent.tsx | 8 ++- .../MoneyRequestPreview/index.tsx | 3 +- .../ReportActionItem/RenameAction.tsx | 5 +- src/libs/ModifiedExpenseMessage.ts | 3 +- src/libs/OptionsListUtils.ts | 7 ++- src/libs/ReportActionsUtils.ts | 63 +++++++++++-------- 6 files changed, 55 insertions(+), 34 deletions(-) diff --git a/src/components/ReportActionItem/MoneyRequestPreview/MoneyRequestPreviewContent.tsx b/src/components/ReportActionItem/MoneyRequestPreview/MoneyRequestPreviewContent.tsx index dc2e67d9c8ae..48d5b67b947a 100644 --- a/src/components/ReportActionItem/MoneyRequestPreview/MoneyRequestPreviewContent.tsx +++ b/src/components/ReportActionItem/MoneyRequestPreview/MoneyRequestPreviewContent.tsx @@ -70,7 +70,10 @@ function MoneyRequestPreviewContent({ const ownerAccountID = iouReport?.ownerAccountID ?? -1; const isPolicyExpenseChat = ReportUtils.isPolicyExpenseChat(chatReport); - const participantAccountIDs = action.actionName === CONST.REPORT.ACTIONS.TYPE.IOU && isBillSplit ? action.originalMessage.participantAccountIDs ?? [] : [managerID, ownerAccountID]; + const participantAccountIDs = + action.actionName === CONST.REPORT.ACTIONS.TYPE.IOU && isBillSplit + ? ReportActionsUtils.getReportActionOriginalMessage(action).participantAccountIDs ?? [] + : [managerID, ownerAccountID]; const participantAvatars = OptionsListUtils.getAvatarsForAccountIDs(participantAccountIDs, personalDetails ?? {}); const sortedParticipantAvatars = lodashSortBy(participantAvatars, (avatar) => avatar.id); if (isPolicyExpenseChat && isBillSplit) { @@ -212,7 +215,8 @@ function MoneyRequestPreviewContent({ }; const getDisplayDeleteAmountText = (): string => { - const iouOriginalMessage: IOUMessage | EmptyObject = action?.actionName === CONST.REPORT.ACTIONS.TYPE.IOU ? action.originalMessage : {}; + const iouOriginalMessage: IOUMessage | EmptyObject = + action?.actionName === CONST.REPORT.ACTIONS.TYPE.IOU ? ReportActionsUtils.getReportActionOriginalMessage(action) : {}; const {amount = 0, currency = CONST.CURRENCY.USD} = iouOriginalMessage; return CurrencyUtils.convertToDisplayString(amount, currency); diff --git a/src/components/ReportActionItem/MoneyRequestPreview/index.tsx b/src/components/ReportActionItem/MoneyRequestPreview/index.tsx index b46e052f3420..8ec71a228a47 100644 --- a/src/components/ReportActionItem/MoneyRequestPreview/index.tsx +++ b/src/components/ReportActionItem/MoneyRequestPreview/index.tsx @@ -3,6 +3,7 @@ import React from 'react'; import {withOnyx} from 'react-native-onyx'; import * as ReportActionsUtils from '@libs/ReportActionsUtils'; import ONYXKEYS from '@src/ONYXKEYS'; +import type {IOUMessage} from '@src/types/onyx/OriginalMessage'; import MoneyRequestPreviewContent from './MoneyRequestPreviewContent'; import type {MoneyRequestPreviewOnyxProps, MoneyRequestPreviewProps} from './types'; @@ -31,7 +32,7 @@ export default withOnyx( transaction: { key: ({action}) => { const isMoneyRequestAction = ReportActionsUtils.isMoneyRequestAction(action); - const transactionID = isMoneyRequestAction ? action?.originalMessage?.IOUTransactionID : 0; + const transactionID = isMoneyRequestAction ? ReportActionsUtils.getReportActionOriginalMessage(action)?.IOUTransactionID : 0; return `${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`; }, }, diff --git a/src/components/ReportActionItem/RenameAction.tsx b/src/components/ReportActionItem/RenameAction.tsx index b4b2553d652a..33f8ed2ee537 100644 --- a/src/components/ReportActionItem/RenameAction.tsx +++ b/src/components/ReportActionItem/RenameAction.tsx @@ -4,8 +4,10 @@ import withCurrentUserPersonalDetails from '@components/withCurrentUserPersonalD import type {WithCurrentUserPersonalDetailsProps} from '@components/withCurrentUserPersonalDetails'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; +import * as ReportActionsUtils from '@libs/ReportActionsUtils'; import CONST from '@src/CONST'; import type {ReportAction} from '@src/types/onyx'; +import type {OriginalMessageRenamed} from '@src/types/onyx/OriginalMessage'; type RenameActionProps = WithCurrentUserPersonalDetailsProps & { /** All the data of the action */ @@ -20,7 +22,8 @@ function RenameAction({currentUserPersonalDetails, action}: RenameActionProps) { const userDisplayName = action.person?.[0]?.text; const actorAccountID = action.actorAccountID ?? ''; const displayName = actorAccountID === currentUserAccountID ? `${translate('common.you')}` : `${userDisplayName}`; - const originalMessage = action.actionName === CONST.REPORT.ACTIONS.TYPE.RENAMED ? action.originalMessage : null; + const originalMessage = + action.actionName === CONST.REPORT.ACTIONS.TYPE.RENAMED ? ReportActionsUtils.getReportActionOriginalMessage(action) : null; const oldName = originalMessage?.oldName ?? ''; const newName = originalMessage?.newName ?? ''; diff --git a/src/libs/ModifiedExpenseMessage.ts b/src/libs/ModifiedExpenseMessage.ts index 2df75030ac19..f864ffd97e51 100644 --- a/src/libs/ModifiedExpenseMessage.ts +++ b/src/libs/ModifiedExpenseMessage.ts @@ -8,6 +8,7 @@ import DateUtils from './DateUtils'; import getReportPolicyID from './getReportPolicyID'; import * as Localize from './Localize'; import * as PolicyUtils from './PolicyUtils'; +import * as ReportActionsUtils from './ReportActionsUtils'; import type {ExpenseOriginalMessage} from './ReportUtils'; import * as TransactionUtils from './TransactionUtils'; @@ -109,7 +110,7 @@ function getForReportAction(reportID: string | undefined, reportAction: OnyxEntr if (reportAction?.actionName !== CONST.REPORT.ACTIONS.TYPE.MODIFIED_EXPENSE) { return ''; } - const reportActionOriginalMessage = reportAction?.originalMessage as ExpenseOriginalMessage | undefined; + const reportActionOriginalMessage = ReportActionsUtils.getReportActionOriginalMessage(reportAction); const policyID = getReportPolicyID(reportID) ?? ''; const removalFragments: string[] = []; diff --git a/src/libs/OptionsListUtils.ts b/src/libs/OptionsListUtils.ts index 0d5854764946..4ebf6b745371 100644 --- a/src/libs/OptionsListUtils.ts +++ b/src/libs/OptionsListUtils.ts @@ -32,6 +32,7 @@ import type { } from '@src/types/onyx'; import type {Participant} from '@src/types/onyx/IOU'; import type * as OnyxCommon from '@src/types/onyx/OnyxCommon'; +import type {Closed, IOUMessage} from '@src/types/onyx/OriginalMessage'; import type DeepValueOf from '@src/types/utils/DeepValueOf'; import type {EmptyObject} from '@src/types/utils/EmptyObject'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; @@ -522,7 +523,8 @@ function getAllReportErrors(report: OnyxEntry, reportActions: OnyxEntry< !report?.parentReportID || !report?.parentReportActionID ? null : allReportActions?.[report.parentReportID ?? '']?.[report.parentReportActionID ?? ''] ?? null; if (parentReportAction?.actorAccountID === currentUserAccountID && ReportActionUtils.isTransactionThread(parentReportAction)) { - const transactionID = parentReportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.IOU ? parentReportAction?.originalMessage?.IOUTransactionID : null; + const transactionID = + parentReportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.IOU ? ReportActionUtils.getReportActionOriginalMessage(parentReportAction)?.IOUTransactionID : null; const transaction = allTransactions?.[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`]; if (TransactionUtils.hasMissingSmartscanFields(transaction ?? null) && !ReportUtils.isSettled(transaction?.reportID)) { reportActionErrors.smartscan = ErrorUtils.getMicroSecondOnyxError('report.genericSmartscanFailureMessage'); @@ -587,7 +589,8 @@ function getLastMessageTextForReport(report: OnyxEntry, lastActorDetails if (ReportUtils.isArchivedRoom(report)) { const archiveReason = - (lastOriginalReportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.CLOSED && lastOriginalReportAction?.originalMessage?.reason) || CONST.REPORT.ARCHIVE_REASON.DEFAULT; + (lastOriginalReportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.CLOSED && ReportActionUtils.getReportActionOriginalMessage(lastOriginalReportAction)?.reason) || + CONST.REPORT.ARCHIVE_REASON.DEFAULT; switch (archiveReason) { case CONST.REPORT.ARCHIVE_REASON.ACCOUNT_CLOSED: case CONST.REPORT.ARCHIVE_REASON.REMOVED_FROM_POLICY: diff --git a/src/libs/ReportActionsUtils.ts b/src/libs/ReportActionsUtils.ts index c54bce1ffe62..8ef43049acb5 100644 --- a/src/libs/ReportActionsUtils.ts +++ b/src/libs/ReportActionsUtils.ts @@ -15,10 +15,12 @@ import type { OriginalMessageActionableMentionWhisper, OriginalMessageActionableReportMentionWhisper, OriginalMessageActionableTrackedExpenseWhisper, + OriginalMessageAddComment, OriginalMessageDismissedViolation, OriginalMessageIOU, OriginalMessageJoinPolicyChangeLog, OriginalMessageReimbursementDequeued, + OriginalMessageReportPreview, } from '@src/types/onyx/OriginalMessage'; import type Report from '@src/types/onyx/Report'; import type {Message, ReportActionBase, ReportActionMessageJSON, ReportActions} from '@src/types/onyx/ReportAction'; @@ -149,12 +151,16 @@ function isModifiedExpenseAction(reportAction: OnyxEntry | ReportA return reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.MODIFIED_EXPENSE; } +function getReportActionOriginalMessage(reportAction: PartialReportAction) { + return (reportAction?.originalMessage ?? reportAction?.message?.[0] ?? reportAction?.message) as T; +} + /** * We are in the process of deprecating reportAction.originalMessage and will be setting the db version of "message" to reportAction.message in the future see: https://github.com/Expensify/App/issues/39797 * In the interim, we must check to see if we have an object or array for the reportAction.message, if we have an array we will use the originalMessage as this means we have not yet migrated. */ function getWhisperedTo(reportAction: OnyxEntry | EmptyObject): number[] { - const originalMessage = reportAction?.originalMessage; + const originalMessage = getReportActionOriginalMessage(reportAction); const message = reportAction?.message; if (!Array.isArray(message) && typeof message === 'object') { @@ -232,11 +238,8 @@ function getParentReportAction(report: OnyxEntry | EmptyObject): ReportA * Determines if the given report action is sent money report action by checking for 'pay' type and presence of IOUDetails object. */ function isSentMoneyReportAction(reportAction: OnyxEntry): boolean { - return ( - reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.IOU && - (reportAction?.originalMessage as IOUMessage)?.type === CONST.IOU.REPORT_ACTION_TYPE.PAY && - !!(reportAction?.originalMessage as IOUMessage)?.IOUDetails - ); + const originalMessage = getReportActionOriginalMessage(reportAction); + return reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.IOU && originalMessage?.type === CONST.IOU.REPORT_ACTION_TYPE.PAY && !!originalMessage?.IOUDetails; } /** @@ -244,11 +247,12 @@ function isSentMoneyReportAction(reportAction: OnyxEntry | EmptyObject): boolean { + const originalMessage = getReportActionOriginalMessage(parentReportAction); return ( parentReportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.IOU && - (parentReportAction.originalMessage.type === CONST.IOU.REPORT_ACTION_TYPE.CREATE || - parentReportAction.originalMessage.type === CONST.IOU.REPORT_ACTION_TYPE.TRACK || - (parentReportAction.originalMessage.type === CONST.IOU.REPORT_ACTION_TYPE.PAY && !!parentReportAction.originalMessage.IOUDetails)) + (originalMessage.type === CONST.IOU.REPORT_ACTION_TYPE.CREATE || + originalMessage.type === CONST.IOU.REPORT_ACTION_TYPE.TRACK || + (originalMessage.type === CONST.IOU.REPORT_ACTION_TYPE.PAY && !!originalMessage.IOUDetails)) ); } @@ -325,7 +329,7 @@ function getCombinedReportActions(reportActions: ReportAction[], transactionThre // Filter out request and send money request actions because we don't want to show any preview actions for one transaction reports const filteredReportActions = [...reportActions, ...filteredTransactionThreadReportActions].filter((action) => { - const actionType = (action as OriginalMessageIOU).originalMessage?.type ?? ''; + const actionType = getReportActionOriginalMessage(action)?.type ?? ''; return actionType !== CONST.IOU.REPORT_ACTION_TYPE.CREATE && actionType !== CONST.IOU.REPORT_ACTION_TYPE.TRACK && !isSentMoneyReportAction(action); }); @@ -389,7 +393,8 @@ function getMostRecentIOURequestActionID(reportActions: ReportAction[] | null): CONST.IOU.REPORT_ACTION_TYPE.SPLIT, CONST.IOU.REPORT_ACTION_TYPE.TRACK, ]; - const iouRequestActions = reportActions?.filter((action) => action.actionName === CONST.REPORT.ACTIONS.TYPE.IOU && iouRequestTypes.includes(action.originalMessage.type)) ?? []; + const iouRequestActions = + reportActions?.filter((action) => action.actionName === CONST.REPORT.ACTIONS.TYPE.IOU && iouRequestTypes.includes(getReportActionOriginalMessage(action).type)) ?? []; if (iouRequestActions.length === 0) { return null; @@ -735,7 +740,7 @@ function getLinkedTransactionID(reportActionOrID: string | OnyxEntry(reportAction)?.IOUTransactionID ?? null; } function getReportAction(reportID: string, reportActionID: string): ReportAction | null { @@ -787,7 +792,10 @@ function getMostRecentReportActionLastModified(): string { function getReportPreviewAction(chatReportID: string, iouReportID: string): OnyxEntry { return ( Object.values(allReportActions?.[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chatReportID}`] ?? {}).find( - (reportAction) => reportAction && reportAction.actionName === CONST.REPORT.ACTIONS.TYPE.REPORT_PREVIEW && reportAction.originalMessage.linkedReportID === iouReportID, + (reportAction) => + reportAction && + reportAction.actionName === CONST.REPORT.ACTIONS.TYPE.REPORT_PREVIEW && + getReportActionOriginalMessage(reportAction).linkedReportID === iouReportID, ) ?? null ); } @@ -796,11 +804,13 @@ function getReportPreviewAction(chatReportID: string, iouReportID: string): Onyx * Get the iouReportID for a given report action. */ function getIOUReportIDFromReportActionPreview(reportAction: OnyxEntry): string { - return reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.REPORT_PREVIEW ? reportAction.originalMessage.linkedReportID : '0'; + return reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.REPORT_PREVIEW + ? getReportActionOriginalMessage(reportAction).linkedReportID + : '0'; } function isCreatedTaskReportAction(reportAction: OnyxEntry): boolean { - return reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.ADD_COMMENT && !!reportAction.originalMessage?.taskReportID; + return reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.ADD_COMMENT && !!getReportActionOriginalMessage(reportAction)?.taskReportID; } /** @@ -818,11 +828,11 @@ function getNumberOfMoneyRequests(reportPreviewAction: OnyxEntry): } function isSplitBillAction(reportAction: OnyxEntry): boolean { - return reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.IOU && reportAction.originalMessage.type === CONST.IOU.REPORT_ACTION_TYPE.SPLIT; + return reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.IOU && getReportActionOriginalMessage(reportAction).type === CONST.IOU.REPORT_ACTION_TYPE.SPLIT; } function isTrackExpenseAction(reportAction: OnyxEntry): boolean { - return reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.IOU && (reportAction.originalMessage as IOUMessage).type === CONST.IOU.REPORT_ACTION_TYPE.TRACK; + return reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.IOU && getReportActionOriginalMessage(reportAction).type === CONST.IOU.REPORT_ACTION_TYPE.TRACK; } function isTaskAction(reportAction: OnyxEntry): boolean { @@ -869,13 +879,13 @@ function getOneTransactionThreadReportID( const iouRequestActions = reportActionsArray.filter( (action) => action.actionName === CONST.REPORT.ACTIONS.TYPE.IOU && - (iouRequestTypes.includes(action.originalMessage.type) ?? []) && + (iouRequestTypes.includes(getReportActionOriginalMessage(action).type) ?? []) && action.childReportID && // Include deleted IOU reportActions if: // - they have an assocaited IOU transaction ID or // - they have visibile childActions (like comments) that we'd want to display // - the action is pending deletion and the user is offline - (Boolean(action.originalMessage.IOUTransactionID) || + (Boolean(getReportActionOriginalMessage(action).IOUTransactionID) || // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing (isMessageDeleted(action) && action.childVisibleActionCount) || (action.pendingAction === CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE && (isOffline ?? isNetworkOffline))), @@ -888,7 +898,7 @@ function getOneTransactionThreadReportID( // If there's only one IOU request action associated with the report but it's been deleted, then we don't consider this a oneTransaction report // and want to display it using the standard view - if (((iouRequestActions[0] as OriginalMessageIOU).originalMessage?.deleted ?? '') !== '') { + if ((getReportActionOriginalMessage(iouRequestActions[0])?.deleted ?? '') !== '') { return null; } @@ -956,7 +966,7 @@ function getMemberChangeMessageElements(reportAction: OnyxEntry): verb = Localize.translateLocal('workspace.invite.leftWorkspace'); } - const originalMessage = reportAction?.originalMessage as ChangeLog; + const originalMessage = getReportActionOriginalMessage(reportAction); const targetAccountIDs: number[] = originalMessage?.targetAccountIDs ?? []; const personalDetails = PersonalDetailsUtils.getPersonalDetailsByIDs(targetAccountIDs, 0); @@ -1018,10 +1028,6 @@ function getReportActionText(reportAction: PartialReportAction): string { return html ? parser.htmlToText(html) : ''; } -function getReportActionOriginalMessage(reportAction: PartialReportAction) { - return (reportAction?.originalMessage ?? reportAction?.message?.[0] ?? reportAction?.message) as T; -} - function getMemberChangeMessageFragment(reportAction: OnyxEntry): Message { const messageElements: readonly MemberChangeMessageElement[] = getMemberChangeMessageElements(reportAction); const html = messageElements @@ -1132,7 +1138,7 @@ function isActionableReportMentionWhisper(reportAction: OnyxEntry) * @returns the actionable mention whisper message. */ function getActionableMentionWhisperMessage(reportAction: OnyxEntry): string { - const originalMessage = reportAction?.originalMessage as OriginalMessageActionableMentionWhisper['originalMessage']; + const originalMessage = getReportActionOriginalMessage(reportAction); const targetAccountIDs: number[] = originalMessage?.inviteeAccountIDs ?? []; const personalDetails = PersonalDetailsUtils.getPersonalDetailsByIDs(targetAccountIDs, 0); const mentionElements = targetAccountIDs.map((accountID): string => { @@ -1192,7 +1198,10 @@ function isActionableTrackExpense(reportAction: OnyxEntry): report */ function isActionableJoinRequestPending(reportID: string): boolean { const sortedReportActions = getSortedReportActions(Object.values(getAllReportActions(reportID))); - const findPendingRequest = sortedReportActions.find((reportActionItem) => isActionableJoinRequest(reportActionItem) && reportActionItem.originalMessage.choice === ''); + const findPendingRequest = sortedReportActions.find( + (reportActionItem) => + isActionableJoinRequest(reportActionItem) && getReportActionOriginalMessage(reportActionItem).choice === '', + ); return !!findPendingRequest; } From ba85808a37f92a2a7b9bd46606ca143a3e1bec37 Mon Sep 17 00:00:00 2001 From: nkdengineer Date: Mon, 27 May 2024 13:15:03 +0700 Subject: [PATCH 07/45] remove originalMessage in ReportUtils --- src/libs/ReportUtils.ts | 48 ++++++++++++++++++------------- src/libs/SidebarUtils.ts | 6 ++-- src/types/onyx/OriginalMessage.ts | 1 + 3 files changed, 32 insertions(+), 23 deletions(-) diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index d0add1a1e851..ee214e9f002f 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -40,12 +40,15 @@ import type {Participant} from '@src/types/onyx/IOU'; import type {Errors, Icon, PendingAction} from '@src/types/onyx/OnyxCommon'; import type { ChangeLog, + Closed, IOUMessage, OriginalMessageActionName, OriginalMessageCreated, OriginalMessageDismissedViolation, OriginalMessageReimbursementDequeued, + OriginalMessageReimbursementQueued, OriginalMessageRenamed, + OriginalMessageReportPreview, PaymentMethodType, ReimbursementDeQueuedMessage, } from '@src/types/onyx/OriginalMessage'; @@ -1526,7 +1529,7 @@ function canDeleteReportAction(reportAction: OnyxEntry, reportID: if (reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.IOU) { // For now, users cannot delete split actions - const isSplitAction = reportAction?.originalMessage?.type === CONST.IOU.REPORT_ACTION_TYPE.SPLIT; + const isSplitAction = ReportActionsUtils.getReportActionOriginalMessage(reportAction)?.type === CONST.IOU.REPORT_ACTION_TYPE.SPLIT; if (isSplitAction) { return false; @@ -2157,7 +2160,7 @@ function getDeletedParentActionMessageForChatReport(reportAction: OnyxEntry, report: OnyxEntry, shouldUseShortDisplayName = true): string { const submitterDisplayName = getDisplayNameForParticipant(report?.ownerAccountID, shouldUseShortDisplayName) ?? ''; - const originalMessage = reportAction?.originalMessage as IOUMessage | undefined; + const originalMessage = ReportActionsUtils.getReportActionOriginalMessage(reportAction); let messageKey: TranslationPaths; if (originalMessage?.paymentType === CONST.IOU.PAYMENT_TYPE.EXPENSIFY) { messageKey = 'iou.waitingOnEnabledWallet'; @@ -2176,7 +2179,7 @@ function getReimbursementDeQueuedActionMessage( report: OnyxEntry | EmptyObject, isLHNPreview = false, ): string { - const originalMessage = reportAction?.originalMessage as ReimbursementDeQueuedMessage | undefined; + const originalMessage = ReportActionsUtils.getReportActionOriginalMessage(reportAction); const amount = originalMessage?.amount; const currency = originalMessage?.currency; const formattedAmount = CurrencyUtils.convertToDisplayString(amount, currency); @@ -2377,7 +2380,8 @@ function getPolicyExpenseChatName(report: OnyxEntry, policy: OnyxEntry

(lastAction)?.reason : CONST.REPORT.ARCHIVE_REASON.DEFAULT; if (archiveReason === CONST.REPORT.ARCHIVE_REASON.ACCOUNT_MERGED && policyExpenseChatRole !== CONST.POLICY.ROLE.ADMIN) { return getPolicyName(report, false, policy); } @@ -2599,15 +2603,16 @@ function canEditMoneyRequest(reportAction: OnyxEntry): boolean { } const allowedReportActionType: Array> = [CONST.IOU.REPORT_ACTION_TYPE.TRACK, CONST.IOU.REPORT_ACTION_TYPE.CREATE]; + const originalMessage = ReportActionsUtils.getReportActionOriginalMessage(reportAction); - if (!allowedReportActionType.includes(reportAction.originalMessage.type)) { + if (!allowedReportActionType.includes(originalMessage.type)) { return false; } - const moneyRequestReportID = reportAction?.originalMessage?.IOUReportID ?? 0; + const moneyRequestReportID = originalMessage?.IOUReportID ?? 0; if (!moneyRequestReportID) { - return reportAction.originalMessage.type === CONST.IOU.REPORT_ACTION_TYPE.TRACK; + return originalMessage.type === CONST.IOU.REPORT_ACTION_TYPE.TRACK; } const moneyRequestReport = getReport(String(moneyRequestReportID)); @@ -2657,7 +2662,7 @@ function canEditFieldOfMoneyRequest(reportAction: OnyxEntry, field return true; } - const iouMessage = reportAction?.originalMessage as IOUMessage; + const iouMessage = ReportActionsUtils.getReportActionOriginalMessage(reportAction); const moneyRequestReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${iouMessage?.IOUReportID}`] ?? ({} as Report); const transaction = allTransactions?.[`${ONYXKEYS.COLLECTION.TRANSACTION}${iouMessage?.IOUTransactionID}`] ?? ({} as Transaction); @@ -2752,7 +2757,7 @@ function getLinkedTransaction(reportAction: OnyxEntry(reportAction)?.IOUTransactionID ?? ''; } return allTransactions?.[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`] ?? {}; @@ -2899,7 +2904,7 @@ function getReportPreviewMessage( return Localize.translateLocal('iou.fieldPending'); } - const originalMessage = iouReportAction?.originalMessage as IOUMessage | undefined; + const originalMessage = ReportActionsUtils.getReportActionOriginalMessage(iouReportAction); // Show Paid preview message if it's settled or if the amount is paid & stuck at receivers end for only chat reports. if (isSettled(report.reportID) || (report.isWaitingOnBankAccount && isPreviewMessageForParentChatReport)) { @@ -3051,10 +3056,10 @@ function isChangeLogObject(originalMessage?: ChangeLog): ChangeLog | undefined { * @param parentReportActionMessage */ function getAdminRoomInvitedParticipants(parentReportAction: ReportAction | Record, parentReportActionMessage: string) { - if (!parentReportAction?.originalMessage) { + if (!ReportActionsUtils.getReportActionOriginalMessage(parentReportAction)) { return parentReportActionMessage || Localize.translateLocal('parentReportAction.deletedMessage'); } - const originalMessage = isChangeLogObject(parentReportAction.originalMessage); + const originalMessage = isChangeLogObject(ReportActionsUtils.getReportActionOriginalMessage(parentReportAction)); const participantAccountIDs = originalMessage?.targetAccountIDs ?? []; const participants = participantAccountIDs.map((id) => { @@ -4226,6 +4231,7 @@ function updateReportPreview( } const message = getReportPreviewMessage(iouReport, reportPreviewAction); + const originalMessage = ReportActionsUtils.getReportActionOriginalMessage(reportPreviewAction); return { ...reportPreviewAction, message: [ @@ -4247,8 +4253,8 @@ function updateReportPreview( // As soon as we add a transaction without a receipt to the report, it will have ready expenses, // so we remove the whisper originalMessage: { - ...(reportPreviewAction.originalMessage ?? {}), - whisperedTo: hasReceipt ? reportPreviewAction?.originalMessage?.whisperedTo : [], + ...(originalMessage ?? {}), + whisperedTo: hasReceipt ? originalMessage?.whisperedTo : [], }, }; } @@ -5031,7 +5037,7 @@ function doesTransactionThreadHaveViolations(report: OnyxEntry, transact if (parentReportAction?.actionName !== CONST.REPORT.ACTIONS.TYPE.IOU) { return false; } - const {IOUTransactionID, IOUReportID} = parentReportAction.originalMessage ?? {}; + const {IOUTransactionID, IOUReportID} = ReportActionsUtils.getReportActionOriginalMessage(parentReportAction) ?? {}; if (!IOUTransactionID || !IOUReportID) { return false; } @@ -5052,7 +5058,7 @@ function shouldDisplayTransactionThreadViolations( transactionViolations: OnyxCollection, parentReportAction: OnyxEntry, ): boolean { - const {IOUReportID} = (parentReportAction?.originalMessage as IOUMessage) ?? {}; + const {IOUReportID} = ReportActionsUtils.getReportActionOriginalMessage(parentReportAction) ?? {}; if (isSettled(IOUReportID)) { return false; } @@ -6015,7 +6021,7 @@ function getIOUReportActionDisplayMessage(reportAction: OnyxEntry, if (reportAction?.actionName !== CONST.REPORT.ACTIONS.TYPE.IOU) { return ''; } - const originalMessage = reportAction.originalMessage; + const originalMessage = ReportActionsUtils.getReportActionOriginalMessage(reportAction); const {IOUReportID} = originalMessage; const iouReport = getReport(IOUReportID); let translationKey: TranslationPaths; @@ -6173,7 +6179,7 @@ function hasSmartscanError(reportActions: ReportAction[]) { } const IOUReportID = ReportActionsUtils.getIOUReportIDFromReportActionPreview(action); const isReportPreviewError = ReportActionsUtils.isReportPreviewAction(action) && hasMissingSmartscanFields(IOUReportID) && !isSettled(IOUReportID); - const transactionID = (action.originalMessage as IOUMessage).IOUTransactionID ?? '0'; + const transactionID = ReportActionsUtils.getReportActionOriginalMessage(action).IOUTransactionID ?? '0'; const transaction = allTransactions?.[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`] ?? {}; const isSplitBillError = ReportActionsUtils.isSplitBillAction(action) && TransactionUtils.hasMissingSmartscanFields(transaction as Transaction); @@ -6481,7 +6487,7 @@ function getIndicatedMissingPaymentMethod(userWallet: OnyxEntry, rep if (!isSubmitterOfUnsettledReport || reportAction.actionName !== CONST.REPORT.ACTIONS.TYPE.REIMBURSEMENT_QUEUED) { return undefined; } - const paymentType = reportAction.originalMessage?.paymentType; + const paymentType = ReportActionsUtils.getReportActionOriginalMessage(reportAction)?.paymentType; if (paymentType === CONST.IOU.PAYMENT_TYPE.EXPENSIFY) { return isEmpty(userWallet) || userWallet.tierName === CONST.WALLET.TIER_NAME.SILVER ? 'wallet' : undefined; } @@ -6615,7 +6621,9 @@ function createDraftTransactionAndNavigateToParticipantSelector(transactionID: s return; } - const linkedTrackedExpenseReportAction = Object.values(reportActions).find((action) => (action.originalMessage as IOUMessage)?.IOUTransactionID === transactionID); + const linkedTrackedExpenseReportAction = Object.values(reportActions).find( + (action) => ReportActionsUtils.getReportActionOriginalMessage(action)?.IOUTransactionID === transactionID, + ); const {created, amount, currency, merchant, mccGroup} = getTransactionDetails(transaction) ?? {}; const comment = getTransactionCommentObject(transaction); diff --git a/src/libs/SidebarUtils.ts b/src/libs/SidebarUtils.ts index b4ae942547a1..57f1c1d9246c 100644 --- a/src/libs/SidebarUtils.ts +++ b/src/libs/SidebarUtils.ts @@ -6,7 +6,7 @@ import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import type {PersonalDetails, PersonalDetailsList, ReportActions, TransactionViolation} from '@src/types/onyx'; import type Beta from '@src/types/onyx/Beta'; -import type {ChangeLog} from '@src/types/onyx/OriginalMessage'; +import type {ChangeLog, OriginalMessageRenamed} from '@src/types/onyx/OriginalMessage'; import type Policy from '@src/types/onyx/Policy'; import type PriorityMode from '@src/types/onyx/PriorityMode'; import type Report from '@src/types/onyx/Report'; @@ -336,7 +336,7 @@ function getOptionData({ const lastActionName = lastAction?.actionName ?? report.lastActionType; if (lastAction?.actionName === CONST.REPORT.ACTIONS.TYPE.RENAMED) { - const newName = lastAction?.originalMessage?.newName ?? ''; + const newName = ReportActionsUtils.getReportActionOriginalMessage(lastAction)?.newName ?? ''; result.alternateText = Localize.translate(preferredLocale, 'newRoomPage.roomRenamedTo', {newName}); } else if (ReportActionsUtils.isTaskAction(lastAction)) { result.alternateText = ReportUtils.formatReportLastMessageText(TaskUtils.getTaskReportActionMessage(lastAction).text); @@ -346,7 +346,7 @@ function getOptionData({ lastActionName === CONST.REPORT.ACTIONS.TYPE.POLICY_CHANGE_LOG.INVITE_TO_ROOM || lastActionName === CONST.REPORT.ACTIONS.TYPE.POLICY_CHANGE_LOG.REMOVE_FROM_ROOM ) { - const lastActionOriginalMessage = lastAction?.actionName ? (lastAction?.originalMessage as ChangeLog) : null; + const lastActionOriginalMessage = lastAction?.actionName ? ReportActionsUtils.getReportActionOriginalMessage(lastAction) : null; const targetAccountIDs = lastActionOriginalMessage?.targetAccountIDs ?? []; const targetAccountIDsLength = targetAccountIDs.length !== 0 ? targetAccountIDs.length : report.lastMessageHtml?.match(/]*><\/mention-user>/g)?.length ?? 0; const verb = diff --git a/src/types/onyx/OriginalMessage.ts b/src/types/onyx/OriginalMessage.ts index b079a64ebb4b..6a8e4b482822 100644 --- a/src/types/onyx/OriginalMessage.ts +++ b/src/types/onyx/OriginalMessage.ts @@ -398,4 +398,5 @@ export type { PaymentMethodType, OriginalMessageActionableTrackedExpenseWhisper, OriginalMessageDismissedViolation, + OriginalMessageReimbursementQueued, }; From e22f5de56e0c542ad9bdc7d5fc748b35394ee4ae Mon Sep 17 00:00:00 2001 From: nkdengineer Date: Mon, 27 May 2024 14:21:08 +0700 Subject: [PATCH 08/45] remove originalMessage in ReportActionItem --- src/pages/home/report/ReportActionItem.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/home/report/ReportActionItem.tsx b/src/pages/home/report/ReportActionItem.tsx index a77aec5ac8b1..95bc4f5231d2 100644 --- a/src/pages/home/report/ReportActionItem.tsx +++ b/src/pages/home/report/ReportActionItem.tsx @@ -294,7 +294,7 @@ function ReportActionItem({ // Hide the message if it is being moderated for a higher offense, or is hidden by a moderator // Removed messages should not be shown anyway and should not need this flow - const latestDecision = ReportActionsUtils.getReportActionMessage(action)?.moderationDecision?.decision ?? ''; + const latestDecision = action.message?.[0]?.moderationDecision?.decision ?? ''; useEffect(() => { if (action.actionName !== CONST.REPORT.ACTIONS.TYPE.ADD_COMMENT) { return; @@ -619,7 +619,7 @@ function ReportActionItem({ } else if (action.actionName === CONST.REPORT.ACTIONS.TYPE.HOLD) { children = ; } else if (action.actionName === CONST.REPORT.ACTIONS.TYPE.HOLD_COMMENT) { - children = ; + children = ; } else if (action.actionName === CONST.REPORT.ACTIONS.TYPE.UNHOLD) { children = ; } else if (action.actionName === CONST.REPORT.ACTIONS.TYPE.MERGED_WITH_CASH_TRANSACTION) { From 6a8c37a9836311329095b960920a0643ea5fc297 Mon Sep 17 00:00:00 2001 From: nkdengineer Date: Mon, 27 May 2024 14:39:57 +0700 Subject: [PATCH 09/45] remove originalMessage in IOU, Report, Policy lib --- src/libs/actions/IOU.ts | 13 ++++++++----- src/libs/actions/Policy.ts | 4 ++-- src/libs/actions/Report.ts | 4 ++-- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index c86f20ae8ca8..a33ec64a3c58 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -52,7 +52,7 @@ import ROUTES from '@src/ROUTES'; import type * as OnyxTypes from '@src/types/onyx'; import type {Participant, Split} from '@src/types/onyx/IOU'; import type {ErrorFields, Errors} from '@src/types/onyx/OnyxCommon'; -import type {IOUMessage, PaymentMethodType} from '@src/types/onyx/OriginalMessage'; +import type {IOUMessage, OriginalMessageReportPreview, PaymentMethodType} from '@src/types/onyx/OriginalMessage'; import type ReportAction from '@src/types/onyx/ReportAction'; import type {ReportPreviewAction} from '@src/types/onyx/ReportAction'; import type {OnyxData} from '@src/types/onyx/Request'; @@ -278,7 +278,10 @@ function getReportPreviewAction(chatReportID: string, iouReportID: string): Onyx // Find the report preview action from the chat report return ( Object.values(reportActions).find( - (reportAction) => reportAction && reportAction.actionName === CONST.REPORT.ACTIONS.TYPE.REPORT_PREVIEW && reportAction.originalMessage.linkedReportID === iouReportID, + (reportAction) => + reportAction && + reportAction.actionName === CONST.REPORT.ACTIONS.TYPE.REPORT_PREVIEW && + ReportActionsUtils.getReportActionOriginalMessage(reportAction).linkedReportID === iouReportID, ) ?? null ); } @@ -3347,7 +3350,7 @@ function requestMoney( currentCreated, merchant, receipt, - isMovingTransactionFromTrackExpense ? (linkedTrackedExpenseReportAction?.originalMessage as IOUMessage)?.IOUTransactionID : undefined, + isMovingTransactionFromTrackExpense ? ReportActionsUtils.getReportActionOriginalMessage(linkedTrackedExpenseReportAction)?.IOUTransactionID : undefined, category, tag, taxCode, @@ -3548,7 +3551,7 @@ function trackExpense( payeeAccountID, moneyRequestReportID, linkedTrackedExpenseReportAction, - isMovingTransactionFromTrackExpense ? (linkedTrackedExpenseReportAction?.originalMessage as IOUMessage)?.IOUTransactionID : undefined, + isMovingTransactionFromTrackExpense ? ReportActionsUtils.getReportActionOriginalMessage(linkedTrackedExpenseReportAction)?.IOUTransactionID : undefined, ); const activeReportID = isMoneyRequestReport ? report.reportID : chatReport.reportID; @@ -5147,7 +5150,7 @@ function updateMoneyRequestAmountAndCurrency({ function deleteMoneyRequest(transactionID: string, reportAction: OnyxTypes.ReportAction, isSingleTransactionView = false) { // STEP 1: Get all collections we're updating - const iouReportID = reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.IOU ? reportAction.originalMessage.IOUReportID : ''; + const iouReportID = reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.IOU ? ReportActionsUtils.getReportActionOriginalMessage(reportAction).IOUReportID : ''; const iouReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${iouReportID}`] ?? null; const chatReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${iouReport?.chatReportID}`]; const reportPreviewAction = getReportPreviewAction(iouReport?.chatReportID ?? '', iouReport?.reportID ?? ''); diff --git a/src/libs/actions/Policy.ts b/src/libs/actions/Policy.ts index 9206aa2fb0b3..c8cae2d7771d 100644 --- a/src/libs/actions/Policy.ts +++ b/src/libs/actions/Policy.ts @@ -3920,7 +3920,7 @@ function acceptJoinRequest(reportID: string, reportAction: OnyxEntry(reportAction).policyID]: { requests: [{accountID: reportAction?.actorAccountID, adminsRoomMessageReportActionID: reportAction.reportActionID}], }, }), @@ -3978,7 +3978,7 @@ function declineJoinRequest(reportID: string, reportAction: OnyxEntry(reportAction).policyID]: { requests: [{accountID: reportAction?.actorAccountID, adminsRoomMessageReportActionID: reportAction.reportActionID}], }, }), diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index 6d3c553e769e..ab1ba1b1a3a5 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -93,7 +93,7 @@ import type { ReportMetadata, ReportUserIsTyping, } from '@src/types/onyx'; -import type {Decision, OriginalMessageIOU} from '@src/types/onyx/OriginalMessage'; +import type {Decision, IOUMessage, OriginalMessageIOU} from '@src/types/onyx/OriginalMessage'; import type {NotificationPreference, Participants, Participant as ReportParticipant, RoomVisibility, WriteCapability} from '@src/types/onyx/Report'; import type Report from '@src/types/onyx/Report'; import type {Message, ReportActionBase, ReportActions} from '@src/types/onyx/ReportAction'; @@ -2088,7 +2088,7 @@ function deleteReport(reportID: string) { const transactionIDs = Object.values(reportActionsForReport ?? {}) .filter((reportAction): reportAction is ReportActionBase & OriginalMessageIOU => reportAction.actionName === CONST.REPORT.ACTIONS.TYPE.IOU) - .map((reportAction) => reportAction.originalMessage.IOUTransactionID); + .map((reportAction) => ReportActionsUtils.getReportActionOriginalMessage(reportAction).IOUTransactionID); [...new Set(transactionIDs)].forEach((transactionID) => { onyxData[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`] = null; From 28ead5b3e993296f15824dcc8701a2dbaebb71b7 Mon Sep 17 00:00:00 2001 From: nkdengineer Date: Mon, 27 May 2024 14:43:06 +0700 Subject: [PATCH 10/45] revert unecessary change --- src/pages/home/report/ReportActionItem.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/home/report/ReportActionItem.tsx b/src/pages/home/report/ReportActionItem.tsx index 95bc4f5231d2..a77aec5ac8b1 100644 --- a/src/pages/home/report/ReportActionItem.tsx +++ b/src/pages/home/report/ReportActionItem.tsx @@ -294,7 +294,7 @@ function ReportActionItem({ // Hide the message if it is being moderated for a higher offense, or is hidden by a moderator // Removed messages should not be shown anyway and should not need this flow - const latestDecision = action.message?.[0]?.moderationDecision?.decision ?? ''; + const latestDecision = ReportActionsUtils.getReportActionMessage(action)?.moderationDecision?.decision ?? ''; useEffect(() => { if (action.actionName !== CONST.REPORT.ACTIONS.TYPE.ADD_COMMENT) { return; @@ -619,7 +619,7 @@ function ReportActionItem({ } else if (action.actionName === CONST.REPORT.ACTIONS.TYPE.HOLD) { children = ; } else if (action.actionName === CONST.REPORT.ACTIONS.TYPE.HOLD_COMMENT) { - children = ; + children = ; } else if (action.actionName === CONST.REPORT.ACTIONS.TYPE.UNHOLD) { children = ; } else if (action.actionName === CONST.REPORT.ACTIONS.TYPE.MERGED_WITH_CASH_TRANSACTION) { From c53630bdff8451e4a106dd1810fae19b6a483036 Mon Sep 17 00:00:00 2001 From: nkdengineer Date: Mon, 27 May 2024 14:46:47 +0700 Subject: [PATCH 11/45] remove originalMessage in ReportActionItem --- src/pages/home/report/ReportActionItem.tsx | 89 ++++++++++++++++------ 1 file changed, 66 insertions(+), 23 deletions(-) diff --git a/src/pages/home/report/ReportActionItem.tsx b/src/pages/home/report/ReportActionItem.tsx index a77aec5ac8b1..06359a2ef954 100644 --- a/src/pages/home/report/ReportActionItem.tsx +++ b/src/pages/home/report/ReportActionItem.tsx @@ -65,6 +65,16 @@ import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import type * as OnyxTypes from '@src/types/onyx'; import type {Errors} from '@src/types/onyx/OnyxCommon'; +import type { + IOUMessage, + OriginalMessageActionableMentionWhisper, + OriginalMessageActionableReportMentionWhisper, + OriginalMessageActionableTrackedExpenseWhisper, + OriginalMessageAddComment, + OriginalMessageDismissedViolation, + OriginalMessageJoinPolicyChangeLog, + OriginalMessageReimbursementQueued, +} from '@src/types/onyx/OriginalMessage'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; import AnimatedEmptyStateBackground from './AnimatedEmptyStateBackground'; import {RestrictedReadOnlyContextMenuActions} from './ContextMenu/ContextMenuActions'; @@ -212,6 +222,7 @@ function ReportActionItem({ const reportScrollManager = useReportScrollManager(); const isActionableWhisper = ReportActionsUtils.isActionableMentionWhisper(action) || ReportActionsUtils.isActionableTrackExpense(action) || ReportActionsUtils.isActionableReportMentionWhisper(action); + const originalMessage = ReportActionsUtils.getReportActionOriginalMessage(action); const highlightedBackgroundColorIfNeeded = useMemo( () => (isReportActionLinked ? StyleUtils.getBackgroundColorStyle(theme.messageHighlightBG) : {}), @@ -219,10 +230,19 @@ function ReportActionItem({ ); const isDeletedParentAction = ReportActionsUtils.isDeletedParentAction(action); - const prevActionResolution = usePrevious(isActionableWhisper ? action.originalMessage.resolution : null); + const prevActionResolution = usePrevious( + isActionableWhisper + ? ( + originalMessage as + | OriginalMessageActionableMentionWhisper['originalMessage'] + | OriginalMessageActionableTrackedExpenseWhisper['originalMessage'] + | OriginalMessageActionableReportMentionWhisper['originalMessage'] + ).resolution + : null, + ); // IOUDetails only exists when we are sending money - const isSendingMoney = isIOUReport(action) && action.originalMessage.type === CONST.IOU.REPORT_ACTION_TYPE.PAY && action.originalMessage.IOUDetails; + const isSendingMoney = isIOUReport(action) && (originalMessage as IOUMessage).type === CONST.IOU.REPORT_ACTION_TYPE.PAY && (originalMessage as IOUMessage).IOUDetails; const updateHiddenState = useCallback( (isHiddenValue: boolean) => { @@ -366,10 +386,18 @@ function ReportActionItem({ return; } - if (prevActionResolution !== (action.originalMessage.resolution ?? null)) { + if ( + prevActionResolution !== + (( + originalMessage as + | OriginalMessageActionableMentionWhisper['originalMessage'] + | OriginalMessageActionableTrackedExpenseWhisper['originalMessage'] + | OriginalMessageActionableReportMentionWhisper['originalMessage'] + ).resolution ?? null) + ) { reportScrollManager.scrollToIndex(index); } - }, [index, action, prevActionResolution, reportScrollManager, isActionableWhisper]); + }, [index, originalMessage, prevActionResolution, reportScrollManager, isActionableWhisper]); const toggleReaction = useCallback( (emoji: Emoji) => { @@ -390,12 +418,12 @@ function ReportActionItem({ ); const actionableItemButtons: ActionableItem[] = useMemo(() => { - if (!isActionableWhisper && (!ReportActionsUtils.isActionableJoinRequest(action) || action.originalMessage.choice !== '')) { + if (!isActionableWhisper && (!ReportActionsUtils.isActionableJoinRequest(action) || (originalMessage as OriginalMessageJoinPolicyChangeLog['originalMessage']).choice !== '')) { return []; } if (ReportActionsUtils.isActionableTrackExpense(action)) { - const transactionID = action?.originalMessage?.transactionID; + const transactionID = (originalMessage as OriginalMessageActionableTrackedExpenseWhisper['originalMessage'])?.transactionID; return [ { text: 'actionableMentionTrackExpense.submit', @@ -477,7 +505,7 @@ function ReportActionItem({ onPress: () => Report.resolveActionableMentionWhisper(report.reportID, action, CONST.REPORT.ACTIONABLE_MENTION_WHISPER_RESOLUTION.NOTHING), }, ]; - }, [action, isActionableWhisper, report.reportID]); + }, [action, isActionableWhisper, report.reportID, originalMessage]); const renderThreadDivider = useMemo( () => @@ -504,23 +532,24 @@ function ReportActionItem({ */ const renderItemContent = (hovered = false, isWhisper = false, hasErrors = false): React.JSX.Element => { let children; + const iouOriginalMessage = originalMessage as IOUMessage; // Show the MoneyRequestPreview for when expense is present if ( isIOUReport(action) && - action.originalMessage && + iouOriginalMessage && // For the pay flow, we only want to show MoneyRequestAction when sending money. When paying, we display a regular system message - (action.originalMessage.type === CONST.IOU.REPORT_ACTION_TYPE.CREATE || - action.originalMessage.type === CONST.IOU.REPORT_ACTION_TYPE.SPLIT || - action.originalMessage.type === CONST.IOU.REPORT_ACTION_TYPE.TRACK || + (iouOriginalMessage.type === CONST.IOU.REPORT_ACTION_TYPE.CREATE || + iouOriginalMessage.type === CONST.IOU.REPORT_ACTION_TYPE.SPLIT || + iouOriginalMessage.type === CONST.IOU.REPORT_ACTION_TYPE.TRACK || isSendingMoney) ) { // There is no single iouReport for bill splits, so only 1:1 requests require an iouReportID - const iouReportID = action.originalMessage.IOUReportID ? action.originalMessage.IOUReportID.toString() : '0'; + const iouReportID = iouOriginalMessage.IOUReportID ? iouOriginalMessage.IOUReportID.toString() : '0'; children = ( ; } else if (action.actionName === CONST.REPORT.ACTIONS.TYPE.DISMISSED_VIOLATION) { - children = ; + children = ( + + ); } else { const hasBeenFlagged = ![CONST.MODERATION.MODERATOR_DECISION_APPROVED, CONST.MODERATION.MODERATOR_DECISION_PENDING].some((item) => item === moderationDecision) && @@ -900,12 +935,21 @@ function ReportActionItem({ // For the `pay` IOU action on non-pay expense flow, we don't want to render anything if `isWaitingOnBankAccount` is true // Otherwise, we will see two system messages informing the payee needs to add a bank account or wallet - if (isIOUReport(action) && !!report?.isWaitingOnBankAccount && action.originalMessage.type === CONST.IOU.REPORT_ACTION_TYPE.PAY && !isSendingMoney) { + if (isIOUReport(action) && !!report?.isWaitingOnBankAccount && (originalMessage as IOUMessage).type === CONST.IOU.REPORT_ACTION_TYPE.PAY && !isSendingMoney) { return null; } // If action is actionable whisper and resolved by user, then we don't want to render anything - if (isActionableWhisper && (action.originalMessage.resolution ?? null)) { + if ( + isActionableWhisper && + (( + originalMessage as + | OriginalMessageActionableMentionWhisper['originalMessage'] + | OriginalMessageActionableTrackedExpenseWhisper['originalMessage'] + | OriginalMessageActionableReportMentionWhisper['originalMessage'] + ).resolution ?? + null) + ) { return null; } @@ -920,7 +964,7 @@ function ReportActionItem({ const whisperedTo = ReportActionsUtils.getWhisperedTo(action); const isMultipleParticipant = whisperedTo.length > 1; - const iouReportID = isIOUReport(action) && action.originalMessage.IOUReportID ? action.originalMessage.IOUReportID.toString() : '0'; + const iouReportID = isIOUReport(action) && (originalMessage as IOUMessage).IOUReportID ? ((originalMessage as IOUMessage)?.IOUReportID ?? '').toString() : '0'; const transactionsWithReceipts = ReportUtils.getTransactionsWithReceipts(iouReportID); const isWhisper = whisperedTo.length > 0 && transactionsWithReceipts.length === 0 && !action.pendingAction; const whisperedToPersonalDetails = isWhisper @@ -1038,14 +1082,13 @@ export default withOnyx({ }, transaction: { key: ({parentReportActionForTransactionThread}) => { - const transactionID = (parentReportActionForTransactionThread as OnyxTypes.OriginalMessageIOU)?.originalMessage.IOUTransactionID - ? (parentReportActionForTransactionThread as OnyxTypes.OriginalMessageIOU).originalMessage.IOUTransactionID - : 0; + const originalMessage = ReportActionsUtils.getReportActionOriginalMessage(parentReportActionForTransactionThread); + const transactionID = originalMessage.IOUTransactionID ? originalMessage.IOUTransactionID : 0; return `${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`; }, }, linkedTransactionRouteError: { - key: ({action}) => `${ONYXKEYS.COLLECTION.TRANSACTION}${(action as OnyxTypes.OriginalMessageIOU)?.originalMessage?.IOUTransactionID ?? 0}`, + key: ({action}) => `${ONYXKEYS.COLLECTION.TRANSACTION}${ReportActionsUtils.getReportActionOriginalMessage(action)?.IOUTransactionID ?? 0}`, selector: (transaction: OnyxEntry) => transaction?.errorFields?.route ?? null, }, })( From 48d26c5190dedc37878920b31637fb16ad592d60 Mon Sep 17 00:00:00 2001 From: nkdengineer Date: Mon, 27 May 2024 14:59:53 +0700 Subject: [PATCH 12/45] fix test --- src/pages/home/report/ReportActionItem.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/home/report/ReportActionItem.tsx b/src/pages/home/report/ReportActionItem.tsx index 06359a2ef954..7435673d1932 100644 --- a/src/pages/home/report/ReportActionItem.tsx +++ b/src/pages/home/report/ReportActionItem.tsx @@ -505,7 +505,7 @@ function ReportActionItem({ onPress: () => Report.resolveActionableMentionWhisper(report.reportID, action, CONST.REPORT.ACTIONABLE_MENTION_WHISPER_RESOLUTION.NOTHING), }, ]; - }, [action, isActionableWhisper, report.reportID, originalMessage]); + }, [action, isActionableWhisper, report.reportID]); const renderThreadDivider = useMemo( () => From 78efa960ee08288674268e86af041bfbdc6e17dc Mon Sep 17 00:00:00 2001 From: nkdengineer Date: Mon, 27 May 2024 15:19:05 +0700 Subject: [PATCH 13/45] fix test --- src/pages/home/report/ReportActionItem.tsx | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/pages/home/report/ReportActionItem.tsx b/src/pages/home/report/ReportActionItem.tsx index 7435673d1932..2a7706464e85 100644 --- a/src/pages/home/report/ReportActionItem.tsx +++ b/src/pages/home/report/ReportActionItem.tsx @@ -505,6 +505,8 @@ function ReportActionItem({ onPress: () => Report.resolveActionableMentionWhisper(report.reportID, action, CONST.REPORT.ACTIONABLE_MENTION_WHISPER_RESOLUTION.NOTHING), }, ]; + + // eslint-disable-next-line react-hooks/exhaustive-deps }, [action, isActionableWhisper, report.reportID]); const renderThreadDivider = useMemo( @@ -1082,13 +1084,13 @@ export default withOnyx({ }, transaction: { key: ({parentReportActionForTransactionThread}) => { - const originalMessage = ReportActionsUtils.getReportActionOriginalMessage(parentReportActionForTransactionThread); - const transactionID = originalMessage.IOUTransactionID ? originalMessage.IOUTransactionID : 0; + const originalMessage = ReportActionsUtils.getReportActionOriginalMessage(parentReportActionForTransactionThread); + const transactionID = originalMessage?.IOUTransactionID ? originalMessage?.IOUTransactionID : 0; return `${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`; }, }, linkedTransactionRouteError: { - key: ({action}) => `${ONYXKEYS.COLLECTION.TRANSACTION}${ReportActionsUtils.getReportActionOriginalMessage(action)?.IOUTransactionID ?? 0}`, + key: ({action}) => `${ONYXKEYS.COLLECTION.TRANSACTION}${ReportActionsUtils.getReportActionOriginalMessage(action)?.IOUTransactionID ?? 0}`, selector: (transaction: OnyxEntry) => transaction?.errorFields?.route ?? null, }, })( From ddeabfcf94483c06e51b7b46bfbf98e214071707 Mon Sep 17 00:00:00 2001 From: nkdengineer Date: Mon, 27 May 2024 15:42:00 +0700 Subject: [PATCH 14/45] remove originalMessage in other files --- src/libs/actions/User.ts | 2 +- .../report/ContextMenu/ContextMenuActions.tsx | 3 +- .../PopoverReportActionContextMenu.tsx | 6 +- .../home/report/ReportActionItemMessage.tsx | 6 +- .../report/ReportActionsListItemRenderer.tsx | 4 +- src/pages/home/report/ReportActionsView.tsx | 17 +-- src/pages/iou/SplitBillDetailsPage.tsx | 13 ++- tests/actions/IOUTest.ts | 105 ++++++++++-------- tests/actions/PolicyMemberTest.ts | 3 +- 9 files changed, 92 insertions(+), 67 deletions(-) diff --git a/src/libs/actions/User.ts b/src/libs/actions/User.ts index f7e90f775b65..afc32847bff6 100644 --- a/src/libs/actions/User.ts +++ b/src/libs/actions/User.ts @@ -523,7 +523,7 @@ function playSoundForMessageType(pushJSON: OnyxServerUpdate[]) { } } - const types = flatten.map((data) => data?.originalMessage).filter(Boolean) as OriginalMessage[]; + const types = flatten.map((data) => ReportActionsUtils.getReportActionOriginalMessage(data)).filter(Boolean) as OriginalMessage[]; for (const message of types) { // Pay someone flow diff --git a/src/pages/home/report/ContextMenu/ContextMenuActions.tsx b/src/pages/home/report/ContextMenu/ContextMenuActions.tsx index afb3d69d3330..c3f48ebe6385 100644 --- a/src/pages/home/report/ContextMenu/ContextMenuActions.tsx +++ b/src/pages/home/report/ContextMenu/ContextMenuActions.tsx @@ -29,6 +29,7 @@ import CONST from '@src/CONST'; import type {TranslationPaths} from '@src/languages/types'; import ROUTES from '@src/ROUTES'; import type {Beta, ReportAction, ReportActionReactions, Transaction} from '@src/types/onyx'; +import type {OriginalMessageReimbursementDequeued} from '@src/types/onyx/OriginalMessage'; import type IconAsset from '@src/types/utils/IconAsset'; import type {ContextMenuAnchor} from './ReportActionContextMenu'; import {hideContextMenu, showDeleteModal} from './ReportActionContextMenu'; @@ -342,7 +343,7 @@ const ContextMenuActions: ContextMenuAction[] = [ const modifyExpenseMessage = ModifiedExpenseMessage.getForReportAction(reportID, reportAction); Clipboard.setString(modifyExpenseMessage); } else if (ReportActionsUtils.isReimbursementDeQueuedAction(reportAction)) { - const {expenseReportID} = reportAction.originalMessage; + const {expenseReportID} = ReportActionsUtils.getReportActionOriginalMessage(reportAction); const expenseReport = ReportUtils.getReport(expenseReportID); const displayMessage = ReportUtils.getReimbursementDeQueuedActionMessage(reportAction, expenseReport); Clipboard.setString(displayMessage); diff --git a/src/pages/home/report/ContextMenu/PopoverReportActionContextMenu.tsx b/src/pages/home/report/ContextMenu/PopoverReportActionContextMenu.tsx index 6cb688ff2558..d6ecb440ec94 100644 --- a/src/pages/home/report/ContextMenu/PopoverReportActionContextMenu.tsx +++ b/src/pages/home/report/ContextMenu/PopoverReportActionContextMenu.tsx @@ -14,6 +14,7 @@ import * as IOU from '@userActions/IOU'; import * as Report from '@userActions/Report'; import type {AnchorDimensions} from '@src/styles'; import type {ReportAction} from '@src/types/onyx'; +import type {IOUMessage} from '@src/types/onyx/OriginalMessage'; import BaseReportActionContextMenu from './BaseReportActionContextMenu'; import type {ContextMenuAction} from './ContextMenuActions'; import type {ContextMenuAnchor, ContextMenuType, ReportActionContextMenu} from './ReportActionContextMenu'; @@ -265,10 +266,11 @@ function PopoverReportActionContextMenu(_props: unknown, ref: ForwardedRef (onComfirmDeleteModal.current = runAndResetCallback(onComfirmDeleteModal.current)); const reportAction = reportActionRef.current; if (ReportActionsUtils.isMoneyRequestAction(reportAction)) { + const originalMessage = ReportActionsUtils.getReportActionOriginalMessage(reportAction); if (ReportActionsUtils.isTrackExpenseAction(reportAction)) { - IOU.deleteTrackExpense(reportIDRef.current, reportAction?.originalMessage?.IOUTransactionID ?? '', reportAction); + IOU.deleteTrackExpense(reportIDRef.current, originalMessage?.IOUTransactionID ?? '', reportAction); } else { - IOU.deleteMoneyRequest(reportAction?.originalMessage?.IOUTransactionID ?? '', reportAction); + IOU.deleteMoneyRequest(originalMessage?.IOUTransactionID ?? '', reportAction); } } else if (reportAction) { Report.deleteReportComment(reportIDRef.current, reportAction); diff --git a/src/pages/home/report/ReportActionItemMessage.tsx b/src/pages/home/report/ReportActionItemMessage.tsx index 46a97a8de8d0..87ec460a56b6 100644 --- a/src/pages/home/report/ReportActionItemMessage.tsx +++ b/src/pages/home/report/ReportActionItemMessage.tsx @@ -12,7 +12,7 @@ import * as ReportUtils from '@libs/ReportUtils'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import type {ReportAction, Transaction} from '@src/types/onyx'; -import type {OriginalMessageAddComment} from '@src/types/onyx/OriginalMessage'; +import type {IOUMessage, OriginalMessageAddComment} from '@src/types/onyx/OriginalMessage'; import TextCommentFragment from './comment/TextCommentFragment'; import ReportActionItemFragment from './ReportActionItemFragment'; @@ -63,7 +63,7 @@ function ReportActionItemMessage({action, transaction, displayAsGroup, reportID, let iouMessage: string | undefined; if (isIOUReport) { - const originalMessage = action.actionName === CONST.REPORT.ACTIONS.TYPE.IOU ? action.originalMessage : null; + const originalMessage = action.actionName === CONST.REPORT.ACTIONS.TYPE.IOU ? ReportActionsUtils.getReportActionOriginalMessage(action) : null; const iouReportID = originalMessage?.IOUReportID; if (iouReportID) { iouMessage = ReportUtils.getIOUReportActionDisplayMessage(action, transaction); @@ -89,7 +89,7 @@ function ReportActionItemMessage({action, transaction, displayAsGroup, reportID, isThreadParentMessage={ReportActionsUtils.isThreadParentMessage(action, reportID)} pendingAction={action.pendingAction} actionName={action.actionName} - source={(action.originalMessage as OriginalMessageAddComment['originalMessage'])?.source} + source={ReportActionsUtils.getReportActionOriginalMessage(action)?.source} accountID={action.actorAccountID ?? 0} style={style} displayAsGroup={displayAsGroup} diff --git a/src/pages/home/report/ReportActionsListItemRenderer.tsx b/src/pages/home/report/ReportActionsListItemRenderer.tsx index 18118e48f7cb..c095f3fa0cb0 100644 --- a/src/pages/home/report/ReportActionsListItemRenderer.tsx +++ b/src/pages/home/report/ReportActionsListItemRenderer.tsx @@ -86,7 +86,7 @@ function ReportActionsListItemRenderer({ pendingAction: reportAction.pendingAction, actionName: reportAction.actionName, errors: reportAction.errors, - originalMessage: reportAction.originalMessage, + originalMessage: reportAction?.originalMessage, childCommenterCount: reportAction.childCommenterCount, linkMetadata: reportAction.linkMetadata, childReportID: reportAction.childReportID, @@ -115,7 +115,7 @@ function ReportActionsListItemRenderer({ reportAction.pendingAction, reportAction.actionName, reportAction.errors, - reportAction.originalMessage, + reportAction?.originalMessage, reportAction.childCommenterCount, reportAction.linkMetadata, reportAction.childReportID, diff --git a/src/pages/home/report/ReportActionsView.tsx b/src/pages/home/report/ReportActionsView.tsx index cd54a8b88511..82998769395c 100755 --- a/src/pages/home/report/ReportActionsView.tsx +++ b/src/pages/home/report/ReportActionsView.tsx @@ -28,6 +28,7 @@ import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import type SCREENS from '@src/SCREENS'; import type * as OnyxTypes from '@src/types/onyx'; +import type {IOUMessage} from '@src/types/onyx/OriginalMessage'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; import getInitialPaginationSize from './getInitialPaginationSize'; import PopoverReactionList from './ReactionList/PopoverReactionList'; @@ -473,14 +474,16 @@ function ReportActionsView({ } const reportPreviewAction = ReportActionsUtils.getReportPreviewAction(report.chatReportID ?? '', report.reportID); - const moneyRequestActions = reportActions.filter( - (action) => + const moneyRequestActions = reportActions.filter((action) => { + const originalMessage = ReportActionsUtils.getReportActionOriginalMessage(action); + return ( action.actionName === CONST.REPORT.ACTIONS.TYPE.IOU && - action.originalMessage && - (action.originalMessage.type === CONST.IOU.REPORT_ACTION_TYPE.CREATE || - Boolean(action.originalMessage.type === CONST.IOU.REPORT_ACTION_TYPE.PAY && action.originalMessage.IOUDetails) || - action.originalMessage.type === CONST.IOU.REPORT_ACTION_TYPE.TRACK), - ); + originalMessage && + (originalMessage.type === CONST.IOU.REPORT_ACTION_TYPE.CREATE || + Boolean(originalMessage.type === CONST.IOU.REPORT_ACTION_TYPE.PAY && originalMessage.IOUDetails) || + originalMessage.type === CONST.IOU.REPORT_ACTION_TYPE.TRACK) + ); + }); if (report.total && moneyRequestActions.length < (reportPreviewAction?.childMoneyRequestCount ?? 0) && isEmptyObject(transactionThreadReport)) { const optimisticIOUAction = ReportUtils.buildOptimisticIOUReportAction( diff --git a/src/pages/iou/SplitBillDetailsPage.tsx b/src/pages/iou/SplitBillDetailsPage.tsx index 7d0b9bb15b07..1de10f3ae920 100644 --- a/src/pages/iou/SplitBillDetailsPage.tsx +++ b/src/pages/iou/SplitBillDetailsPage.tsx @@ -12,6 +12,7 @@ import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import type {SplitDetailsNavigatorParamList} from '@libs/Navigation/types'; import * as OptionsListUtils from '@libs/OptionsListUtils'; +import * as ReportActionsUtils from '@libs/ReportActionsUtils'; import * as ReportUtils from '@libs/ReportUtils'; import * as TransactionUtils from '@libs/TransactionUtils'; import withReportAndReportActionOrNotFound from '@pages/home/report/withReportAndReportActionOrNotFound'; @@ -22,6 +23,7 @@ import ONYXKEYS from '@src/ONYXKEYS'; import type SCREENS from '@src/SCREENS'; import type {PersonalDetailsList, Report, ReportAction, Session, Transaction} from '@src/types/onyx'; import type {Participant} from '@src/types/onyx/IOU'; +import type {IOUMessage} from '@src/types/onyx/OriginalMessage'; import type {ReportActions} from '@src/types/onyx/ReportAction'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; @@ -58,7 +60,8 @@ function SplitBillDetailsPage({personalDetails, report, route, reportActions, tr const reportID = report?.reportID ?? ''; const {translate} = useLocalize(); const reportAction = useMemo(() => reportActions?.[route.params.reportActionID] ?? ({} as ReportAction), [reportActions, route.params.reportActionID]); - const participantAccountIDs = reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.IOU ? reportAction?.originalMessage.participantAccountIDs ?? [] : []; + const participantAccountIDs = + reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.IOU ? ReportActionsUtils.getReportActionOriginalMessage(reportAction).participantAccountIDs ?? [] : []; // In case this is workspace split expense, we manually add the workspace as the second participant of the split expense // because we don't save any accountID in the report action's originalMessage other than the payee's accountID @@ -145,16 +148,16 @@ const WrappedComponent = withOnyx { const reportAction = reportActions?.[route.params.reportActionID]; - const IOUTransactionID = - reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.IOU && reportAction?.originalMessage?.IOUTransactionID ? reportAction.originalMessage.IOUTransactionID : 0; + const originalMessage = ReportActionsUtils.getReportActionOriginalMessage(reportAction); + const IOUTransactionID = reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.IOU && originalMessage?.IOUTransactionID ? originalMessage.IOUTransactionID : 0; return `${ONYXKEYS.COLLECTION.TRANSACTION}${IOUTransactionID}`; }, }, draftTransaction: { key: ({route, reportActions}) => { const reportAction = reportActions?.[route.params.reportActionID]; - const IOUTransactionID = - reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.IOU && reportAction?.originalMessage?.IOUTransactionID ? reportAction.originalMessage.IOUTransactionID : 0; + const originalMessage = ReportActionsUtils.getReportActionOriginalMessage(reportAction); + const IOUTransactionID = reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.IOU && originalMessage?.IOUTransactionID ? originalMessage.IOUTransactionID : 0; return `${ONYXKEYS.COLLECTION.SPLIT_TRANSACTION_DRAFT}${IOUTransactionID}`; }, }, diff --git a/tests/actions/IOUTest.ts b/tests/actions/IOUTest.ts index 7fe5a30979b0..d5cf9b326103 100644 --- a/tests/actions/IOUTest.ts +++ b/tests/actions/IOUTest.ts @@ -18,7 +18,7 @@ import * as ReportUtils from '@src/libs/ReportUtils'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import type * as OnyxTypes from '@src/types/onyx'; -import type {IOUMessage, OriginalMessageIOU} from '@src/types/onyx/OriginalMessage'; +import type {IOUMessage, OriginalMessageIOU, OriginalMessageModifiedExpense} from '@src/types/onyx/OriginalMessage'; import type {Participant} from '@src/types/onyx/Report'; import type {ReportActionBase} from '@src/types/onyx/ReportAction'; import {toCollectionDataSet} from '@src/types/utils/CollectionDataSet'; @@ -134,21 +134,22 @@ describe('actions/IOU', () => { expect(Object.values(iouActions).length).toBe(1); createdAction = createdActions?.[0] ?? null; iouAction = iouActions?.[0] ?? null; + const originalMessage = ReportActionsUtils.getReportActionOriginalMessage(iouAction); // The CREATED action should not be created after the IOU action expect(Date.parse(createdAction?.created ?? '')).toBeLessThan(Date.parse(iouAction?.created ?? '')); // The IOUReportID should be correct - expect(iouAction.originalMessage.IOUReportID).toBe(iouReportID); + expect(originalMessage?.IOUReportID).toBe(iouReportID); // The comment should be included in the IOU action - expect(iouAction.originalMessage.comment).toBe(comment); + expect(originalMessage?.comment).toBe(comment); // The amount in the IOU action should be correct - expect(iouAction.originalMessage.amount).toBe(amount); + expect(originalMessage?.amount).toBe(amount); // The IOU type should be correct - expect(iouAction.originalMessage.type).toBe(CONST.IOU.REPORT_ACTION_TYPE.CREATE); + expect(originalMessage?.type).toBe(CONST.IOU.REPORT_ACTION_TYPE.CREATE); // Both actions should be pending expect(createdAction?.pendingAction).toBe(CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD); @@ -209,7 +210,7 @@ describe('actions/IOU', () => { expect(transaction?.pendingAction).toBe(CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD); // The transactionID on the iou action should match the one from the transactions collection - expect((iouAction?.originalMessage as IOUMessage)?.IOUTransactionID).toBe(transactionID); + expect(ReportActionsUtils.getReportActionOriginalMessage(iouAction)?.IOUTransactionID).toBe(transactionID); expect(transaction?.merchant).toBe(merchant); @@ -318,21 +319,22 @@ describe('actions/IOU', () => { Object.values(allIOUReportActions ?? {}).find( (reportAction): reportAction is ReportActionBase & OriginalMessageIOU => reportAction.actionName === CONST.REPORT.ACTIONS.TYPE.IOU, ) ?? null; + const originalMessage = ReportActionsUtils.getReportActionOriginalMessage(iouAction); // The CREATED action should not be created after the IOU action expect(Date.parse(iouCreatedAction?.created ?? '')).toBeLessThan(Date.parse(iouAction?.created ?? '')); // The IOUReportID should be correct - expect(iouAction?.originalMessage?.IOUReportID).toBe(iouReportID); + expect(originalMessage?.IOUReportID).toBe(iouReportID); // The comment should be included in the IOU action - expect(iouAction?.originalMessage?.comment).toBe(comment); + expect(originalMessage?.comment).toBe(comment); // The amount in the IOU action should be correct - expect(iouAction?.originalMessage?.amount).toBe(amount); + expect(originalMessage?.amount).toBe(amount); // The IOU action type should be correct - expect(iouAction?.originalMessage?.type).toBe(CONST.IOU.REPORT_ACTION_TYPE.CREATE); + expect(originalMessage?.type).toBe(CONST.IOU.REPORT_ACTION_TYPE.CREATE); // The IOU action should be pending expect(iouAction?.pendingAction).toBe(CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD); @@ -371,7 +373,7 @@ describe('actions/IOU', () => { expect(transaction?.pendingAction).toBe(CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD); // The transactionID on the iou action should match the one from the transactions collection - expect((iouAction?.originalMessage as IOUMessage)?.IOUTransactionID).toBe(transactionID); + expect(ReportActionsUtils.getReportActionOriginalMessage(iouAction)?.IOUTransactionID).toBe(transactionID); resolve(); }, @@ -519,17 +521,19 @@ describe('actions/IOU', () => { reportAction?.reportActionID !== createdAction.reportActionID && reportAction?.reportActionID !== iouAction?.reportActionID, ) ?? null; + const newOriginalMessage = ReportActionsUtils.getReportActionOriginalMessage(newIOUAction); + // The IOUReportID should be correct - expect(iouAction.originalMessage.IOUReportID).toBe(iouReportID); + expect(ReportActionsUtils.getReportActionOriginalMessage(iouAction).IOUReportID).toBe(iouReportID); // The comment should be included in the IOU action - expect(newIOUAction?.originalMessage.comment).toBe(comment); + expect(newOriginalMessage?.comment).toBe(comment); // The amount in the IOU action should be correct - expect(newIOUAction?.originalMessage.amount).toBe(amount); + expect(newOriginalMessage?.amount).toBe(amount); // The type of the IOU action should be correct - expect(newIOUAction?.originalMessage.type).toBe(CONST.IOU.REPORT_ACTION_TYPE.CREATE); + expect(newOriginalMessage?.type).toBe(CONST.IOU.REPORT_ACTION_TYPE.CREATE); // The IOU action should be pending expect(newIOUAction?.pendingAction).toBe(CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD); @@ -560,7 +564,7 @@ describe('actions/IOU', () => { expect(newTransaction?.pendingAction).toBe(CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD); // The transactionID on the iou action should match the one from the transactions collection - expect((newIOUAction?.originalMessage as IOUMessage)?.IOUTransactionID).toBe(newTransaction?.transactionID); + expect(ReportActionsUtils.getReportActionOriginalMessage(newIOUAction)?.IOUTransactionID).toBe(newTransaction?.transactionID); resolve(); }, @@ -667,21 +671,22 @@ describe('actions/IOU', () => { expect(Object.values(iouActions).length).toBe(1); createdAction = createdActions[0]; iouAction = iouActions[0]; + const originalMessage = ReportActionsUtils.getReportActionOriginalMessage(iouAction); // The CREATED action should not be created after the IOU action expect(Date.parse(createdAction?.created ?? '')).toBeLessThan(Date.parse(iouAction?.created ?? {})); // The IOUReportID should be correct - expect(iouAction.originalMessage.IOUReportID).toBe(iouReportID); + expect(originalMessage?.IOUReportID).toBe(iouReportID); // The comment should be included in the IOU action - expect(iouAction.originalMessage.comment).toBe(comment); + expect(originalMessage?.comment).toBe(comment); // The amount in the IOU action should be correct - expect(iouAction.originalMessage.amount).toBe(amount); + expect(originalMessage?.amount).toBe(amount); // The type should be correct - expect(iouAction.originalMessage.type).toBe(CONST.IOU.REPORT_ACTION_TYPE.CREATE); + expect(originalMessage?.type).toBe(CONST.IOU.REPORT_ACTION_TYPE.CREATE); // Both actions should be pending expect(createdAction?.pendingAction).toBe(CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD); @@ -713,7 +718,7 @@ describe('actions/IOU', () => { expect(transaction?.pendingAction).toBe(CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD); // The transactionID on the iou action should match the one from the transactions collection - expect((iouAction?.originalMessage as IOUMessage)?.IOUTransactionID).toBe(transactionID); + expect(ReportActionsUtils.getReportActionOriginalMessage(iouAction)?.IOUTransactionID).toBe(transactionID); resolve(); }, @@ -1191,11 +1196,13 @@ describe('actions/IOU', () => { Object.values(carlosReportActions ?? {}).find( (reportAction): reportAction is ReportActionBase & OriginalMessageIOU => reportAction.actionName === CONST.REPORT.ACTIONS.TYPE.IOU, ) ?? null; + const carlosOriginalMessage = ReportActionsUtils.getReportActionOriginalMessage(carlosIOUAction); + expect(carlosIOUAction?.pendingAction).toBe(CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD); - expect(carlosIOUAction?.originalMessage.IOUReportID).toBe(carlosIOUReport?.reportID); - expect(carlosIOUAction?.originalMessage.amount).toBe(amount / 4); - expect(carlosIOUAction?.originalMessage.comment).toBe(comment); - expect(carlosIOUAction?.originalMessage.type).toBe(CONST.IOU.REPORT_ACTION_TYPE.CREATE); + expect(carlosOriginalMessage.IOUReportID).toBe(carlosIOUReport?.reportID); + expect(carlosOriginalMessage.amount).toBe(amount / 4); + expect(carlosOriginalMessage.comment).toBe(comment); + expect(carlosOriginalMessage.type).toBe(CONST.IOU.REPORT_ACTION_TYPE.CREATE); expect(Date.parse(carlosIOUCreatedAction?.created ?? '')).toBeLessThan(Date.parse(carlosIOUAction?.created ?? '')); // Jules DM should have three reportActions, the existing CREATED action, the existing IOU action, and a new pending IOU action @@ -1210,11 +1217,13 @@ describe('actions/IOU', () => { (reportAction): reportAction is ReportActionBase & OriginalMessageIOU => reportAction.reportActionID !== julesCreatedAction.reportActionID && reportAction.reportActionID !== julesExistingIOUAction.reportActionID, ) ?? null; + const julesOriginalMessage = ReportActionsUtils.getReportActionOriginalMessage(julesIOUAction); + expect(julesIOUAction?.pendingAction).toBe(CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD); - expect(julesIOUAction?.originalMessage.IOUReportID).toBe(julesIOUReport?.reportID); - expect(julesIOUAction?.originalMessage.amount).toBe(amount / 4); - expect(julesIOUAction?.originalMessage.comment).toBe(comment); - expect(julesIOUAction?.originalMessage.type).toBe(CONST.IOU.REPORT_ACTION_TYPE.CREATE); + expect(julesOriginalMessage.IOUReportID).toBe(julesIOUReport?.reportID); + expect(julesOriginalMessage.amount).toBe(amount / 4); + expect(julesOriginalMessage.comment).toBe(comment); + expect(julesOriginalMessage.type).toBe(CONST.IOU.REPORT_ACTION_TYPE.CREATE); expect(Date.parse(julesIOUCreatedAction?.created ?? '')).toBeLessThan(Date.parse(julesIOUAction?.created ?? '')); // Vit DM should have two reportActions – a pending CREATED action and a pending IOU action @@ -1227,12 +1236,14 @@ describe('actions/IOU', () => { Object.values(vitReportActions ?? {}).find( (reportAction): reportAction is ReportActionBase & OriginalMessageIOU => reportAction.actionName === CONST.REPORT.ACTIONS.TYPE.IOU, ) ?? null; + const vitOriginalMessage = ReportActionsUtils.getReportActionOriginalMessage(vitIOUAction); + expect(vitCreatedAction?.pendingAction).toBe(CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD); expect(vitIOUAction?.pendingAction).toBe(CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD); - expect(vitIOUAction?.originalMessage.IOUReportID).toBe(vitIOUReport?.reportID); - expect(vitIOUAction?.originalMessage.amount).toBe(amount / 4); - expect(vitIOUAction?.originalMessage.comment).toBe(comment); - expect(vitIOUAction?.originalMessage.type).toBe(CONST.IOU.REPORT_ACTION_TYPE.CREATE); + expect(vitOriginalMessage.IOUReportID).toBe(vitIOUReport?.reportID); + expect(vitOriginalMessage.amount).toBe(amount / 4); + expect(vitOriginalMessage.comment).toBe(comment); + expect(vitOriginalMessage.type).toBe(CONST.IOU.REPORT_ACTION_TYPE.CREATE); expect(Date.parse(vitCreatedAction?.created ?? '')).toBeLessThan(Date.parse(vitIOUAction?.created ?? '')); // Group chat should have two reportActions – a pending CREATED action and a pending IOU action w/ type SPLIT @@ -1243,10 +1254,12 @@ describe('actions/IOU', () => { Object.values(groupReportActions ?? {}).find( (reportAction): reportAction is ReportActionBase & OriginalMessageIOU => reportAction.actionName === CONST.REPORT.ACTIONS.TYPE.IOU, ) ?? null; + const groupOriginalMessage = ReportActionsUtils.getReportActionOriginalMessage(groupIOUAction); + expect(groupCreatedAction?.pendingAction).toBe(CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD); expect(groupIOUAction?.pendingAction).toBe(CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD); - expect(groupIOUAction?.originalMessage).not.toHaveProperty('IOUReportID'); - expect(groupIOUAction?.originalMessage?.type).toBe(CONST.IOU.REPORT_ACTION_TYPE.SPLIT); + expect(groupOriginalMessage).not.toHaveProperty('IOUReportID'); + expect(groupOriginalMessage?.type).toBe(CONST.IOU.REPORT_ACTION_TYPE.SPLIT); expect(Date.parse(groupCreatedAction?.created ?? '')).toBeLessThanOrEqual(Date.parse(groupIOUAction?.created ?? '')); resolve(); @@ -1273,15 +1286,15 @@ describe('actions/IOU', () => { carlosTransaction = Object.values(allTransactions ?? {}).find( - (transaction) => transaction?.transactionID === (carlosIOUAction?.originalMessage as IOUMessage)?.IOUTransactionID, + (transaction) => transaction?.transactionID === ReportActionsUtils.getReportActionOriginalMessage(carlosIOUAction)?.IOUTransactionID, ) ?? null; julesTransaction = Object.values(allTransactions ?? {}).find( - (transaction) => transaction?.transactionID === (julesIOUAction?.originalMessage as IOUMessage)?.IOUTransactionID, + (transaction) => transaction?.transactionID === ReportActionsUtils.getReportActionOriginalMessage(julesIOUAction)?.IOUTransactionID, ) ?? null; vitTransaction = Object.values(allTransactions ?? {}).find( - (transaction) => transaction?.transactionID === (vitIOUAction?.originalMessage as IOUMessage)?.IOUTransactionID, + (transaction) => transaction?.transactionID === ReportActionsUtils.getReportActionOriginalMessage(vitIOUAction)?.IOUTransactionID, ) ?? null; groupTransaction = Object.values(allTransactions ?? {}).find((transaction) => transaction?.reportID === CONST.REPORT.SPLIT_REPORTID) ?? null; @@ -1453,7 +1466,7 @@ describe('actions/IOU', () => { createIOUAction = Object.values(reportActionsForIOUReport ?? {}).find((reportAction) => reportAction.actionName === CONST.REPORT.ACTIONS.TYPE.IOU) ?? null; expect(createIOUAction).toBeTruthy(); - expect((createIOUAction?.originalMessage as IOUMessage)?.IOUReportID).toBe(iouReport?.reportID); + expect(ReportActionsUtils.getReportActionOriginalMessage(createIOUAction)?.IOUReportID).toBe(iouReport?.reportID); resolve(); }, @@ -1473,7 +1486,7 @@ describe('actions/IOU', () => { expect(transaction).toBeTruthy(); expect(transaction?.amount).toBe(amount); expect(transaction?.reportID).toBe(iouReport?.reportID); - expect((createIOUAction?.originalMessage as IOUMessage)?.IOUTransactionID).toBe(transaction?.transactionID); + expect(ReportActionsUtils.getReportActionOriginalMessage(createIOUAction)?.IOUTransactionID).toBe(transaction?.transactionID); resolve(); }, }); @@ -1525,7 +1538,8 @@ describe('actions/IOU', () => { payIOUAction = Object.values(reportActionsForIOUReport ?? {}).find( (reportAction) => - reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.IOU && reportAction?.originalMessage?.type === CONST.IOU.REPORT_ACTION_TYPE.PAY, + reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.IOU && + ReportActionsUtils.getReportActionOriginalMessage(reportAction)?.type === CONST.IOU.REPORT_ACTION_TYPE.PAY, ) ?? null; expect(payIOUAction).toBeTruthy(); expect(payIOUAction?.pendingAction).toBe(CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD); @@ -1575,7 +1589,8 @@ describe('actions/IOU', () => { payIOUAction = Object.values(reportActionsForIOUReport ?? {}).find( (reportAction) => - reportAction.actionName === CONST.REPORT.ACTIONS.TYPE.IOU && reportAction.originalMessage.type === CONST.IOU.REPORT_ACTION_TYPE.PAY, + reportAction.actionName === CONST.REPORT.ACTIONS.TYPE.IOU && + ReportActionsUtils.getReportActionOriginalMessage(reportAction).type === CONST.IOU.REPORT_ACTION_TYPE.PAY, ) ?? null; expect(payIOUAction).toBeTruthy(); @@ -1707,7 +1722,7 @@ describe('actions/IOU', () => { Onyx.disconnect(connectionID); const updatedAction = Object.values(allActions ?? {}).find((reportAction) => !isEmptyObject(reportAction)); expect(updatedAction?.actionName).toEqual('MODIFIEDEXPENSE'); - expect(updatedAction?.originalMessage).toEqual( + expect(ReportActionsUtils.getReportActionOriginalMessage(updatedAction)).toEqual( expect.objectContaining({amount: 20000, newComment: 'Double the amount!', oldAmount: amount, oldComment: comment}), ); resolve(); @@ -2192,7 +2207,7 @@ describe('actions/IOU', () => { (reportAction): reportAction is ReportActionBase & OriginalMessageIOU => reportAction.actionName === CONST.REPORT.ACTIONS.TYPE.IOU, ) ?? null; expect(createIOUAction).toBeTruthy(); - expect(createIOUAction?.originalMessage.IOUReportID).toBe(iouReport?.reportID); + expect(ReportActionsUtils.getReportActionOriginalMessage(createIOUAction).IOUReportID).toBe(iouReport?.reportID); // When fetching all transactions from Onyx const allTransactions = await new Promise>((resolve) => { @@ -2211,7 +2226,7 @@ describe('actions/IOU', () => { expect(transaction).toBeTruthy(); expect(transaction?.amount).toBe(amount); expect(transaction?.reportID).toBe(iouReport?.reportID); - expect(createIOUAction?.originalMessage.IOUTransactionID).toBe(transaction?.transactionID); + expect(ReportActionsUtils.getReportActionOriginalMessage(createIOUAction).IOUTransactionID).toBe(transaction?.transactionID); }); afterEach(PusherHelper.teardown); diff --git a/tests/actions/PolicyMemberTest.ts b/tests/actions/PolicyMemberTest.ts index 4f3afc51ec66..1c9df151a5c2 100644 --- a/tests/actions/PolicyMemberTest.ts +++ b/tests/actions/PolicyMemberTest.ts @@ -2,6 +2,7 @@ import Onyx from 'react-native-onyx'; import CONST from '@src/CONST'; import OnyxUpdateManager from '@src/libs/actions/OnyxUpdateManager'; import * as Policy from '@src/libs/actions/Policy'; +import * as ReportActionsUtils from '@src/libs/ReportActionsUtils'; import ONYXKEYS from '@src/ONYXKEYS'; import type {Policy as PolicyType, Report, ReportAction} from '@src/types/onyx'; import type {OriginalMessageJoinPolicyChangeLog} from '@src/types/onyx/OriginalMessage'; @@ -59,7 +60,7 @@ describe('actions/PolicyMember', () => { const reportAction = reportActions?.[fakeReportAction.reportActionID]; if (!isEmptyObject(reportAction)) { - expect((reportAction.originalMessage as OriginalMessageJoinPolicyChangeLog['originalMessage'])?.choice)?.toBe( + expect(ReportActionsUtils.getReportActionOriginalMessage(reportAction)?.choice)?.toBe( CONST.REPORT.ACTIONABLE_MENTION_JOIN_WORKSPACE_RESOLUTION.ACCEPT, ); expect(reportAction?.pendingAction).toBe(CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE); From ff08fe1ce992ab42b4c12fccb2940002a41e9816 Mon Sep 17 00:00:00 2001 From: nkdengineer Date: Tue, 28 May 2024 18:33:44 +0700 Subject: [PATCH 15/45] remove originalMessage in MoneyRequestHeader --- src/components/MoneyRequestHeader.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/MoneyRequestHeader.tsx b/src/components/MoneyRequestHeader.tsx index d1cf8866d04e..c0006b2c8d96 100644 --- a/src/components/MoneyRequestHeader.tsx +++ b/src/components/MoneyRequestHeader.tsx @@ -19,7 +19,7 @@ import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import type {Policy, Report, ReportAction} from '@src/types/onyx'; -import type {IOUMessage, OriginalMessageIOU} from '@src/types/onyx/OriginalMessage'; +import type {IOUMessage} from '@src/types/onyx/OriginalMessage'; import type IconAsset from '@src/types/utils/IconAsset'; import Button from './Button'; import ConfirmModal from './ConfirmModal'; @@ -49,7 +49,7 @@ type MoneyRequestHeaderProps = { function MoneyRequestHeader({report, parentReportAction, policy, shouldUseNarrowLayout = false, onBackButtonPress}: MoneyRequestHeaderProps) { const [parentReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${report.parentReportID}`); - const [transaction] = useOnyx(`${ONYXKEYS.COLLECTION.TRANSACTION}${(parentReportAction as ReportAction & OriginalMessageIOU)?.originalMessage?.IOUTransactionID ?? 0}`); + const [transaction] = useOnyx(`${ONYXKEYS.COLLECTION.TRANSACTION}${ReportActionsUtils.getReportActionOriginalMessage(parentReportAction)?.IOUTransactionID ?? 0}`); const [transactionViolations] = useOnyx(ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS); const [session] = useOnyx(ONYXKEYS.SESSION); const [shownHoldUseExplanation] = useOnyx(ONYXKEYS.NVP_HOLD_USE_EXPLAINED, {initWithStoredValues: false}); From c966d0e6a34b466ffa2e684ff2c62cd1602ee0c6 Mon Sep 17 00:00:00 2001 From: nkdengineer Date: Mon, 3 Jun 2024 17:55:15 +0700 Subject: [PATCH 16/45] refactor type of originalMessage --- src/components/AttachmentModal.tsx | 2 +- .../LHNOptionsList/LHNOptionsList.tsx | 4 +- src/components/MoneyReportHeader.tsx | 4 +- src/components/MoneyRequestHeader.tsx | 6 +- .../MoneyRequestPreviewContent.tsx | 4 +- .../MoneyRequestPreview/index.tsx | 2 +- .../ReportActionItem/MoneyRequestView.tsx | 4 +- src/libs/OptionsListUtils.ts | 2 +- src/libs/ReportActionsUtils.ts | 115 ++--- src/libs/ReportUtils.ts | 18 +- src/libs/actions/IOU.ts | 6 +- src/libs/actions/Report.ts | 2 +- .../home/report/ReportActionItemMessage.tsx | 2 +- src/pages/home/report/ReportActionsView.tsx | 2 +- src/pages/iou/SplitBillDetailsPage.tsx | 2 +- src/types/onyx/OriginalMessage.ts | 456 +++++++----------- src/types/onyx/ReportAction.ts | 35 +- src/types/onyx/ReportActionName.ts | 6 + tests/actions/IOUTest.ts | 36 +- 19 files changed, 309 insertions(+), 399 deletions(-) create mode 100644 src/types/onyx/ReportActionName.ts diff --git a/src/components/AttachmentModal.tsx b/src/components/AttachmentModal.tsx index f3b1e8c956c9..f9310d24c2f3 100644 --- a/src/components/AttachmentModal.tsx +++ b/src/components/AttachmentModal.tsx @@ -620,7 +620,7 @@ export default withOnyx({ const parentReportAction = ReportActionsUtils.getReportAction(report?.parentReportID ?? '', report?.parentReportActionID ?? ''); const transactionID = parentReportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.IOU - ? ReportActionsUtils.getReportActionOriginalMessage(parentReportAction).IOUTransactionID ?? '0' + ? ReportActionsUtils.getOriginalMessage(parentReportAction).IOUTransactionID ?? '0' : '0'; return `${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`; }, diff --git a/src/components/LHNOptionsList/LHNOptionsList.tsx b/src/components/LHNOptionsList/LHNOptionsList.tsx index e02f76b28505..e8cee57f463a 100644 --- a/src/components/LHNOptionsList/LHNOptionsList.tsx +++ b/src/components/LHNOptionsList/LHNOptionsList.tsx @@ -114,7 +114,7 @@ function LHNOptionsList({ const itemPolicy = policy?.[`${ONYXKEYS.COLLECTION.POLICY}${itemFullReport?.policyID}`] ?? null; const transactionID = itemParentReportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.IOU - ? ReportActionsUtils.getReportActionOriginalMessage(itemParentReportAction).IOUTransactionID ?? '' + ? ReportActionsUtils.getOriginalMessage(itemParentReportAction).IOUTransactionID ?? '' : ''; const itemTransaction = transactions?.[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`] ?? null; const hasDraftComment = DraftCommentUtils.isValidDraftComment(draftComments?.[`${ONYXKEYS.COLLECTION.REPORT_DRAFT_COMMENT}${reportID}`]); @@ -125,7 +125,7 @@ function LHNOptionsList({ let lastReportActionTransactionID = ''; if (lastReportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.IOU) { - lastReportActionTransactionID = ReportActionsUtils.getReportActionOriginalMessage(lastReportAction)?.IOUTransactionID ?? ''; + lastReportActionTransactionID = ReportActionsUtils.getOriginalMessage(lastReportAction)?.IOUTransactionID ?? ''; } const lastReportActionTransaction = transactions?.[`${ONYXKEYS.COLLECTION.TRANSACTION}${lastReportActionTransactionID}`] ?? {}; diff --git a/src/components/MoneyReportHeader.tsx b/src/components/MoneyReportHeader.tsx index f3d3a46f688e..e41a5e64c6da 100644 --- a/src/components/MoneyReportHeader.tsx +++ b/src/components/MoneyReportHeader.tsx @@ -145,7 +145,7 @@ function MoneyReportHeader({policy, report: moneyRequestReport, transactionThrea if (requestParentReportAction) { const iouTransactionID = requestParentReportAction.actionName === CONST.REPORT.ACTIONS.TYPE.IOU - ? ReportActionsUtils.getReportActionOriginalMessage(requestParentReportAction)?.IOUTransactionID ?? '' + ? ReportActionsUtils.getOriginalMessage(requestParentReportAction)?.IOUTransactionID ?? '' : ''; if (ReportActionsUtils.isTrackExpenseAction(requestParentReportAction)) { IOU.deleteTrackExpense(moneyRequestReport?.reportID ?? '', iouTransactionID, requestParentReportAction, true); @@ -163,7 +163,7 @@ function MoneyReportHeader({policy, report: moneyRequestReport, transactionThrea } const iouTransactionID = requestParentReportAction.actionName === CONST.REPORT.ACTIONS.TYPE.IOU - ? ReportActionsUtils.getReportActionOriginalMessage(requestParentReportAction)?.IOUTransactionID ?? '' + ? ReportActionsUtils.getOriginalMessage(requestParentReportAction)?.IOUTransactionID ?? '' : ''; const reportID = transactionThreadReport?.reportID ?? ''; diff --git a/src/components/MoneyRequestHeader.tsx b/src/components/MoneyRequestHeader.tsx index 03a51254ce12..cdff4a9a8d9a 100644 --- a/src/components/MoneyRequestHeader.tsx +++ b/src/components/MoneyRequestHeader.tsx @@ -49,7 +49,7 @@ type MoneyRequestHeaderProps = { function MoneyRequestHeader({report, parentReportAction, policy, shouldUseNarrowLayout = false, onBackButtonPress}: MoneyRequestHeaderProps) { const [parentReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${report.parentReportID}`); - const [transaction] = useOnyx(`${ONYXKEYS.COLLECTION.TRANSACTION}${ReportActionsUtils.getReportActionOriginalMessage(parentReportAction)?.IOUTransactionID ?? 0}`); + const [transaction] = useOnyx(`${ONYXKEYS.COLLECTION.TRANSACTION}${ReportActionsUtils.getOriginalMessage(parentReportAction)?.IOUTransactionID ?? 0}`); const [transactionViolations] = useOnyx(ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS); const [session] = useOnyx(ONYXKEYS.SESSION); const [shownHoldUseExplanation] = useOnyx(ONYXKEYS.NVP_HOLD_USE_EXPLAINED, {initWithStoredValues: false}); @@ -77,7 +77,7 @@ function MoneyRequestHeader({report, parentReportAction, policy, shouldUseNarrow if (parentReportAction) { const iouTransactionID = parentReportAction.actionName === CONST.REPORT.ACTIONS.TYPE.IOU - ? ReportActionsUtils.getReportActionOriginalMessage(parentReportAction)?.IOUTransactionID ?? '' + ? ReportActionsUtils.getOriginalMessage(parentReportAction)?.IOUTransactionID ?? '' : ''; if (ReportActionsUtils.isTrackExpenseAction(parentReportAction)) { IOU.deleteTrackExpense(parentReport?.reportID ?? '', iouTransactionID, parentReportAction, true); @@ -103,7 +103,7 @@ function MoneyRequestHeader({report, parentReportAction, policy, shouldUseNarrow const changeMoneyRequestStatus = () => { const iouTransactionID = - parentReportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.IOU ? ReportActionsUtils.getReportActionOriginalMessage(parentReportAction)?.IOUTransactionID ?? '' : ''; + parentReportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.IOU ? ReportActionsUtils.getOriginalMessage(parentReportAction)?.IOUTransactionID ?? '' : ''; if (isOnHold) { IOU.unholdRequest(iouTransactionID, report?.reportID); diff --git a/src/components/ReportActionItem/MoneyRequestPreview/MoneyRequestPreviewContent.tsx b/src/components/ReportActionItem/MoneyRequestPreview/MoneyRequestPreviewContent.tsx index f2c7e8ddd263..190abe61bc0d 100644 --- a/src/components/ReportActionItem/MoneyRequestPreview/MoneyRequestPreviewContent.tsx +++ b/src/components/ReportActionItem/MoneyRequestPreview/MoneyRequestPreviewContent.tsx @@ -76,7 +76,7 @@ function MoneyRequestPreviewContent({ const participantAccountIDs = action.actionName === CONST.REPORT.ACTIONS.TYPE.IOU && isBillSplit - ? ReportActionsUtils.getReportActionOriginalMessage(action).participantAccountIDs ?? [] + ? ReportActionsUtils.getOriginalMessage(action).participantAccountIDs ?? [] : [managerID, ownerAccountID]; const participantAvatars = OptionsListUtils.getAvatarsForAccountIDs(participantAccountIDs, personalDetails ?? {}); const sortedParticipantAvatars = lodashSortBy(participantAvatars, (avatar) => avatar.id); @@ -222,7 +222,7 @@ function MoneyRequestPreviewContent({ const getDisplayDeleteAmountText = (): string => { const iouOriginalMessage: IOUMessage | EmptyObject = - action?.actionName === CONST.REPORT.ACTIONS.TYPE.IOU ? ReportActionsUtils.getReportActionOriginalMessage(action) : {}; + action?.actionName === CONST.REPORT.ACTIONS.TYPE.IOU ? ReportActionsUtils.getOriginalMessage(action) : {}; const {amount = 0, currency = CONST.CURRENCY.USD} = iouOriginalMessage; return CurrencyUtils.convertToDisplayString(amount, currency); diff --git a/src/components/ReportActionItem/MoneyRequestPreview/index.tsx b/src/components/ReportActionItem/MoneyRequestPreview/index.tsx index 8ec71a228a47..3733cd553de3 100644 --- a/src/components/ReportActionItem/MoneyRequestPreview/index.tsx +++ b/src/components/ReportActionItem/MoneyRequestPreview/index.tsx @@ -32,7 +32,7 @@ export default withOnyx( transaction: { key: ({action}) => { const isMoneyRequestAction = ReportActionsUtils.isMoneyRequestAction(action); - const transactionID = isMoneyRequestAction ? ReportActionsUtils.getReportActionOriginalMessage(action)?.IOUTransactionID : 0; + const transactionID = isMoneyRequestAction ? ReportActionsUtils.getOriginalMessage(action)?.IOUTransactionID : 0; return `${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`; }, }, diff --git a/src/components/ReportActionItem/MoneyRequestView.tsx b/src/components/ReportActionItem/MoneyRequestView.tsx index 7486eff9d344..c55a1930b7bd 100644 --- a/src/components/ReportActionItem/MoneyRequestView.tsx +++ b/src/components/ReportActionItem/MoneyRequestView.tsx @@ -605,7 +605,7 @@ export default withOnyx { const parentReportAction = parentReportActions?.[report.parentReportActionID ?? '']; const originalMessage = - parentReportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.IOU ? ReportActionsUtils.getReportActionOriginalMessage(parentReportAction) : undefined; + parentReportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.IOU ? ReportActionsUtils.getOriginalMessage(parentReportAction) : undefined; const transactionID = originalMessage?.IOUTransactionID ?? 0; return `${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`; }, @@ -614,7 +614,7 @@ export default withOnyx { const parentReportAction = parentReportActions?.[report.parentReportActionID ?? '']; const originalMessage = - parentReportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.IOU ? ReportActionsUtils.getReportActionOriginalMessage(parentReportAction) : undefined; + parentReportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.IOU ? ReportActionsUtils.getOriginalMessage(parentReportAction) : undefined; const transactionID = originalMessage?.IOUTransactionID ?? 0; return `${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transactionID}`; }, diff --git a/src/libs/OptionsListUtils.ts b/src/libs/OptionsListUtils.ts index c138611c0416..e3e1ca175b1b 100644 --- a/src/libs/OptionsListUtils.ts +++ b/src/libs/OptionsListUtils.ts @@ -534,7 +534,7 @@ function getAllReportErrors(report: OnyxEntry, reportActions: OnyxEntry< if (parentReportAction?.actorAccountID === currentUserAccountID && ReportActionUtils.isTransactionThread(parentReportAction)) { const transactionID = - parentReportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.IOU ? ReportActionUtils.getReportActionOriginalMessage(parentReportAction)?.IOUTransactionID : null; + parentReportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.IOU ? ReportActionUtils.getOriginalMessage(parentReportAction)?.IOUTransactionID : null; const transaction = allTransactions?.[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`]; if (TransactionUtils.hasMissingSmartscanFields(transaction ?? null) && !ReportUtils.isSettled(transaction?.reportID)) { reportActionErrors.smartscan = ErrorUtils.getMicroSecondOnyxError('report.genericSmartscanFailureMessage'); diff --git a/src/libs/ReportActionsUtils.ts b/src/libs/ReportActionsUtils.ts index 57d8da13d732..710801f76643 100644 --- a/src/libs/ReportActionsUtils.ts +++ b/src/libs/ReportActionsUtils.ts @@ -8,22 +8,8 @@ import type {ValueOf} from 'type-fest'; import CONST from '@src/CONST'; import type {TranslationPaths} from '@src/languages/types'; import ONYXKEYS from '@src/ONYXKEYS'; -import type { - ActionName, - ChangeLog, - IOUMessage, - OriginalMessageActionableMentionWhisper, - OriginalMessageActionableReportMentionWhisper, - OriginalMessageActionableTrackedExpenseWhisper, - OriginalMessageAddComment, - OriginalMessageDismissedViolation, - OriginalMessageIOU, - OriginalMessageJoinPolicyChangeLog, - OriginalMessageReimbursementDequeued, - OriginalMessageReportPreview, -} from '@src/types/onyx/OriginalMessage'; import type Report from '@src/types/onyx/Report'; -import type {Message, ReportActionBase, ReportActionMessageJSON, ReportActions} from '@src/types/onyx/ReportAction'; +import type {Message, OriginalMessage, ReportActions} from '@src/types/onyx/ReportAction'; import type ReportAction from '@src/types/onyx/ReportAction'; import type {EmptyObject} from '@src/types/utils/EmptyObject'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; @@ -37,6 +23,7 @@ import * as PersonalDetailsUtils from './PersonalDetailsUtils'; import type {OptimisticIOUReportAction, PartialReportAction} from './ReportUtils'; import StringUtils from './StringUtils'; import * as TransactionUtils from './TransactionUtils'; +import ReportActionName from '@src/types/onyx/ReportActionName'; type LastVisibleMessage = { lastMessageTranslationKey?: string; @@ -135,7 +122,7 @@ function isPendingRemove(reportAction: OnyxEntry | EmptyObject): b return getReportActionMessage(reportAction)?.moderationDecision?.decision === CONST.MODERATION.MODERATOR_DECISION_PENDING_REMOVE; } -function isMoneyRequestAction(reportAction: OnyxEntry): reportAction is ReportAction & OriginalMessageIOU { +function isMoneyRequestAction(reportAction: OnyxEntry): reportAction is ReportAction { return reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.IOU; } @@ -155,26 +142,46 @@ function getReportActionOriginalMessage(reportAction: PartialReportAction) { return (reportAction?.originalMessage ?? reportAction?.message?.[0] ?? reportAction?.message) as T; } +function isActionOfType(action: OnyxEntry, ...actionNames: T): action is ({ + [K in keyof T]: ReportAction +}[number]) { + return actionNames.includes(action?.actionName as T[number]); +} + +function getOriginalMessage(reportAction: ReportAction): OriginalMessage { + if (!Array.isArray(reportAction?.message)) { + return reportAction?.message ?? reportAction?.originalMessage; + } + return reportAction.originalMessage; +} + +function getMessage(reportAction: OnyxEntry>): OriginalMessage | Message | undefined { + if (!Array.isArray(reportAction?.message)) { + return reportAction?.message ?? reportAction?.originalMessage; + } + return reportAction.originalMessage ?? reportAction.message?.[0]; +} + /** * We are in the process of deprecating reportAction.originalMessage and will be setting the db version of "message" to reportAction.message in the future see: https://github.com/Expensify/App/issues/39797 * In the interim, we must check to see if we have an object or array for the reportAction.message, if we have an array we will use the originalMessage as this means we have not yet migrated. */ -function getWhisperedTo(reportAction: OnyxEntry | EmptyObject): number[] { - const originalMessage = getReportActionOriginalMessage(reportAction); +function getWhisperedTo(reportAction: OnyxEntry): number[] { + const originalMessage = getMessage(reportAction); const message = reportAction?.message; if (!Array.isArray(message) && typeof message === 'object') { - return (message as ReportActionMessageJSON)?.whisperedTo ?? []; + return (message)?.whisperedTo ?? []; } if (originalMessage) { - return (originalMessage as ReportActionMessageJSON)?.whisperedTo ?? []; + return (originalMessage)?.whisperedTo ?? []; } return []; } -function isWhisperAction(reportAction: OnyxEntry | EmptyObject): boolean { +function isWhisperAction(reportAction: OnyxEntry): boolean { return getWhisperedTo(reportAction).length > 0; } @@ -193,13 +200,7 @@ function isReimbursementQueuedAction(reportAction: OnyxEntry) { } function isMemberChangeAction(reportAction: OnyxEntry) { - return ( - reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.ROOM_CHANGE_LOG.INVITE_TO_ROOM || - reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.ROOM_CHANGE_LOG.REMOVE_FROM_ROOM || - reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.POLICY_CHANGE_LOG.INVITE_TO_ROOM || - reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.POLICY_CHANGE_LOG.REMOVE_FROM_ROOM || - reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.POLICY_CHANGE_LOG.LEAVE_POLICY - ); + return isActionOfType(reportAction, CONST.REPORT.ACTIONS.TYPE.ROOM_CHANGE_LOG.INVITE_TO_ROOM, CONST.REPORT.ACTIONS.TYPE.ROOM_CHANGE_LOG.REMOVE_FROM_ROOM, CONST.REPORT.ACTIONS.TYPE.POLICY_CHANGE_LOG.INVITE_TO_ROOM, CONST.REPORT.ACTIONS.TYPE.POLICY_CHANGE_LOG.REMOVE_FROM_ROOM, CONST.REPORT.ACTIONS.TYPE.POLICY_CHANGE_LOG.LEAVE_POLICY); } function isInviteMemberAction(reportAction: OnyxEntry) { @@ -210,7 +211,7 @@ function isLeavePolicyAction(reportAction: OnyxEntry) { return reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.POLICY_CHANGE_LOG.LEAVE_POLICY; } -function isReimbursementDeQueuedAction(reportAction: OnyxEntry): reportAction is ReportActionBase & OriginalMessageReimbursementDequeued { +function isReimbursementDeQueuedAction(reportAction: OnyxEntry): reportAction is ReportAction { return reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.REIMBURSEMENT_DEQUEUED; } @@ -238,8 +239,7 @@ function getParentReportAction(report: OnyxEntry | EmptyObject): ReportA * Determines if the given report action is sent money report action by checking for 'pay' type and presence of IOUDetails object. */ function isSentMoneyReportAction(reportAction: OnyxEntry): boolean { - const originalMessage = getReportActionOriginalMessage(reportAction); - return reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.IOU && originalMessage?.type === CONST.IOU.REPORT_ACTION_TYPE.PAY && !!originalMessage?.IOUDetails; + return isActionOfType(reportAction, CONST.REPORT.ACTIONS.TYPE.IOU) && getOriginalMessage(reportAction)?.type === CONST.IOU.REPORT_ACTION_TYPE.PAY && !!getOriginalMessage(reportAction)?.IOUDetails; } /** @@ -247,12 +247,15 @@ function isSentMoneyReportAction(reportAction: OnyxEntry | EmptyObject): boolean { - const originalMessage = getReportActionOriginalMessage(parentReportAction); + if (isEmptyObject(parentReportAction)) { + return false; + } + const originalMessage = getOriginalMessage(parentReportAction); return ( parentReportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.IOU && - (originalMessage.type === CONST.IOU.REPORT_ACTION_TYPE.CREATE || - originalMessage.type === CONST.IOU.REPORT_ACTION_TYPE.TRACK || - (originalMessage.type === CONST.IOU.REPORT_ACTION_TYPE.PAY && !!originalMessage.IOUDetails)) + (originalMessage?.type === CONST.IOU.REPORT_ACTION_TYPE.CREATE || + originalMessage?.type === CONST.IOU.REPORT_ACTION_TYPE.TRACK || + (originalMessage?.type === CONST.IOU.REPORT_ACTION_TYPE.PAY && !!originalMessage?.IOUDetails)) ); } @@ -331,7 +334,7 @@ function getCombinedReportActions(reportActions: ReportAction[], transactionThre const isSelfDM = report?.chatType === CONST.REPORT.CHAT_TYPE.SELF_DM; // Filter out request and send money request actions because we don't want to show any preview actions for one transaction reports const filteredReportActions = [...reportActions, ...filteredTransactionThreadReportActions].filter((action) => { - const actionType = getReportActionOriginalMessage(action)?.type ?? ''; + const actionType = getOriginalMessage(action)?.type ?? ''; if (isSelfDM) { return actionType !== CONST.IOU.REPORT_ACTION_TYPE.CREATE && !isSentMoneyReportAction(action); } @@ -399,7 +402,7 @@ function getMostRecentIOURequestActionID(reportActions: ReportAction[] | null): CONST.IOU.REPORT_ACTION_TYPE.TRACK, ]; const iouRequestActions = - reportActions?.filter((action) => action.actionName === CONST.REPORT.ACTIONS.TYPE.IOU && iouRequestTypes.includes(getReportActionOriginalMessage(action).type)) ?? []; + reportActions?.filter((action) => isActionOfType(action, CONST.REPORT.ACTIONS.TYPE.IOU) && iouRequestTypes.includes(getOriginalMessage(action).type)) ?? []; if (iouRequestActions.length === 0) { return null; @@ -516,13 +519,13 @@ function isReportActionDeprecated(reportAction: OnyxEntry, key: st return true; } - const deprecatedOldDotReportActions: ActionName[] = [ + const deprecatedOldDotReportActions: ReportActionName[] = [ CONST.REPORT.ACTIONS.TYPE.DELETED_ACCOUNT, CONST.REPORT.ACTIONS.TYPE.REIMBURSEMENT_REQUESTED, CONST.REPORT.ACTIONS.TYPE.REIMBURSEMENT_SETUP_REQUESTED, CONST.REPORT.ACTIONS.TYPE.DONATION, ]; - if (deprecatedOldDotReportActions.includes(reportAction.actionName as ActionName)) { + if (deprecatedOldDotReportActions.includes(reportAction.actionName as ReportActionName)) { Log.info('Front end filtered out reportAction for being an older, deprecated report action', false, reportAction); return true; } @@ -531,7 +534,7 @@ function isReportActionDeprecated(reportAction: OnyxEntry, key: st } const {POLICY_CHANGE_LOG: policyChangelogTypes, ROOM_CHANGE_LOG: roomChangeLogTypes, ...otherActionTypes} = CONST.REPORT.ACTIONS.TYPE; -const supportedActionTypes: ActionName[] = [...Object.values(otherActionTypes), ...Object.values(policyChangelogTypes), ...Object.values(roomChangeLogTypes)]; +const supportedActionTypes: ReportActionName[] = [...Object.values(otherActionTypes), ...Object.values(policyChangelogTypes), ...Object.values(roomChangeLogTypes)]; /** * Checks if a reportAction is fit for display, meaning that it's not deprecated, is of a valid @@ -590,8 +593,8 @@ function shouldHideNewMarker(reportAction: OnyxEntry): boolean { * Checks whether an action is actionable track expense. * */ -function isActionableTrackExpense(reportAction: OnyxEntry): reportAction is ReportActionBase & OriginalMessageActionableTrackedExpenseWhisper { - return reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.ACTIONABLE_TRACK_EXPENSE_WHISPER; +function isActionableTrackExpense(reportAction: OnyxEntry): reportAction is ReportAction { + return isActionOfType(reportAction, CONST.REPORT.ACTIONS.TYPE.ACTIONABLE_TRACK_EXPENSE_WHISPER); } /** @@ -599,7 +602,7 @@ function isActionableTrackExpense(reportAction: OnyxEntry): report * */ function isResolvedActionTrackExpense(reportAction: OnyxEntry): boolean { - const resolution = (reportAction?.originalMessage as OriginalMessageActionableMentionWhisper['originalMessage'])?.resolution; + const resolution = reportAction && 'resolution' in reportAction ? reportAction?.resolution : null; return isActionableTrackExpense(reportAction) && !!resolution; } @@ -774,7 +777,7 @@ function getLinkedTransactionID(reportActionOrID: string | OnyxEntry(reportAction)?.IOUTransactionID ?? null; + return getOriginalMessage(reportAction)?.IOUTransactionID ?? null; } function getReportAction(reportID: string, reportActionID: string): OnyxEntry { @@ -828,8 +831,8 @@ function getReportPreviewAction(chatReportID: string, iouReportID: string): Onyx Object.values(allReportActions?.[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chatReportID}`] ?? {}).find( (reportAction) => reportAction && - reportAction.actionName === CONST.REPORT.ACTIONS.TYPE.REPORT_PREVIEW && - getReportActionOriginalMessage(reportAction).linkedReportID === iouReportID, + isActionOfType(reportAction, CONST.REPORT.ACTIONS.TYPE.REPORT_PREVIEW) && + getOriginalMessage(reportAction)?.linkedReportID === iouReportID, ) ?? null ); } @@ -838,13 +841,13 @@ function getReportPreviewAction(chatReportID: string, iouReportID: string): Onyx * Get the iouReportID for a given report action. */ function getIOUReportIDFromReportActionPreview(reportAction: OnyxEntry): string { - return reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.REPORT_PREVIEW - ? getReportActionOriginalMessage(reportAction).linkedReportID + return isActionOfType(reportAction, CONST.REPORT.ACTIONS.TYPE.REPORT_PREVIEW) + ? getOriginalMessage(reportAction)?.linkedReportID ?? '0' : '0'; } function isCreatedTaskReportAction(reportAction: OnyxEntry): boolean { - return reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.ADD_COMMENT && !!getReportActionOriginalMessage(reportAction)?.taskReportID; + return isActionOfType(reportAction, CONST.REPORT.ACTIONS.TYPE.ADD_COMMENT) && !!getOriginalMessage(reportAction)?.taskReportID; } /** @@ -862,15 +865,15 @@ function getNumberOfMoneyRequests(reportPreviewAction: OnyxEntry): } function isSplitBillAction(reportAction: OnyxEntry): boolean { - return reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.IOU && getReportActionOriginalMessage(reportAction).type === CONST.IOU.REPORT_ACTION_TYPE.SPLIT; + return isActionOfType(reportAction, CONST.REPORT.ACTIONS.TYPE.IOU) && getOriginalMessage(reportAction)?.type === CONST.IOU.REPORT_ACTION_TYPE.SPLIT; } function isTrackExpenseAction(reportAction: OnyxEntry): boolean { - return reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.IOU && getReportActionOriginalMessage(reportAction).type === CONST.IOU.REPORT_ACTION_TYPE.TRACK; + return isActionOfType(reportAction, CONST.REPORT.ACTIONS.TYPE.IOU) && getOriginalMessage(reportAction)?.type === CONST.IOU.REPORT_ACTION_TYPE.TRACK; } function isPayAction(reportAction: OnyxEntry): boolean { - return reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.IOU && (reportAction.originalMessage as IOUMessage).type === CONST.IOU.REPORT_ACTION_TYPE.PAY; + return isActionOfType(reportAction, CONST.REPORT.ACTIONS.TYPE.IOU) && getOriginalMessage(reportAction)?.type === CONST.IOU.REPORT_ACTION_TYPE.PAY; } function isTaskAction(reportAction: OnyxEntry): boolean { @@ -917,13 +920,13 @@ function getOneTransactionThreadReportID( const iouRequestActions = reportActionsArray.filter( (action) => action.actionName === CONST.REPORT.ACTIONS.TYPE.IOU && - (iouRequestTypes.includes(getReportActionOriginalMessage(action).type) ?? []) && + (iouRequestTypes.includes(getOriginalMessage(action).type) ?? []) && action.childReportID && // Include deleted IOU reportActions if: // - they have an assocaited IOU transaction ID or // - they have visibile childActions (like comments) that we'd want to display // - the action is pending deletion and the user is offline - (Boolean(getReportActionOriginalMessage(action).IOUTransactionID) || + (Boolean(getOriginalMessage(action).IOUTransactionID) || // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing (isMessageDeleted(action) && action.childVisibleActionCount) || (action.pendingAction === CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE && (isOffline ?? isNetworkOffline))), @@ -936,7 +939,7 @@ function getOneTransactionThreadReportID( // If there's only one IOU request action associated with the report but it's been deleted, then we don't consider this a oneTransaction report // and want to display it using the standard view - if ((getReportActionOriginalMessage(iouRequestActions[0])?.deleted ?? '') !== '') { + if ((getOriginalMessage(iouRequestActions[0])?.deleted ?? '') !== '') { return null; } @@ -1332,6 +1335,8 @@ export { getReportActionHtml, getReportActionMessage, getReportActionOriginalMessage, + isActionOfType, + getMessage, isActionableTrackExpense, isLinkedTransactionHeld, isResolvedActionTrackExpense, diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 18f4142265ad..23c1c5a4161b 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -1537,7 +1537,7 @@ function canDeleteReportAction(reportAction: OnyxEntry, reportID: if (reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.IOU) { // For now, users cannot delete split actions - const isSplitAction = ReportActionsUtils.getReportActionOriginalMessage(reportAction)?.type === CONST.IOU.REPORT_ACTION_TYPE.SPLIT; + const isSplitAction = ReportActionsUtils.getOriginalMessage(reportAction)?.type === CONST.IOU.REPORT_ACTION_TYPE.SPLIT; if (isSplitAction) { return false; @@ -2611,7 +2611,7 @@ function canEditMoneyRequest(reportAction: OnyxEntry): boolean { } const allowedReportActionType: Array> = [CONST.IOU.REPORT_ACTION_TYPE.TRACK, CONST.IOU.REPORT_ACTION_TYPE.CREATE]; - const originalMessage = ReportActionsUtils.getReportActionOriginalMessage(reportAction); + const originalMessage = ReportActionsUtils.getOriginalMessage(reportAction); if (!allowedReportActionType.includes(originalMessage.type)) { return false; @@ -2670,7 +2670,7 @@ function canEditFieldOfMoneyRequest(reportAction: OnyxEntry, field return true; } - const iouMessage = ReportActionsUtils.getReportActionOriginalMessage(reportAction); + const iouMessage = ReportActionsUtils.getOriginalMessage(reportAction); const moneyRequestReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${iouMessage?.IOUReportID}`] ?? ({} as Report); const transaction = allTransactions?.[`${ONYXKEYS.COLLECTION.TRANSACTION}${iouMessage?.IOUTransactionID}`] ?? ({} as Transaction); @@ -2766,7 +2766,7 @@ function getLinkedTransaction(reportAction: OnyxEntry(reportAction)?.IOUTransactionID ?? ''; + transactionID = ReportActionsUtils.getOriginalMessage(reportAction)?.IOUTransactionID ?? ''; } return allTransactions?.[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`] ?? {}; @@ -5122,7 +5122,7 @@ function doesTransactionThreadHaveViolations(report: OnyxEntry, transact if (parentReportAction?.actionName !== CONST.REPORT.ACTIONS.TYPE.IOU) { return false; } - const {IOUTransactionID, IOUReportID} = ReportActionsUtils.getReportActionOriginalMessage(parentReportAction) ?? {}; + const {IOUTransactionID, IOUReportID} = ReportActionsUtils.getOriginalMessage(parentReportAction) ?? {}; if (!IOUTransactionID || !IOUReportID) { return false; } @@ -5143,7 +5143,7 @@ function shouldDisplayTransactionThreadViolations( transactionViolations: OnyxCollection, parentReportAction: OnyxEntry, ): boolean { - const {IOUReportID} = ReportActionsUtils.getReportActionOriginalMessage(parentReportAction) ?? {}; + const {IOUReportID} = ReportActionsUtils.getOriginalMessage(parentReportAction) ?? {}; if (isSettled(IOUReportID)) { return false; } @@ -6101,7 +6101,7 @@ function getIOUReportActionDisplayMessage(reportAction: OnyxEntry, if (reportAction?.actionName !== CONST.REPORT.ACTIONS.TYPE.IOU) { return ''; } - const originalMessage = ReportActionsUtils.getReportActionOriginalMessage(reportAction); + const originalMessage = ReportActionsUtils.getOriginalMessage(reportAction); const {IOUReportID} = originalMessage; const iouReport = getReport(IOUReportID); let translationKey: TranslationPaths; @@ -6259,7 +6259,7 @@ function hasSmartscanError(reportActions: ReportAction[]) { } const IOUReportID = ReportActionsUtils.getIOUReportIDFromReportActionPreview(action); const isReportPreviewError = ReportActionsUtils.isReportPreviewAction(action) && hasMissingSmartscanFields(IOUReportID) && !isSettled(IOUReportID); - const transactionID = ReportActionsUtils.getReportActionOriginalMessage(action).IOUTransactionID ?? '0'; + const transactionID = ReportActionsUtils.getOriginalMessage(action).IOUTransactionID ?? '0'; const transaction = allTransactions?.[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`] ?? {}; const isSplitBillError = ReportActionsUtils.isSplitBillAction(action) && TransactionUtils.hasMissingSmartscanFields(transaction as Transaction); @@ -6702,7 +6702,7 @@ function createDraftTransactionAndNavigateToParticipantSelector(transactionID: s } const linkedTrackedExpenseReportAction = Object.values(reportActions).find( - (action) => ReportActionsUtils.getReportActionOriginalMessage(action)?.IOUTransactionID === transactionID, + (action) => ReportActionsUtils.getOriginalMessage(action)?.IOUTransactionID === transactionID, ); const {created, amount, currency, merchant, mccGroup} = getTransactionDetails(transaction) ?? {}; diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index ea1b53c18eb8..de0891dd3ab1 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -3418,7 +3418,7 @@ function requestMoney( currentCreated, merchant, receipt, - isMovingTransactionFromTrackExpense ? ReportActionsUtils.getReportActionOriginalMessage(linkedTrackedExpenseReportAction)?.IOUTransactionID : undefined, + isMovingTransactionFromTrackExpense ? ReportActionsUtils.getOriginalMessage(linkedTrackedExpenseReportAction)?.IOUTransactionID : undefined, category, tag, taxCode, @@ -3620,7 +3620,7 @@ function trackExpense( payeeAccountID, moneyRequestReportID, linkedTrackedExpenseReportAction, - isMovingTransactionFromTrackExpense ? ReportActionsUtils.getReportActionOriginalMessage(linkedTrackedExpenseReportAction)?.IOUTransactionID : undefined, + isMovingTransactionFromTrackExpense ? ReportActionsUtils.getOriginalMessage(linkedTrackedExpenseReportAction)?.IOUTransactionID : undefined, ); const activeReportID = isMoneyRequestReport ? report.reportID : chatReport.reportID; @@ -5200,7 +5200,7 @@ function updateMoneyRequestAmountAndCurrency({ function deleteMoneyRequest(transactionID: string, reportAction: OnyxTypes.ReportAction, isSingleTransactionView = false) { // STEP 1: Get all collections we're updating - const iouReportID = reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.IOU ? ReportActionsUtils.getReportActionOriginalMessage(reportAction).IOUReportID : ''; + const iouReportID = reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.IOU ? ReportActionsUtils.getOriginalMessage(reportAction).IOUReportID : ''; const iouReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${iouReportID}`] ?? null; const chatReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${iouReport?.chatReportID}`]; const reportPreviewAction = getReportPreviewAction(iouReport?.chatReportID ?? '', iouReport?.reportID ?? ''); diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index 9975293c1fb2..5bf58ce94b84 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -2110,7 +2110,7 @@ function deleteReport(reportID: string) { const transactionIDs = Object.values(reportActionsForReport ?? {}) .filter((reportAction): reportAction is ReportActionBase & OriginalMessageIOU => reportAction.actionName === CONST.REPORT.ACTIONS.TYPE.IOU) - .map((reportAction) => ReportActionsUtils.getReportActionOriginalMessage(reportAction).IOUTransactionID); + .map((reportAction) => ReportActionsUtils.getOriginalMessage(reportAction).IOUTransactionID); [...new Set(transactionIDs)].forEach((transactionID) => { onyxData[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`] = null; diff --git a/src/pages/home/report/ReportActionItemMessage.tsx b/src/pages/home/report/ReportActionItemMessage.tsx index 87ec460a56b6..252066a68cc3 100644 --- a/src/pages/home/report/ReportActionItemMessage.tsx +++ b/src/pages/home/report/ReportActionItemMessage.tsx @@ -63,7 +63,7 @@ function ReportActionItemMessage({action, transaction, displayAsGroup, reportID, let iouMessage: string | undefined; if (isIOUReport) { - const originalMessage = action.actionName === CONST.REPORT.ACTIONS.TYPE.IOU ? ReportActionsUtils.getReportActionOriginalMessage(action) : null; + const originalMessage = action.actionName === CONST.REPORT.ACTIONS.TYPE.IOU ? ReportActionsUtils.getOriginalMessage(action) : null; const iouReportID = originalMessage?.IOUReportID; if (iouReportID) { iouMessage = ReportUtils.getIOUReportActionDisplayMessage(action, transaction); diff --git a/src/pages/home/report/ReportActionsView.tsx b/src/pages/home/report/ReportActionsView.tsx index 8c42d30af7ee..d1fa94e3e640 100755 --- a/src/pages/home/report/ReportActionsView.tsx +++ b/src/pages/home/report/ReportActionsView.tsx @@ -482,7 +482,7 @@ function ReportActionsView({ const reportPreviewAction = ReportActionsUtils.getReportPreviewAction(report.chatReportID ?? '', report.reportID); const moneyRequestActions = reportActions.filter((action) => { - const originalMessage = ReportActionsUtils.getReportActionOriginalMessage(action); + const originalMessage = ReportActionsUtils.getOriginalMessage(action); return ( action.actionName === CONST.REPORT.ACTIONS.TYPE.IOU && originalMessage && diff --git a/src/pages/iou/SplitBillDetailsPage.tsx b/src/pages/iou/SplitBillDetailsPage.tsx index 1de10f3ae920..396ae51a2ee4 100644 --- a/src/pages/iou/SplitBillDetailsPage.tsx +++ b/src/pages/iou/SplitBillDetailsPage.tsx @@ -61,7 +61,7 @@ function SplitBillDetailsPage({personalDetails, report, route, reportActions, tr const {translate} = useLocalize(); const reportAction = useMemo(() => reportActions?.[route.params.reportActionID] ?? ({} as ReportAction), [reportActions, route.params.reportActionID]); const participantAccountIDs = - reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.IOU ? ReportActionsUtils.getReportActionOriginalMessage(reportAction).participantAccountIDs ?? [] : []; + reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.IOU ? ReportActionsUtils.getOriginalMessage(reportAction).participantAccountIDs ?? [] : []; // In case this is workspace split expense, we manually add the workspace as the second participant of the split expense // because we don't save any accountID in the report action's originalMessage other than the payee's accountID diff --git a/src/types/onyx/OriginalMessage.ts b/src/types/onyx/OriginalMessage.ts index 6a8e4b482822..7eaf1d448b8d 100644 --- a/src/types/onyx/OriginalMessage.ts +++ b/src/types/onyx/OriginalMessage.ts @@ -1,61 +1,20 @@ -import type {ValueOf} from 'type-fest'; -import type CONST from '@src/CONST'; +import type {TupleToUnion, ValueOf} from 'type-fest'; +import CONST from '@src/CONST'; +import type AssertTypesEqual from '@src/types/utils/AssertTypesEqual'; import type DeepValueOf from '@src/types/utils/DeepValueOf'; +import type ReportActionName from './ReportActionName'; type PaymentMethodType = DeepValueOf; -type ActionName = DeepValueOf; -type OriginalMessageActionName = - | 'ADDCOMMENT' - | 'APPROVED' - | 'CHRONOSOOOLIST' - | 'CLOSED' - | 'CREATED' - | 'HOLD' - | 'UNHOLD' - | 'IOU' - | 'MODIFIEDEXPENSE' - | 'REIMBURSEMENTQUEUED' - | 'RENAMED' - | 'REPORTPREVIEW' - | 'SUBMITTED' - | 'TASKCANCELLED' - | 'TASKCOMPLETED' - | 'TASKEDITED' - | 'TASKREOPENED' - | 'ACTIONABLEJOINREQUEST' - | 'ACTIONABLEMENTIONWHISPER' - | 'ACTIONABLEREPORTMENTIONWHISPER' - | 'ACTIONABLETRACKEXPENSEWHISPER' - | ValueOf; -type OriginalMessageApproved = { - actionName: typeof CONST.REPORT.ACTIONS.TYPE.APPROVED; - originalMessage: unknown; -}; type OriginalMessageSource = 'Chronos' | 'email' | 'ios' | 'android' | 'web' | ''; -type OriginalMessageHold = { - actionName: typeof CONST.REPORT.ACTIONS.TYPE.HOLD; - originalMessage: unknown; -}; - -type OriginalMessageHoldComment = { - actionName: typeof CONST.REPORT.ACTIONS.TYPE.HOLD_COMMENT; - originalMessage: unknown; -}; - -type OriginalMessageUnHold = { - actionName: typeof CONST.REPORT.ACTIONS.TYPE.UNHOLD; - originalMessage: unknown; -}; - type IOUDetails = { amount: number; comment?: string; currency: string; }; -type IOUMessage = { +type OriginalMessageIOU = { /** The ID of the iou transaction */ IOUTransactionID?: string; IOUReportID?: string; @@ -74,18 +33,6 @@ type IOUMessage = { whisperedTo?: number[]; }; -type ReimbursementDeQueuedMessage = { - cancellationReason: string; - expenseReportID?: string; - amount: number; - currency: string; -}; - -type OriginalMessageIOU = { - actionName: typeof CONST.REPORT.ACTIONS.TYPE.IOU; - originalMessage: IOUMessage; -}; - type FlagSeverityName = ValueOf< Pick< typeof CONST.MODERATION, @@ -118,84 +65,53 @@ type Reaction = { users: User[]; }; -type Closed = { - policyName: string; - reason: ValueOf; - lastModified?: string; - newAccountID?: number; - oldAccountID?: number; -}; - type OriginalMessageAddComment = { - actionName: typeof CONST.REPORT.ACTIONS.TYPE.ADD_COMMENT; - originalMessage: { - html: string; - source?: OriginalMessageSource; - lastModified?: string; - taskReportID?: string; - edits?: string[]; - childReportID?: string; - isDeletedParentAction?: boolean; - flags?: Record; - moderationDecisions?: Decision[]; - whisperedTo: number[]; - reactions?: Reaction[]; - }; + html: string; + text: string; + source?: OriginalMessageSource; + lastModified?: string; + taskReportID?: string; + edits?: string[]; + childReportID?: string; + isDeletedParentAction?: boolean; + flags?: Record; + moderationDecisions?: Decision[]; + whisperedTo: number[]; + reactions?: Reaction[]; }; type OriginalMessageActionableMentionWhisper = { - actionName: typeof CONST.REPORT.ACTIONS.TYPE.ACTIONABLE_MENTION_WHISPER; - originalMessage: { - inviteeAccountIDs: number[]; - inviteeEmails: string; - lastModified: string; - reportID: number; - resolution?: ValueOf | null; - whisperedTo?: number[]; - }; + inviteeAccountIDs: number[]; + inviteeEmails: string; + lastModified: string; + reportID: number; + resolution?: ValueOf | null; + whisperedTo?: number[]; }; type OriginalMessageActionableReportMentionWhisper = { - actionName: typeof CONST.REPORT.ACTIONS.TYPE.ACTIONABLE_REPORT_MENTION_WHISPER; - originalMessage: { - reportNames: string[]; - mentionedAccountIDs: number[]; - reportActionID: number; - reportID: number; - lastModified: string; - resolution?: ValueOf | null; - whisperedTo?: number[]; - }; -}; - -type OriginalMessageSubmitted = { - actionName: typeof CONST.REPORT.ACTIONS.TYPE.SUBMITTED; - originalMessage: unknown; + reportNames: string[]; + mentionedAccountIDs: number[]; + reportActionID: number; + reportID: number; + lastModified: string; + resolution?: ValueOf | null; + whisperedTo?: number[]; }; type OriginalMessageClosed = { - actionName: typeof CONST.REPORT.ACTIONS.TYPE.CLOSED; - originalMessage: Closed; -}; - -type OriginalMessageCreated = { - actionName: typeof CONST.REPORT.ACTIONS.TYPE.CREATED; - originalMessage?: unknown; -}; - -type OriginalMessageMarkedReimbursed = { - actionName: typeof CONST.REPORT.ACTIONS.TYPE.MARKED_REIMBURSED; - originalMessage?: unknown; + policyName: string; + reason: ValueOf; + lastModified?: string; + newAccountID?: number; + oldAccountID?: number; }; type OriginalMessageRenamed = { - actionName: typeof CONST.REPORT.ACTIONS.TYPE.RENAMED; - originalMessage: { - html: string; - lastModified: string; - oldName: string; - newName: string; - }; + html: string; + lastModified: string; + oldName: string; + newName: string; }; type ChronosOOOTimestamp = { @@ -205,12 +121,6 @@ type ChronosOOOTimestamp = { timezone_type: number; }; -type ChangeLog = { - targetAccountIDs?: number[]; - roomName?: string; - reportID?: number; -}; - type ChronosOOOEvent = { id: string; lengthInDays: number; @@ -220,183 +130,169 @@ type ChronosOOOEvent = { }; type OriginalMessageChronosOOOList = { - actionName: typeof CONST.REPORT.ACTIONS.TYPE.CHRONOS_OOO_LIST; - originalMessage: { - edits: string[]; - events: ChronosOOOEvent[]; - html: string; - lastModified: string; - }; + edits: string[]; + events: ChronosOOOEvent[]; + html: string; + lastModified: string; }; type OriginalMessageReportPreview = { - actionName: typeof CONST.REPORT.ACTIONS.TYPE.REPORT_PREVIEW; - originalMessage: { - linkedReportID: string; - lastModified?: string; - whisperedTo?: number[]; - }; + linkedReportID: string; + lastModified?: string; + whisperedTo?: number[]; }; -type OriginalMessagePolicyChangeLog = { - actionName: ValueOf; - originalMessage: ChangeLog; +type OriginalMessageChangeLog = { + targetAccountIDs?: number[]; + roomName?: string; + reportID?: number; }; type OriginalMessageJoinPolicyChangeLog = { - actionName: typeof CONST.REPORT.ACTIONS.TYPE.ACTIONABLE_JOIN_REQUEST; - originalMessage: { - choice: string; - email: string; - inviterEmail: string; - lastModified: string; - policyID: string; - }; -}; - -type OriginalMessageRoomChangeLog = { - actionName: ValueOf; - originalMessage: ChangeLog; -}; - -type OriginalMessagePolicyTask = { - actionName: - | typeof CONST.REPORT.ACTIONS.TYPE.TASK_EDITED - | typeof CONST.REPORT.ACTIONS.TYPE.TASK_CANCELLED - | typeof CONST.REPORT.ACTIONS.TYPE.TASK_COMPLETED - | typeof CONST.REPORT.ACTIONS.TYPE.TASK_REOPENED - | typeof CONST.REPORT.ACTIONS.TYPE.MODIFIED_EXPENSE; - originalMessage: unknown; + choice: string; + email: string; + inviterEmail: string; + lastModified: string; + policyID: string; }; type OriginalMessageModifiedExpense = { - actionName: typeof CONST.REPORT.ACTIONS.TYPE.MODIFIED_EXPENSE; - originalMessage: { - oldMerchant?: string; - merchant?: string; - oldCurrency?: string; - currency?: string; - oldAmount?: number; - amount?: number; - oldComment?: string; - newComment?: string; - oldCreated?: string; - created?: string; - oldCategory?: string; - category?: string; - oldTag?: string; - tag?: string; - oldTaxAmount?: number; - taxAmount?: number; - oldTaxRate?: string; - taxRate?: string; - oldBillable?: string; - billable?: string; - whisperedTo?: number[]; - }; + oldMerchant?: string; + merchant?: string; + oldCurrency?: string; + currency?: string; + oldAmount?: number; + amount?: number; + oldComment?: string; + newComment?: string; + oldCreated?: string; + created?: string; + oldCategory?: string; + category?: string; + oldTag?: string; + tag?: string; + oldTaxAmount?: number; + taxAmount?: number; + oldTaxRate?: string; + taxRate?: string; + oldBillable?: string; + billable?: string; + whisperedTo?: number[]; }; type OriginalMessageReimbursementQueued = { - actionName: typeof CONST.REPORT.ACTIONS.TYPE.REIMBURSEMENT_QUEUED; - originalMessage: { - paymentType: DeepValueOf; - }; + paymentType: DeepValueOf; }; type OriginalMessageActionableTrackedExpenseWhisper = { - actionName: typeof CONST.REPORT.ACTIONS.TYPE.ACTIONABLE_TRACK_EXPENSE_WHISPER; - originalMessage: { - transactionID: string; - lastModified: string; - resolution?: ValueOf; - }; + transactionID: string; + lastModified: string; + resolution?: ValueOf; }; type OriginalMessageReimbursementDequeued = { - actionName: typeof CONST.REPORT.ACTIONS.TYPE.REIMBURSEMENT_DEQUEUED; - originalMessage: { - expenseReportID: string; - }; + cancellationReason: string; + expenseReportID?: string; + amount: number; + currency: string; }; type OriginalMessageMoved = { - actionName: typeof CONST.REPORT.ACTIONS.TYPE.MOVED; - originalMessage: { - fromPolicyID: string; - toPolicyID: string; - newParentReportID: string; - movedReportID: string; - }; -}; - -type OriginalMessageMergedWithCashTransaction = { - actionName: typeof CONST.REPORT.ACTIONS.TYPE.MERGED_WITH_CASH_TRANSACTION; - originalMessage: Record; // No data is sent with this action + fromPolicyID: string; + toPolicyID: string; + newParentReportID: string; + movedReportID: string; }; type OriginalMessageDismissedViolation = { - actionName: typeof CONST.REPORT.ACTIONS.TYPE.DISMISSED_VIOLATION; - originalMessage: { - reason: string; - violationName: string; - }; -}; + reason: string; + violationName: string; +}; + +type OriginalMessageMap = { + [CONST.REPORT.ACTIONS.TYPE.ACTIONABLE_JOIN_REQUEST]: OriginalMessageJoinPolicyChangeLog; + [CONST.REPORT.ACTIONS.TYPE.ACTIONABLE_MENTION_WHISPER]: OriginalMessageActionableMentionWhisper; + [CONST.REPORT.ACTIONS.TYPE.ACTIONABLE_REPORT_MENTION_WHISPER]: OriginalMessageActionableReportMentionWhisper; + [CONST.REPORT.ACTIONS.TYPE.ACTIONABLE_TRACK_EXPENSE_WHISPER]: OriginalMessageActionableTrackedExpenseWhisper; + [CONST.REPORT.ACTIONS.TYPE.ADD_COMMENT]: OriginalMessageAddComment; + [CONST.REPORT.ACTIONS.TYPE.APPROVED]: never; + [CONST.REPORT.ACTIONS.TYPE.CHANGE_FIELD]: never; + [CONST.REPORT.ACTIONS.TYPE.CHANGE_POLICY]: never; + [CONST.REPORT.ACTIONS.TYPE.CHANGE_TYPE]: never; + [CONST.REPORT.ACTIONS.TYPE.CHRONOS_OOO_LIST]: OriginalMessageChronosOOOList; + [CONST.REPORT.ACTIONS.TYPE.CLOSED]: OriginalMessageClosed; + [CONST.REPORT.ACTIONS.TYPE.CREATED]: never; + [CONST.REPORT.ACTIONS.TYPE.DELEGATE_SUBMIT]: never; + [CONST.REPORT.ACTIONS.TYPE.DELETED_ACCOUNT]: never; + [CONST.REPORT.ACTIONS.TYPE.DISMISSED_VIOLATION]: OriginalMessageDismissedViolation; + [CONST.REPORT.ACTIONS.TYPE.DONATION]: never; + [CONST.REPORT.ACTIONS.TYPE.EXPORTED_TO_CSV]: never; + [CONST.REPORT.ACTIONS.TYPE.EXPORTED_TO_INTEGRATION]: never; + [CONST.REPORT.ACTIONS.TYPE.EXPORTED_TO_QUICK_BOOKS]: never; + [CONST.REPORT.ACTIONS.TYPE.FORWARDED]: never; + [CONST.REPORT.ACTIONS.TYPE.HOLD]: never; + [CONST.REPORT.ACTIONS.TYPE.HOLD_COMMENT]: never; + [CONST.REPORT.ACTIONS.TYPE.INTEGRATIONS_MESSAGE]: never; + [CONST.REPORT.ACTIONS.TYPE.IOU]: OriginalMessageIOU; + [CONST.REPORT.ACTIONS.TYPE.MANAGER_ATTACH_RECEIPT]: never; + [CONST.REPORT.ACTIONS.TYPE.MANAGER_DETACH_RECEIPT]: never; + [CONST.REPORT.ACTIONS.TYPE.MARK_REIMBURSED_FROM_INTEGRATION]: never; + [CONST.REPORT.ACTIONS.TYPE.MARKED_REIMBURSED]: never; + [CONST.REPORT.ACTIONS.TYPE.MERGED_WITH_CASH_TRANSACTION]: never; + [CONST.REPORT.ACTIONS.TYPE.MODIFIED_EXPENSE]: OriginalMessageModifiedExpense; + [CONST.REPORT.ACTIONS.TYPE.MOVED]: OriginalMessageMoved; + [CONST.REPORT.ACTIONS.TYPE.OUTDATED_BANK_ACCOUNT]: never; + [CONST.REPORT.ACTIONS.TYPE.REIMBURSEMENT_ACH_BOUNCE]: never; + [CONST.REPORT.ACTIONS.TYPE.REIMBURSEMENT_ACH_CANCELLED]: never; + [CONST.REPORT.ACTIONS.TYPE.REIMBURSEMENT_ACCOUNT_CHANGED]: never; + [CONST.REPORT.ACTIONS.TYPE.REIMBURSEMENT_DEQUEUED]: OriginalMessageReimbursementDequeued; + [CONST.REPORT.ACTIONS.TYPE.REIMBURSEMENT_DELAYED]: never; + [CONST.REPORT.ACTIONS.TYPE.REIMBURSEMENT_QUEUED]: OriginalMessageReimbursementQueued; + [CONST.REPORT.ACTIONS.TYPE.REIMBURSEMENT_REQUESTED]: never; + [CONST.REPORT.ACTIONS.TYPE.REIMBURSEMENT_SETUP]: never; + [CONST.REPORT.ACTIONS.TYPE.RENAMED]: OriginalMessageRenamed; + [CONST.REPORT.ACTIONS.TYPE.REPORT_PREVIEW]: OriginalMessageReportPreview; + [CONST.REPORT.ACTIONS.TYPE.SELECTED_FOR_RANDOM_AUDIT]: never; + [CONST.REPORT.ACTIONS.TYPE.SHARE]: never; + [CONST.REPORT.ACTIONS.TYPE.STRIPE_PAID]: never; + [CONST.REPORT.ACTIONS.TYPE.SUBMITTED]: never; + [CONST.REPORT.ACTIONS.TYPE.TASK_CANCELLED]: never; + [CONST.REPORT.ACTIONS.TYPE.TASK_COMPLETED]: never; + [CONST.REPORT.ACTIONS.TYPE.TASK_EDITED]: never; + [CONST.REPORT.ACTIONS.TYPE.TASK_REOPENED]: never; + [CONST.REPORT.ACTIONS.TYPE.TAKE_CONTROL]: never; + [CONST.REPORT.ACTIONS.TYPE.UNAPPROVED]: never; + [CONST.REPORT.ACTIONS.TYPE.UNHOLD]: never; + [CONST.REPORT.ACTIONS.TYPE.UNSHARE]: never; + [CONST.REPORT.ACTIONS.TYPE.UPDATE_GROUP_CHAT_MEMBER_ROLE]: never; +} & { + [T in ValueOf]: OriginalMessageChangeLog; +} & { + [T in ValueOf]: OriginalMessageChangeLog; +}; + +// eslint-disable-next-line @typescript-eslint/no-unused-vars +type AssertOriginalMessageDefinedForAllActions = AssertTypesEqual< + ReportActionName, + keyof OriginalMessageMap, + `Error: Types don't match, OriginalMessageMap type is missing: ${Exclude}` +>; -type OriginalMessage = - | OriginalMessageApproved - | OriginalMessageIOU - | OriginalMessageAddComment - | OriginalMessageActionableMentionWhisper - | OriginalMessageActionableReportMentionWhisper - | OriginalMessageSubmitted - | OriginalMessageClosed - | OriginalMessageCreated - | OriginalMessageHold - | OriginalMessageHoldComment - | OriginalMessageUnHold - | OriginalMessageRenamed - | OriginalMessageChronosOOOList - | OriginalMessageReportPreview - | OriginalMessageRoomChangeLog - | OriginalMessagePolicyChangeLog - | OriginalMessagePolicyTask - | OriginalMessageJoinPolicyChangeLog - | OriginalMessageModifiedExpense - | OriginalMessageReimbursementQueued - | OriginalMessageReimbursementDequeued - | OriginalMessageMoved - | OriginalMessageMarkedReimbursed - | OriginalMessageActionableTrackedExpenseWhisper - | OriginalMessageMergedWithCashTransaction - | OriginalMessageDismissedViolation; +type OriginalMessage = OriginalMessageMap[T]; + +// Note: type-fest's ConditionalKeys does not work correctly with objects containing `never`: https://github.com/sindresorhus/type-fest/issues/878 +type ReportActionNamesWithHTMLMessage = { + [TKey in keyof OriginalMessageMap]-?: OriginalMessageMap[TKey] extends {html: string} ? (OriginalMessageMap[TKey] extends never ? never : TKey) : never; +}[keyof OriginalMessageMap]; +const REPORT_ACTIONS_WITH_HTML_MESSAGE = [CONST.REPORT.ACTIONS.TYPE.ADD_COMMENT, CONST.REPORT.ACTIONS.TYPE.CHRONOS_OOO_LIST, CONST.REPORT.ACTIONS.TYPE.RENAMED] as const; + +// eslint-disable-next-line @typescript-eslint/no-unused-vars +type AssertAllActionsWithHTMLAreListed = AssertTypesEqual< + ReportActionNamesWithHTMLMessage, + TupleToUnion, + `Error: Types don't match, REPORT_ACTIONS_WITH_HTML_MESSAGE is missing: ${Exclude}` +>; export default OriginalMessage; -export type { - ChronosOOOEvent, - Decision, - Reaction, - ActionName, - IOUMessage, - ReimbursementDeQueuedMessage, - Closed, - OriginalMessageActionName, - ChangeLog, - OriginalMessageIOU, - OriginalMessageCreated, - OriginalMessageRenamed, - OriginalMessageAddComment, - OriginalMessageJoinPolicyChangeLog, - OriginalMessageActionableMentionWhisper, - OriginalMessageActionableReportMentionWhisper, - OriginalMessageReportPreview, - OriginalMessageModifiedExpense, - OriginalMessageChronosOOOList, - OriginalMessageRoomChangeLog, - OriginalMessageSource, - OriginalMessageReimbursementDequeued, - DecisionName, - PaymentMethodType, - OriginalMessageActionableTrackedExpenseWhisper, - OriginalMessageDismissedViolation, - OriginalMessageReimbursementQueued, -}; +export {REPORT_ACTIONS_WITH_HTML_MESSAGE}; +export type {ChronosOOOEvent, PaymentMethodType, OriginalMessageSource, ReportActionNamesWithHTMLMessage, Reaction, Decision}; diff --git a/src/types/onyx/ReportAction.ts b/src/types/onyx/ReportAction.ts index d7333feb8650..d7e5aff17909 100644 --- a/src/types/onyx/ReportAction.ts +++ b/src/types/onyx/ReportAction.ts @@ -1,4 +1,4 @@ -import type {ValueOf} from 'type-fest'; +import type {Spread, TupleToUnion, ValueOf} from 'type-fest'; import type {FileObject} from '@components/AttachmentModal'; import type {AvatarSource} from '@libs/UserUtils'; import type CONST from '@src/CONST'; @@ -6,15 +6,12 @@ import type ONYXKEYS from '@src/ONYXKEYS'; import type CollectionDataSet from '@src/types/utils/CollectionDataSet'; import type {EmptyObject} from '@src/types/utils/EmptyObject'; import type * as OnyxCommon from './OnyxCommon'; -import type {Decision, OriginalMessageModifiedExpense, OriginalMessageReportPreview, Reaction} from './OriginalMessage'; import type OriginalMessage from './OriginalMessage'; +import type {Decision, Reaction, ReportActionNamesWithHTMLMessage} from './OriginalMessage'; import type {NotificationPreference} from './Report'; +import type ReportActionName from './ReportActionName'; import type {Receipt} from './Transaction'; -type ReportActionMessageJSON = { - whisperedTo?: number[]; -}; - type Message = { /** The type of the action item fragment. Used to render a corresponding component */ type: string; @@ -131,6 +128,9 @@ type ReportActionBase = OnyxCommon.OnyxValueWithOfflineFeedback<{ /** The ID of the previous reportAction on the report. It is a string represenation of a 64-bit integer (or null for CREATED actions). */ previousReportActionID?: string; + /** The name (or type) of the action */ + actionName: ReportActionName; + actorAccountID?: number; /** The account of the last message's actor */ @@ -142,12 +142,6 @@ type ReportActionBase = OnyxCommon.OnyxValueWithOfflineFeedback<{ /** ISO-formatted datetime */ created: string; - /** report action message */ - message?: Array; - - /** report action message */ - previousMessage?: Array; - /** Whether we have received a response back from the server */ isLoading?: boolean; @@ -232,13 +226,22 @@ type ReportActionBase = OnyxCommon.OnyxValueWithOfflineFeedback<{ adminAccountID?: number; }>; -type ReportAction = ReportActionBase & OriginalMessage; -type ReportPreviewAction = ReportActionBase & OriginalMessageReportPreview; -type ModifiedExpenseAction = ReportActionBase & OriginalMessageModifiedExpense; +type ReportAction = ReportActionBase & { + originalMessage: OriginalMessage; + + /** report action message */ + message?: OriginalMessage | Array; + + /** report action message */ + previousMessage?: OriginalMessage | Array; +}; + +type ReportActionWithHTMLMessage = ReportAction; +type ReportActionChangeLog = ReportAction>>; type ReportActions = Record; type ReportActionsCollectionDataSet = CollectionDataSet; export default ReportAction; -export type {ReportActions, ReportActionBase, Message, LinkMetadata, OriginalMessage, ReportActionsCollectionDataSet, ReportPreviewAction, ModifiedExpenseAction, ReportActionMessageJSON}; +export type {ReportActions, Message, LinkMetadata, OriginalMessage, ReportActionsCollectionDataSet, ReportActionWithHTMLMessage, ReportActionChangeLog}; diff --git a/src/types/onyx/ReportActionName.ts b/src/types/onyx/ReportActionName.ts new file mode 100644 index 000000000000..08b67db6f84c --- /dev/null +++ b/src/types/onyx/ReportActionName.ts @@ -0,0 +1,6 @@ +import type CONST from '@src/CONST'; +import type DeepValueOf from '@src/types/utils/DeepValueOf'; + +type ReportActionName = DeepValueOf; + +export default ReportActionName; \ No newline at end of file diff --git a/tests/actions/IOUTest.ts b/tests/actions/IOUTest.ts index 163f1c96c65a..d0439a21ff5e 100644 --- a/tests/actions/IOUTest.ts +++ b/tests/actions/IOUTest.ts @@ -210,7 +210,7 @@ describe('actions/IOU', () => { expect(transaction?.pendingAction).toBe(CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD); // The transactionID on the iou action should match the one from the transactions collection - expect(ReportActionsUtils.getReportActionOriginalMessage(iouAction)?.IOUTransactionID).toBe(transactionID); + expect(ReportActionsUtils.getOriginalMessage(iouAction)?.IOUTransactionID).toBe(transactionID); expect(transaction?.merchant).toBe(merchant); @@ -373,7 +373,7 @@ describe('actions/IOU', () => { expect(transaction?.pendingAction).toBe(CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD); // The transactionID on the iou action should match the one from the transactions collection - expect(ReportActionsUtils.getReportActionOriginalMessage(iouAction)?.IOUTransactionID).toBe(transactionID); + expect(ReportActionsUtils.getOriginalMessage(iouAction)?.IOUTransactionID).toBe(transactionID); resolve(); }, @@ -524,7 +524,7 @@ describe('actions/IOU', () => { const newOriginalMessage = ReportActionsUtils.getReportActionOriginalMessage(newIOUAction); // The IOUReportID should be correct - expect(ReportActionsUtils.getReportActionOriginalMessage(iouAction).IOUReportID).toBe(iouReportID); + expect(ReportActionsUtils.getOriginalMessage(iouAction).IOUReportID).toBe(iouReportID); // The comment should be included in the IOU action expect(newOriginalMessage?.comment).toBe(comment); @@ -564,7 +564,7 @@ describe('actions/IOU', () => { expect(newTransaction?.pendingAction).toBe(CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD); // The transactionID on the iou action should match the one from the transactions collection - expect(ReportActionsUtils.getReportActionOriginalMessage(newIOUAction)?.IOUTransactionID).toBe(newTransaction?.transactionID); + expect(ReportActionsUtils.getOriginalMessage(newIOUAction)?.IOUTransactionID).toBe(newTransaction?.transactionID); resolve(); }, @@ -718,7 +718,7 @@ describe('actions/IOU', () => { expect(transaction?.pendingAction).toBe(CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD); // The transactionID on the iou action should match the one from the transactions collection - expect(ReportActionsUtils.getReportActionOriginalMessage(iouAction)?.IOUTransactionID).toBe(transactionID); + expect(ReportActionsUtils.getOriginalMessage(iouAction)?.IOUTransactionID).toBe(transactionID); resolve(); }, @@ -1196,7 +1196,7 @@ describe('actions/IOU', () => { Object.values(carlosReportActions ?? {}).find( (reportAction): reportAction is ReportActionBase & OriginalMessageIOU => reportAction.actionName === CONST.REPORT.ACTIONS.TYPE.IOU, ) ?? null; - const carlosOriginalMessage = ReportActionsUtils.getReportActionOriginalMessage(carlosIOUAction); + const carlosOriginalMessage = ReportActionsUtils.getOriginalMessage(carlosIOUAction); expect(carlosIOUAction?.pendingAction).toBe(CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD); expect(carlosOriginalMessage.IOUReportID).toBe(carlosIOUReport?.reportID); @@ -1217,7 +1217,7 @@ describe('actions/IOU', () => { (reportAction): reportAction is ReportActionBase & OriginalMessageIOU => reportAction.reportActionID !== julesCreatedAction.reportActionID && reportAction.reportActionID !== julesExistingIOUAction.reportActionID, ) ?? null; - const julesOriginalMessage = ReportActionsUtils.getReportActionOriginalMessage(julesIOUAction); + const julesOriginalMessage = ReportActionsUtils.getOriginalMessage(julesIOUAction); expect(julesIOUAction?.pendingAction).toBe(CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD); expect(julesOriginalMessage.IOUReportID).toBe(julesIOUReport?.reportID); @@ -1236,7 +1236,7 @@ describe('actions/IOU', () => { Object.values(vitReportActions ?? {}).find( (reportAction): reportAction is ReportActionBase & OriginalMessageIOU => reportAction.actionName === CONST.REPORT.ACTIONS.TYPE.IOU, ) ?? null; - const vitOriginalMessage = ReportActionsUtils.getReportActionOriginalMessage(vitIOUAction); + const vitOriginalMessage = ReportActionsUtils.getOriginalMessage(vitIOUAction); expect(vitCreatedAction?.pendingAction).toBe(CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD); expect(vitIOUAction?.pendingAction).toBe(CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD); @@ -1254,7 +1254,7 @@ describe('actions/IOU', () => { Object.values(groupReportActions ?? {}).find( (reportAction): reportAction is ReportActionBase & OriginalMessageIOU => reportAction.actionName === CONST.REPORT.ACTIONS.TYPE.IOU, ) ?? null; - const groupOriginalMessage = ReportActionsUtils.getReportActionOriginalMessage(groupIOUAction); + const groupOriginalMessage = ReportActionsUtils.getOriginalMessage(groupIOUAction); expect(groupCreatedAction?.pendingAction).toBe(CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD); expect(groupIOUAction?.pendingAction).toBe(CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD); @@ -1286,15 +1286,15 @@ describe('actions/IOU', () => { carlosTransaction = Object.values(allTransactions ?? {}).find( - (transaction) => transaction?.transactionID === ReportActionsUtils.getReportActionOriginalMessage(carlosIOUAction)?.IOUTransactionID, + (transaction) => transaction?.transactionID === ReportActionsUtils.getOriginalMessage(carlosIOUAction)?.IOUTransactionID, ) ?? null; julesTransaction = Object.values(allTransactions ?? {}).find( - (transaction) => transaction?.transactionID === ReportActionsUtils.getReportActionOriginalMessage(julesIOUAction)?.IOUTransactionID, + (transaction) => transaction?.transactionID === ReportActionsUtils.getOriginalMessage(julesIOUAction)?.IOUTransactionID, ) ?? null; vitTransaction = Object.values(allTransactions ?? {}).find( - (transaction) => transaction?.transactionID === ReportActionsUtils.getReportActionOriginalMessage(vitIOUAction)?.IOUTransactionID, + (transaction) => transaction?.transactionID === ReportActionsUtils.getOriginalMessage(vitIOUAction)?.IOUTransactionID, ) ?? null; groupTransaction = Object.values(allTransactions ?? {}).find((transaction) => transaction?.reportID === CONST.REPORT.SPLIT_REPORTID) ?? null; @@ -1466,7 +1466,7 @@ describe('actions/IOU', () => { createIOUAction = Object.values(reportActionsForIOUReport ?? {}).find((reportAction) => reportAction.actionName === CONST.REPORT.ACTIONS.TYPE.IOU) ?? null; expect(createIOUAction).toBeTruthy(); - expect(ReportActionsUtils.getReportActionOriginalMessage(createIOUAction)?.IOUReportID).toBe(iouReport?.reportID); + expect(ReportActionsUtils.getOriginalMessage(createIOUAction)?.IOUReportID).toBe(iouReport?.reportID); resolve(); }, @@ -1486,7 +1486,7 @@ describe('actions/IOU', () => { expect(transaction).toBeTruthy(); expect(transaction?.amount).toBe(amount); expect(transaction?.reportID).toBe(iouReport?.reportID); - expect(ReportActionsUtils.getReportActionOriginalMessage(createIOUAction)?.IOUTransactionID).toBe(transaction?.transactionID); + expect(ReportActionsUtils.getOriginalMessage(createIOUAction)?.IOUTransactionID).toBe(transaction?.transactionID); resolve(); }, }); @@ -1539,7 +1539,7 @@ describe('actions/IOU', () => { Object.values(reportActionsForIOUReport ?? {}).find( (reportAction) => reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.IOU && - ReportActionsUtils.getReportActionOriginalMessage(reportAction)?.type === CONST.IOU.REPORT_ACTION_TYPE.PAY, + ReportActionsUtils.getOriginalMessage(reportAction)?.type === CONST.IOU.REPORT_ACTION_TYPE.PAY, ) ?? null; expect(payIOUAction).toBeTruthy(); expect(payIOUAction?.pendingAction).toBe(CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD); @@ -1590,7 +1590,7 @@ describe('actions/IOU', () => { Object.values(reportActionsForIOUReport ?? {}).find( (reportAction) => reportAction.actionName === CONST.REPORT.ACTIONS.TYPE.IOU && - ReportActionsUtils.getReportActionOriginalMessage(reportAction).type === CONST.IOU.REPORT_ACTION_TYPE.PAY, + ReportActionsUtils.getOriginalMessage(reportAction).type === CONST.IOU.REPORT_ACTION_TYPE.PAY, ) ?? null; expect(payIOUAction).toBeTruthy(); @@ -2207,7 +2207,7 @@ describe('actions/IOU', () => { (reportAction): reportAction is ReportActionBase & OriginalMessageIOU => reportAction.actionName === CONST.REPORT.ACTIONS.TYPE.IOU, ) ?? null; expect(createIOUAction).toBeTruthy(); - expect(ReportActionsUtils.getReportActionOriginalMessage(createIOUAction).IOUReportID).toBe(iouReport?.reportID); + expect(ReportActionsUtils.getOriginalMessage(createIOUAction).IOUReportID).toBe(iouReport?.reportID); // When fetching all transactions from Onyx const allTransactions = await new Promise>((resolve) => { @@ -2226,7 +2226,7 @@ describe('actions/IOU', () => { expect(transaction).toBeTruthy(); expect(transaction?.amount).toBe(amount); expect(transaction?.reportID).toBe(iouReport?.reportID); - expect(ReportActionsUtils.getReportActionOriginalMessage(createIOUAction).IOUTransactionID).toBe(transaction?.transactionID); + expect(ReportActionsUtils.getOriginalMessage(createIOUAction).IOUTransactionID).toBe(transaction?.transactionID); }); afterEach(PusherHelper.teardown); From 4ef5d61015c252d830074c01cbf86e0db7c09b06 Mon Sep 17 00:00:00 2001 From: nkdengineer Date: Tue, 4 Jun 2024 09:42:49 +0700 Subject: [PATCH 17/45] resolve with getOriginalMessage function --- src/components/ArchivedReportFooter.tsx | 3 +- .../ChronosOOOListActions.tsx | 8 +- .../ReportActionItem/RenameAction.tsx | 4 +- src/libs/ModifiedExpenseMessage.ts | 6 +- src/libs/OptionsListUtils.ts | 2 +- src/libs/ReportActionsUtils.ts | 135 +++++++++++++----- src/libs/ReportUtils.ts | 38 ++--- src/libs/SidebarUtils.ts | 14 +- src/libs/actions/IOU.ts | 4 +- src/libs/actions/Policy/Policy.ts | 8 +- src/libs/actions/User.ts | 2 +- .../report/ContextMenu/ContextMenuActions.tsx | 3 +- .../PopoverReportActionContextMenu.tsx | 3 +- src/pages/home/report/ReportActionItem.tsx | 86 ++++------- .../home/report/ReportActionItemMessage.tsx | 6 +- src/pages/iou/SplitBillDetailsPage.tsx | 7 +- src/types/onyx/OriginalMessage.ts | 1 + src/types/onyx/ReportAction.ts | 4 +- tests/actions/IOUTest.ts | 25 ++-- 19 files changed, 191 insertions(+), 168 deletions(-) diff --git a/src/components/ArchivedReportFooter.tsx b/src/components/ArchivedReportFooter.tsx index aee7f6140626..6dfb5cb8c742 100644 --- a/src/components/ArchivedReportFooter.tsx +++ b/src/components/ArchivedReportFooter.tsx @@ -11,7 +11,6 @@ import * as ReportUtils from '@libs/ReportUtils'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import type {PersonalDetailsList, Report, ReportAction} from '@src/types/onyx'; -import type {Closed} from '@src/types/onyx/OriginalMessage'; import Banner from './Banner'; type ArchivedReportFooterOnyxProps = { @@ -31,7 +30,7 @@ function ArchivedReportFooter({report, reportClosedAction, personalDetails = {}} const styles = useThemeStyles(); const {translate} = useLocalize(); - const originalMessage = reportClosedAction?.actionName === CONST.REPORT.ACTIONS.TYPE.CLOSED ? ReportActionsUtils.getReportActionOriginalMessage(reportClosedAction) : null; + const originalMessage = ReportActionsUtils.isClosedAction(reportClosedAction) ? ReportActionsUtils.getOriginalMessage(reportClosedAction) : null; const archiveReason = originalMessage?.reason ?? CONST.REPORT.ARCHIVE_REASON.DEFAULT; const actorPersonalDetails = personalDetails?.[reportClosedAction?.actorAccountID ?? 0]; let displayName = PersonalDetailsUtils.getDisplayNameOrDefault(actorPersonalDetails); diff --git a/src/components/ReportActionItem/ChronosOOOListActions.tsx b/src/components/ReportActionItem/ChronosOOOListActions.tsx index 38b220b4551c..26ddaf360b9d 100644 --- a/src/components/ReportActionItem/ChronosOOOListActions.tsx +++ b/src/components/ReportActionItem/ChronosOOOListActions.tsx @@ -8,15 +8,15 @@ import useThemeStyles from '@hooks/useThemeStyles'; import DateUtils from '@libs/DateUtils'; import * as ReportActionsUtils from '@libs/ReportActionsUtils'; import * as Chronos from '@userActions/Chronos'; -import type {OriginalMessageChronosOOOList} from '@src/types/onyx/OriginalMessage'; -import type {ReportActionBase} from '@src/types/onyx/ReportAction'; +import ReportAction from '@src/types/onyx/ReportAction'; +import CONST from '@src/CONST'; type ChronosOOOListActionsProps = { /** The ID of the report */ reportID: string; /** All the data of the action */ - action: ReportActionBase & OriginalMessageChronosOOOList; + action: ReportAction; }; function ChronosOOOListActions({reportID, action}: ChronosOOOListActionsProps) { @@ -24,7 +24,7 @@ function ChronosOOOListActions({reportID, action}: ChronosOOOListActionsProps) { const {translate, preferredLocale} = useLocalize(); - const events = ReportActionsUtils.getReportActionOriginalMessage(action)?.events ?? []; + const events = ReportActionsUtils.getOriginalMessage(action)?.events ?? []; if (!events.length) { return ( diff --git a/src/components/ReportActionItem/RenameAction.tsx b/src/components/ReportActionItem/RenameAction.tsx index 33f8ed2ee537..37ee2f46c368 100644 --- a/src/components/ReportActionItem/RenameAction.tsx +++ b/src/components/ReportActionItem/RenameAction.tsx @@ -5,9 +5,7 @@ import type {WithCurrentUserPersonalDetailsProps} from '@components/withCurrentU import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import * as ReportActionsUtils from '@libs/ReportActionsUtils'; -import CONST from '@src/CONST'; import type {ReportAction} from '@src/types/onyx'; -import type {OriginalMessageRenamed} from '@src/types/onyx/OriginalMessage'; type RenameActionProps = WithCurrentUserPersonalDetailsProps & { /** All the data of the action */ @@ -23,7 +21,7 @@ function RenameAction({currentUserPersonalDetails, action}: RenameActionProps) { const actorAccountID = action.actorAccountID ?? ''; const displayName = actorAccountID === currentUserAccountID ? `${translate('common.you')}` : `${userDisplayName}`; const originalMessage = - action.actionName === CONST.REPORT.ACTIONS.TYPE.RENAMED ? ReportActionsUtils.getReportActionOriginalMessage(action) : null; + ReportActionsUtils.isRenamedAction(action) ? ReportActionsUtils.getOriginalMessage(action) : null; const oldName = originalMessage?.oldName ?? ''; const newName = originalMessage?.newName ?? ''; diff --git a/src/libs/ModifiedExpenseMessage.ts b/src/libs/ModifiedExpenseMessage.ts index f864ffd97e51..6e8e4c138995 100644 --- a/src/libs/ModifiedExpenseMessage.ts +++ b/src/libs/ModifiedExpenseMessage.ts @@ -106,11 +106,11 @@ function getForDistanceRequest(newDistance: string, oldDistance: string, newAmou * ModifiedExpense::getNewDotComment in Web-Expensify should match this. * If we change this function be sure to update the backend as well. */ -function getForReportAction(reportID: string | undefined, reportAction: OnyxEntry | ReportAction | Record): string { - if (reportAction?.actionName !== CONST.REPORT.ACTIONS.TYPE.MODIFIED_EXPENSE) { +function getForReportAction(reportID: string | undefined, reportAction: OnyxEntry): string { + if (!ReportActionsUtils.isModifiedExpenseAction(reportAction)) { return ''; } - const reportActionOriginalMessage = ReportActionsUtils.getReportActionOriginalMessage(reportAction); + const reportActionOriginalMessage = ReportActionsUtils.getOriginalMessage(reportAction); const policyID = getReportPolicyID(reportID) ?? ''; const removalFragments: string[] = []; diff --git a/src/libs/OptionsListUtils.ts b/src/libs/OptionsListUtils.ts index e3e1ca175b1b..4c0b60785f37 100644 --- a/src/libs/OptionsListUtils.ts +++ b/src/libs/OptionsListUtils.ts @@ -605,7 +605,7 @@ function getLastMessageTextForReport(report: OnyxEntry, lastActorDetails if (ReportUtils.isArchivedRoom(report)) { const archiveReason = - (lastOriginalReportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.CLOSED && ReportActionUtils.getReportActionOriginalMessage(lastOriginalReportAction)?.reason) || + (ReportActionUtils.isClosedAction(lastOriginalReportAction) && ReportActionUtils.getOriginalMessage(lastOriginalReportAction)?.reason) || CONST.REPORT.ARCHIVE_REASON.DEFAULT; switch (archiveReason) { case CONST.REPORT.ARCHIVE_REASON.ACCOUNT_CLOSED: diff --git a/src/libs/ReportActionsUtils.ts b/src/libs/ReportActionsUtils.ts index 710801f76643..408eccfece20 100644 --- a/src/libs/ReportActionsUtils.ts +++ b/src/libs/ReportActionsUtils.ts @@ -97,6 +97,10 @@ function isCreatedAction(reportAction: OnyxEntry): boolean { function isDeletedAction(reportAction: OnyxEntry): boolean { const message = reportAction?.message ?? []; + if (!Array.isArray(message)) { + return !message; + } + // A legacy deleted comment has either an empty array or an object with html field with empty string as value const isLegacyDeletedComment = message.length === 0 || message[0]?.html === ''; @@ -104,7 +108,10 @@ function isDeletedAction(reportAction: OnyxEntry): boolean { @@ -123,19 +130,31 @@ function isPendingRemove(reportAction: OnyxEntry | EmptyObject): b } function isMoneyRequestAction(reportAction: OnyxEntry): reportAction is ReportAction { - return reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.IOU; + return isActionOfType(reportAction, CONST.REPORT.ACTIONS.TYPE.IOU); } -function isReportPreviewAction(reportAction: OnyxEntry): boolean { - return reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.REPORT_PREVIEW; +function isReportPreviewAction(reportAction: OnyxEntry): reportAction is ReportAction { + return isActionOfType(reportAction, CONST.REPORT.ACTIONS.TYPE.REPORT_PREVIEW); } function isReportActionSubmitted(reportAction: OnyxEntry): boolean { return reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.SUBMITTED; } -function isModifiedExpenseAction(reportAction: OnyxEntry | ReportAction | Record): boolean { - return reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.MODIFIED_EXPENSE; +function isModifiedExpenseAction(reportAction: OnyxEntry): reportAction is ReportAction { + return isActionOfType(reportAction, CONST.REPORT.ACTIONS.TYPE.MODIFIED_EXPENSE); +} + +function isPolicyChangelLogAction(reportAction: OnyxEntry): reportAction is ReportAction> { + return isActionOfType(reportAction, ...Object.values(CONST.REPORT.ACTIONS.TYPE.POLICY_CHANGE_LOG)); +} + +function isChronosOOOListAction(reportAction: OnyxEntry): reportAction is ReportAction { + return isActionOfType(reportAction, CONST.REPORT.ACTIONS.TYPE.CHRONOS_OOO_LIST); +} + +function isAddCommentAction(reportAction: OnyxEntry): reportAction is ReportAction { + return isActionOfType(reportAction, CONST.REPORT.ACTIONS.TYPE.ADD_COMMENT); } function getReportActionOriginalMessage(reportAction: PartialReportAction) { @@ -167,14 +186,21 @@ function getMessage(reportAction: OnyxEntry): number[] { - const originalMessage = getMessage(reportAction); + if (!reportAction) { + return []; + } + const originalMessage = getOriginalMessage(reportAction); const message = reportAction?.message; - if (!Array.isArray(message) && typeof message === 'object') { + if (! ('whisperedTo' in originalMessage) && ! (!!message && 'whisperedTo' in message)) { + return [] + } + + if (!Array.isArray(message) && typeof message === 'object' && 'whisperedTo' in message) { return (message)?.whisperedTo ?? []; } - if (originalMessage) { + if (originalMessage && 'whisperedTo' in originalMessage) { return (originalMessage)?.whisperedTo ?? []; } @@ -195,26 +221,38 @@ function isWhisperActionTargetedToOthers(reportAction: OnyxEntry): return !getWhisperedTo(reportAction).includes(currentUserAccountID ?? 0); } -function isReimbursementQueuedAction(reportAction: OnyxEntry) { - return reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.REIMBURSEMENT_QUEUED; +function isReimbursementQueuedAction(reportAction: OnyxEntry): reportAction is ReportAction { + return isActionOfType(reportAction, CONST.REPORT.ACTIONS.TYPE.REIMBURSEMENT_QUEUED); } function isMemberChangeAction(reportAction: OnyxEntry) { return isActionOfType(reportAction, CONST.REPORT.ACTIONS.TYPE.ROOM_CHANGE_LOG.INVITE_TO_ROOM, CONST.REPORT.ACTIONS.TYPE.ROOM_CHANGE_LOG.REMOVE_FROM_ROOM, CONST.REPORT.ACTIONS.TYPE.POLICY_CHANGE_LOG.INVITE_TO_ROOM, CONST.REPORT.ACTIONS.TYPE.POLICY_CHANGE_LOG.REMOVE_FROM_ROOM, CONST.REPORT.ACTIONS.TYPE.POLICY_CHANGE_LOG.LEAVE_POLICY); } -function isInviteMemberAction(reportAction: OnyxEntry) { - return reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.ROOM_CHANGE_LOG.INVITE_TO_ROOM || reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.POLICY_CHANGE_LOG.INVITE_TO_ROOM; +function isInviteMemberAction(reportAction: OnyxEntry): reportAction is ReportAction { + return isActionOfType(reportAction, CONST.REPORT.ACTIONS.TYPE.ROOM_CHANGE_LOG.INVITE_TO_ROOM, CONST.REPORT.ACTIONS.TYPE.POLICY_CHANGE_LOG.INVITE_TO_ROOM); } -function isLeavePolicyAction(reportAction: OnyxEntry) { - return reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.POLICY_CHANGE_LOG.LEAVE_POLICY; +function isLeavePolicyAction(reportAction: OnyxEntry): reportAction is ReportAction { + return isActionOfType(reportAction, CONST.REPORT.ACTIONS.TYPE.POLICY_CHANGE_LOG.LEAVE_POLICY); } function isReimbursementDeQueuedAction(reportAction: OnyxEntry): reportAction is ReportAction { return reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.REIMBURSEMENT_DEQUEUED; } +function isClosedAction(reportAction: OnyxEntry): reportAction is ReportAction { + return isActionOfType(reportAction, CONST.REPORT.ACTIONS.TYPE.CLOSED); +} + +function isRenamedAction(reportAction: OnyxEntry): reportAction is ReportAction { + return isActionOfType(reportAction, CONST.REPORT.ACTIONS.TYPE.RENAMED); +} + +function isRoomChangeLogAction(reportAction: OnyxEntry): reportAction is ReportAction> { + return isActionOfType(reportAction, ...Object.values(CONST.REPORT.ACTIONS.TYPE.ROOM_CHANGE_LOG)); +} + /** * Returns whether the comment is a thread parent message/the first message in a thread */ @@ -247,12 +285,11 @@ function isSentMoneyReportAction(reportAction: OnyxEntry | EmptyObject): boolean { - if (isEmptyObject(parentReportAction)) { + if (isEmptyObject(parentReportAction) || !isMoneyRequestAction(parentReportAction)) { return false; } const originalMessage = getOriginalMessage(parentReportAction); return ( - parentReportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.IOU && (originalMessage?.type === CONST.IOU.REPORT_ACTION_TYPE.CREATE || originalMessage?.type === CONST.IOU.REPORT_ACTION_TYPE.TRACK || (originalMessage?.type === CONST.IOU.REPORT_ACTION_TYPE.PAY && !!originalMessage?.IOUDetails)) @@ -334,7 +371,10 @@ function getCombinedReportActions(reportActions: ReportAction[], transactionThre const isSelfDM = report?.chatType === CONST.REPORT.CHAT_TYPE.SELF_DM; // Filter out request and send money request actions because we don't want to show any preview actions for one transaction reports const filteredReportActions = [...reportActions, ...filteredTransactionThreadReportActions].filter((action) => { - const actionType = getOriginalMessage(action)?.type ?? ''; + if (!isMoneyRequestAction(action)) { + return true; + } + const actionType = getOriginalMessage(action)?.type ?? ''; if (isSelfDM) { return actionType !== CONST.IOU.REPORT_ACTION_TYPE.CREATE && !isSentMoneyReportAction(action); } @@ -634,7 +674,7 @@ function shouldReportActionBeVisibleAsLastAction(reportAction: OnyxEntry, reportID?: string): string | null { const reportAction = typeof reportActionOrID === 'string' ? allReportActions?.[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`]?.[reportActionOrID] : reportActionOrID; - if (!reportAction || reportAction.actionName !== CONST.REPORT.ACTIONS.TYPE.IOU) { + if (!reportAction || !isMoneyRequestAction(reportAction)) { return null; } - return getOriginalMessage(reportAction)?.IOUTransactionID ?? null; + return getOriginalMessage(reportAction)?.IOUTransactionID ?? null; } function getReportAction(reportID: string, reportActionID: string): OnyxEntry { @@ -919,14 +959,14 @@ function getOneTransactionThreadReportID( const iouRequestActions = reportActionsArray.filter( (action) => - action.actionName === CONST.REPORT.ACTIONS.TYPE.IOU && - (iouRequestTypes.includes(getOriginalMessage(action).type) ?? []) && + isMoneyRequestAction(action) && + (iouRequestTypes.includes(getOriginalMessage(action).type) ?? []) && action.childReportID && // Include deleted IOU reportActions if: // - they have an assocaited IOU transaction ID or // - they have visibile childActions (like comments) that we'd want to display // - the action is pending deletion and the user is offline - (Boolean(getOriginalMessage(action).IOUTransactionID) || + (Boolean(getOriginalMessage(action).IOUTransactionID) || // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing (isMessageDeleted(action) && action.childVisibleActionCount) || (action.pendingAction === CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE && (isOffline ?? isNetworkOffline))), @@ -939,7 +979,7 @@ function getOneTransactionThreadReportID( // If there's only one IOU request action associated with the report but it's been deleted, then we don't consider this a oneTransaction report // and want to display it using the standard view - if ((getOriginalMessage(iouRequestActions[0])?.deleted ?? '') !== '') { + if (isMoneyRequestAction(iouRequestActions[0]) && (getOriginalMessage(iouRequestActions[0])?.deleted ?? '') !== '') { return null; } @@ -988,7 +1028,7 @@ function isNotifiableReportAction(reportAction: OnyxEntry): boolea return false; } - const actions: ActionName[] = [CONST.REPORT.ACTIONS.TYPE.ADD_COMMENT, CONST.REPORT.ACTIONS.TYPE.IOU, CONST.REPORT.ACTIONS.TYPE.MODIFIED_EXPENSE]; + const actions: ReportActionName[] = [CONST.REPORT.ACTIONS.TYPE.ADD_COMMENT, CONST.REPORT.ACTIONS.TYPE.IOU, CONST.REPORT.ACTIONS.TYPE.MODIFIED_EXPENSE]; return actions.includes(reportAction.actionName); } @@ -997,6 +1037,10 @@ function getMemberChangeMessageElements(reportAction: OnyxEntry): const isInviteAction = isInviteMemberAction(reportAction); const isLeaveAction = isLeavePolicyAction(reportAction); + if (!isInviteAction && !isLeaveAction) { + return []; + } + // Currently, we only render messages when members are invited let verb = Localize.translateLocal('workspace.invite.removed'); if (isInviteAction) { @@ -1007,7 +1051,7 @@ function getMemberChangeMessageElements(reportAction: OnyxEntry): verb = Localize.translateLocal('workspace.invite.leftWorkspace'); } - const originalMessage = getReportActionOriginalMessage(reportAction); + const originalMessage = getOriginalMessage(reportAction); const targetAccountIDs: number[] = originalMessage?.targetAccountIDs ?? []; const personalDetails = PersonalDetailsUtils.getPersonalDetailsByIDs(targetAccountIDs, 0); @@ -1129,6 +1173,9 @@ function isOldDotReportAction(action: ReportAction): boolean { * For now, we just concat all of the text elements of the message to create the full message. */ function getMessageOfOldDotReportAction(reportAction: OnyxEntry): string { + if (!Array.isArray(reportAction?.message)) { + return ''; + } return reportAction?.message?.map((element) => element?.text).join('') ?? ''; } @@ -1161,16 +1208,16 @@ function hasRequestFromCurrentAccount(reportID: string, currentAccountID: number * Checks if a given report action corresponds to an actionable mention whisper. * @param reportAction */ -function isActionableMentionWhisper(reportAction: OnyxEntry): reportAction is ReportActionBase & OriginalMessageActionableMentionWhisper { - return reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.ACTIONABLE_MENTION_WHISPER; +function isActionableMentionWhisper(reportAction: OnyxEntry): reportAction is ReportAction { + return isActionOfType(reportAction, CONST.REPORT.ACTIONS.TYPE.ACTIONABLE_MENTION_WHISPER); } /** * Checks if a given report action corresponds to an actionable report mention whisper. * @param reportAction */ -function isActionableReportMentionWhisper(reportAction: OnyxEntry): reportAction is ReportActionBase & OriginalMessageActionableReportMentionWhisper { - return reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.ACTIONABLE_REPORT_MENTION_WHISPER; +function isActionableReportMentionWhisper(reportAction: OnyxEntry): reportAction is ReportAction { + return isActionOfType(reportAction,CONST.REPORT.ACTIONS.TYPE.ACTIONABLE_REPORT_MENTION_WHISPER); } /** @@ -1178,8 +1225,11 @@ function isActionableReportMentionWhisper(reportAction: OnyxEntry) * @param reportAction * @returns the actionable mention whisper message. */ -function getActionableMentionWhisperMessage(reportAction: OnyxEntry): string { - const originalMessage = getReportActionOriginalMessage(reportAction); +function getActionableMentionWhisperMessage(reportAction: OnyxEntry>): string { + if (!reportAction) { + return ''; + } + const originalMessage = getOriginalMessage(reportAction); const targetAccountIDs: number[] = originalMessage?.inviteeAccountIDs ?? []; const personalDetails = PersonalDetailsUtils.getPersonalDetailsByIDs(targetAccountIDs, 0); const mentionElements = targetAccountIDs.map((accountID): string => { @@ -1225,8 +1275,8 @@ function isCurrentActionUnread(report: Report | EmptyObject, reportAction: Repor * Checks if a given report action corresponds to a join request action. * @param reportAction */ -function isActionableJoinRequest(reportAction: OnyxEntry): reportAction is ReportActionBase & OriginalMessageJoinPolicyChangeLog { - return reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.ACTIONABLE_JOIN_REQUEST; +function isActionableJoinRequest(reportAction: OnyxEntry): reportAction is ReportAction { + return isActionOfType(reportAction, CONST.REPORT.ACTIONS.TYPE.ACTIONABLE_JOIN_REQUEST); } /** @@ -1237,7 +1287,7 @@ function isActionableJoinRequestPending(reportID: string): boolean { const sortedReportActions = getSortedReportActions(Object.values(getAllReportActions(reportID))); const findPendingRequest = sortedReportActions.find( (reportActionItem) => - isActionableJoinRequest(reportActionItem) && getReportActionOriginalMessage(reportActionItem).choice === '', + isActionableJoinRequest(reportActionItem) && getOriginalMessage(reportActionItem).choice === '', ); return !!findPendingRequest; } @@ -1250,10 +1300,13 @@ function isApprovedOrSubmittedReportAction(action: OnyxEntry | Emp * Gets the text version of the message in a report action */ function getReportActionMessageText(reportAction: OnyxEntry | EmptyObject): string { + if (!Array.isArray(reportAction?.message)) { + return ''; + } return reportAction?.message?.reduce((acc, curr) => `${acc}${curr?.text}`, '') ?? ''; } -function getDismissedViolationMessageText(originalMessage: OriginalMessageDismissedViolation['originalMessage']): string { +function getDismissedViolationMessageText(originalMessage: ReportAction['originalMessage']): string { const reason = originalMessage.reason; const violationName = originalMessage.violationName; return Localize.translateLocal(`violationDismissal.${violationName}.${reason}` as TranslationPaths); @@ -1335,11 +1388,17 @@ export { getReportActionHtml, getReportActionMessage, getReportActionOriginalMessage, + getOriginalMessage, isActionOfType, getMessage, isActionableTrackExpense, isLinkedTransactionHeld, isResolvedActionTrackExpense, + isClosedAction, + isRenamedAction, + isRoomChangeLogAction, + isChronosOOOListAction, + isAddCommentAction }; export type {LastVisibleMessage}; diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 23c1c5a4161b..17f49f8f8498 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -1,7 +1,7 @@ import {format} from 'date-fns'; import ExpensiMark from 'expensify-common/lib/ExpensiMark'; import Str from 'expensify-common/lib/str'; -import {isEmpty} from 'lodash'; +import {isEmpty, last} from 'lodash'; import lodashEscape from 'lodash/escape'; import lodashFindLastIndex from 'lodash/findLastIndex'; import lodashIntersection from 'lodash/intersection'; @@ -2167,8 +2167,11 @@ function getDeletedParentActionMessageForChatReport(reportAction: OnyxEntry, report: OnyxEntry, shouldUseShortDisplayName = true): string { + if (!ReportActionsUtils.isMoneyRequestAction(reportAction)) { + return ''; + } const submitterDisplayName = getDisplayNameForParticipant(report?.ownerAccountID, shouldUseShortDisplayName) ?? ''; - const originalMessage = ReportActionsUtils.getReportActionOriginalMessage(reportAction); + const originalMessage = ReportActionsUtils.getOriginalMessage(reportAction); let messageKey: TranslationPaths; if (originalMessage?.paymentType === CONST.IOU.PAYMENT_TYPE.EXPENSIFY) { messageKey = 'iou.waitingOnEnabledWallet'; @@ -2187,7 +2190,10 @@ function getReimbursementDeQueuedActionMessage( report: OnyxEntry | EmptyObject, isLHNPreview = false, ): string { - const originalMessage = ReportActionsUtils.getReportActionOriginalMessage(reportAction); + if (!ReportActionsUtils.isMoneyRequestAction(reportAction)) { + return ''; + } + const originalMessage = ReportActionsUtils.getOriginalMessage(reportAction); const amount = originalMessage?.amount; const currency = originalMessage?.currency; const formattedAmount = CurrencyUtils.convertToDisplayString(amount, currency); @@ -2389,7 +2395,7 @@ function getPolicyExpenseChatName(report: OnyxEntry, policy: OnyxEntry

(lastAction)?.reason : CONST.REPORT.ARCHIVE_REASON.DEFAULT; + ReportActionsUtils.isClosedAction(lastAction) ? ReportActionsUtils.getOriginalMessage(lastAction)?.reason : CONST.REPORT.ARCHIVE_REASON.DEFAULT; if (archiveReason === CONST.REPORT.ARCHIVE_REASON.ACCOUNT_MERGED && policyExpenseChatRole !== CONST.POLICY.ROLE.ADMIN) { return getPolicyName(report, false, policy); } @@ -2826,7 +2832,7 @@ function getTransactionReportName(reportAction: OnyxEntry | EmptyObject, - iouReportAction: OnyxEntry | EmptyObject = {}, + iouReportAction: OnyxEntry> | EmptyObject = {}, shouldConsiderScanningReceiptOrPendingRoute = false, isPreviewMessageForParentChatReport = false, policy: OnyxEntry = null, @@ -2835,7 +2841,7 @@ function getReportPreviewMessage( ): string { const reportActionMessage = ReportActionsUtils.getReportActionMessage(iouReportAction)?.html ?? ''; - if (isEmptyObject(report) || !report?.reportID) { + if (isEmptyObject(report) || !report?.reportID || isEmptyObject(iouReportAction)) { // The iouReport is not found locally after SignIn because the OpenApp API won't return iouReports if they're settled // As a temporary solution until we know how to solve this the best, we just use the message that returned from BE return reportActionMessage; @@ -2913,7 +2919,7 @@ function getReportPreviewMessage( return Localize.translateLocal('iou.fieldPending'); } - const originalMessage = ReportActionsUtils.getReportActionOriginalMessage(iouReportAction); + const originalMessage = ReportActionsUtils.isMoneyRequestAction(iouReportAction) ? ReportActionsUtils.getOriginalMessage(iouReportAction) : undefined; // Show Paid preview message if it's settled or if the amount is paid & stuck at receivers end for only chat reports. if (isSettled(report.reportID) || (report.isWaitingOnBankAccount && isPreviewMessageForParentChatReport)) { @@ -3064,14 +3070,14 @@ function isChangeLogObject(originalMessage?: ChangeLog): ChangeLog | undefined { * @param parentReportAction * @param parentReportActionMessage */ -function getAdminRoomInvitedParticipants(parentReportAction: ReportAction | Record, parentReportActionMessage: string) { - if (!ReportActionsUtils.getReportActionOriginalMessage(parentReportAction)) { +function getAdminRoomInvitedParticipants(parentReportAction: ReportAction, parentReportActionMessage: string) { + if (!ReportActionsUtils.getOriginalMessage(parentReportAction)) { return parentReportActionMessage || Localize.translateLocal('parentReportAction.deletedMessage'); } - const originalMessage = isChangeLogObject(ReportActionsUtils.getReportActionOriginalMessage(parentReportAction)); + const originalMessage = isChangeLogObject(ReportActionsUtils.getOriginalMessage(parentReportAction)); const participantAccountIDs = originalMessage?.targetAccountIDs ?? []; - const participants = participantAccountIDs.map((id) => { + const participants = participantAccountIDs.map((id: number) => { const name = getDisplayNameForParticipant(id); if (name && name?.length > 0) { return name; @@ -3194,7 +3200,7 @@ function getReportName(report: OnyxEntry, policy: OnyxEntry = nu if (parentReportActionMessage && isArchivedRoom(report)) { return `${parentReportActionMessage} (${Localize.translateLocal('common.archived')})`; } - if (ReportActionsUtils.isModifiedExpenseAction(parentReportAction)) { + if (!isEmptyObject(parentReportAction) && ReportActionsUtils.isModifiedExpenseAction(parentReportAction)) { return ModifiedExpenseMessage.getForReportAction(report?.reportID, parentReportAction); } return parentReportActionMessage; @@ -4293,7 +4299,7 @@ function buildOptimisticMovedTrackedExpenseModifiedReportAction(transactionThrea */ function updateReportPreview( iouReport: OnyxEntry, - reportPreviewAction: ReportPreviewAction, + reportPreviewAction: ReportAction, isPayRequest = false, comment = '', transaction: OnyxEntry = null, @@ -4313,7 +4319,7 @@ function updateReportPreview( } const message = getReportPreviewMessage(iouReport, reportPreviewAction); - const originalMessage = ReportActionsUtils.getReportActionOriginalMessage(reportPreviewAction); + const originalMessage = ReportActionsUtils.getOriginalMessage(reportPreviewAction); return { ...reportPreviewAction, message: [ @@ -6564,10 +6570,10 @@ function isAllowedToSubmitDraftExpenseReport(report: OnyxEntry): boolean */ function getIndicatedMissingPaymentMethod(userWallet: OnyxEntry, reportId: string, reportAction: ReportAction): MissingPaymentMethod | undefined { const isSubmitterOfUnsettledReport = isCurrentUserSubmitter(reportId) && !isSettled(reportId); - if (!isSubmitterOfUnsettledReport || reportAction.actionName !== CONST.REPORT.ACTIONS.TYPE.REIMBURSEMENT_QUEUED) { + if (!isSubmitterOfUnsettledReport || !ReportActionsUtils.isActionOfType(reportAction, CONST.REPORT.ACTIONS.TYPE.REIMBURSEMENT_QUEUED)) { return undefined; } - const paymentType = ReportActionsUtils.getReportActionOriginalMessage(reportAction)?.paymentType; + const paymentType = ReportActionsUtils.getOriginalMessage(reportAction)?.paymentType; if (paymentType === CONST.IOU.PAYMENT_TYPE.EXPENSIFY) { return isEmpty(userWallet) || userWallet.tierName === CONST.WALLET.TIER_NAME.SILVER ? 'wallet' : undefined; } diff --git a/src/libs/SidebarUtils.ts b/src/libs/SidebarUtils.ts index aa7605c07362..0efadfbab1b7 100644 --- a/src/libs/SidebarUtils.ts +++ b/src/libs/SidebarUtils.ts @@ -6,7 +6,6 @@ import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import type {PersonalDetails, PersonalDetailsList, ReportActions, TransactionViolation} from '@src/types/onyx'; import type Beta from '@src/types/onyx/Beta'; -import type {ChangeLog, OriginalMessageRenamed} from '@src/types/onyx/OriginalMessage'; import type Policy from '@src/types/onyx/Policy'; import type PriorityMode from '@src/types/onyx/PriorityMode'; import type Report from '@src/types/onyx/Report'; @@ -334,18 +333,13 @@ function getOptionData({ if ((result.isChatRoom || result.isPolicyExpenseChat || result.isThread || result.isTaskReport || isThreadMessage) && !result.isArchivedRoom) { const lastActionName = lastAction?.actionName ?? report.lastActionType; - if (lastAction?.actionName === CONST.REPORT.ACTIONS.TYPE.RENAMED) { - const newName = ReportActionsUtils.getReportActionOriginalMessage(lastAction)?.newName ?? ''; + if (ReportActionsUtils.isRenamedAction(lastAction)) { + const newName = ReportActionsUtils.getOriginalMessage(lastAction)?.newName ?? ''; result.alternateText = Localize.translate(preferredLocale, 'newRoomPage.roomRenamedTo', {newName}); } else if (ReportActionsUtils.isTaskAction(lastAction)) { result.alternateText = ReportUtils.formatReportLastMessageText(TaskUtils.getTaskReportActionMessage(lastAction).text); - } else if ( - lastActionName === CONST.REPORT.ACTIONS.TYPE.ROOM_CHANGE_LOG.INVITE_TO_ROOM || - lastActionName === CONST.REPORT.ACTIONS.TYPE.ROOM_CHANGE_LOG.REMOVE_FROM_ROOM || - lastActionName === CONST.REPORT.ACTIONS.TYPE.POLICY_CHANGE_LOG.INVITE_TO_ROOM || - lastActionName === CONST.REPORT.ACTIONS.TYPE.POLICY_CHANGE_LOG.REMOVE_FROM_ROOM - ) { - const lastActionOriginalMessage = lastAction?.actionName ? ReportActionsUtils.getReportActionOriginalMessage(lastAction) : null; + } else if (ReportActionsUtils.isRoomChangeLogAction(lastAction)) { + const lastActionOriginalMessage = lastAction?.actionName ? ReportActionsUtils.getOriginalMessage(lastAction) : null; const targetAccountIDs = lastActionOriginalMessage?.targetAccountIDs ?? []; const targetAccountIDsLength = targetAccountIDs.length !== 0 ? targetAccountIDs.length : report.lastMessageHtml?.match(/]*><\/mention-user>/g)?.length ?? 0; const verb = diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index de0891dd3ab1..5699c903fee6 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -295,8 +295,8 @@ function getReportPreviewAction(chatReportID: string, iouReportID: string): Onyx Object.values(reportActions).find( (reportAction) => reportAction && - reportAction.actionName === CONST.REPORT.ACTIONS.TYPE.REPORT_PREVIEW && - ReportActionsUtils.getReportActionOriginalMessage(reportAction).linkedReportID === iouReportID, + ReportActionsUtils.isReportPreviewAction(reportAction) && + ReportActionsUtils.getOriginalMessage(reportAction).linkedReportID === iouReportID, ) ?? null ); } diff --git a/src/libs/actions/Policy/Policy.ts b/src/libs/actions/Policy/Policy.ts index cb19cfb45867..1f0744c24fb9 100644 --- a/src/libs/actions/Policy/Policy.ts +++ b/src/libs/actions/Policy/Policy.ts @@ -3101,7 +3101,7 @@ function createWorkspaceFromIOUPayment(iouReport: Report | EmptyObject): string /** * Accept user join request to a workspace */ -function acceptJoinRequest(reportID: string, reportAction: OnyxEntry) { +function acceptJoinRequest(reportID: string, reportAction: OnyxEntry>) { const choice = CONST.REPORT.ACTIONABLE_MENTION_JOIN_WORKSPACE_RESOLUTION.ACCEPT; if (!reportAction) { return; @@ -3148,7 +3148,7 @@ function acceptJoinRequest(reportID: string, reportAction: OnyxEntry(reportAction).policyID]: { + [ReportActionsUtils.getOriginalMessage(reportAction).policyID]: { requests: [{accountID: reportAction?.actorAccountID, adminsRoomMessageReportActionID: reportAction.reportActionID}], }, }), @@ -3160,7 +3160,7 @@ function acceptJoinRequest(reportID: string, reportAction: OnyxEntry) { +function declineJoinRequest(reportID: string, reportAction: OnyxEntry>) { if (!reportAction) { return; } @@ -3206,7 +3206,7 @@ function declineJoinRequest(reportID: string, reportAction: OnyxEntry(reportAction).policyID]: { + [ReportActionsUtils.getOriginalMessage(reportAction).policyID]: { requests: [{accountID: reportAction?.actorAccountID, adminsRoomMessageReportActionID: reportAction.reportActionID}], }, }), diff --git a/src/libs/actions/User.ts b/src/libs/actions/User.ts index afc32847bff6..cab0c1c6f152 100644 --- a/src/libs/actions/User.ts +++ b/src/libs/actions/User.ts @@ -523,7 +523,7 @@ function playSoundForMessageType(pushJSON: OnyxServerUpdate[]) { } } - const types = flatten.map((data) => ReportActionsUtils.getReportActionOriginalMessage(data)).filter(Boolean) as OriginalMessage[]; + const types = flatten.map((data) => ReportActionsUtils.getOriginalMessage(data)).filter(Boolean); for (const message of types) { // Pay someone flow diff --git a/src/pages/home/report/ContextMenu/ContextMenuActions.tsx b/src/pages/home/report/ContextMenu/ContextMenuActions.tsx index 7a364a2cbbb2..ade0ca7da227 100644 --- a/src/pages/home/report/ContextMenu/ContextMenuActions.tsx +++ b/src/pages/home/report/ContextMenu/ContextMenuActions.tsx @@ -29,7 +29,6 @@ import CONST from '@src/CONST'; import type {TranslationPaths} from '@src/languages/types'; import ROUTES from '@src/ROUTES'; import type {Beta, ReportAction, ReportActionReactions, Transaction} from '@src/types/onyx'; -import type {OriginalMessageReimbursementDequeued} from '@src/types/onyx/OriginalMessage'; import type IconAsset from '@src/types/utils/IconAsset'; import type {ContextMenuAnchor} from './ReportActionContextMenu'; import {hideContextMenu, showDeleteModal} from './ReportActionContextMenu'; @@ -343,7 +342,7 @@ const ContextMenuActions: ContextMenuAction[] = [ const modifyExpenseMessage = ModifiedExpenseMessage.getForReportAction(reportID, reportAction); Clipboard.setString(modifyExpenseMessage); } else if (ReportActionsUtils.isReimbursementDeQueuedAction(reportAction)) { - const {expenseReportID} = ReportActionsUtils.getReportActionOriginalMessage(reportAction); + const {expenseReportID} = ReportActionsUtils.getOriginalMessage(reportAction); const expenseReport = ReportUtils.getReport(expenseReportID); const displayMessage = ReportUtils.getReimbursementDeQueuedActionMessage(reportAction, expenseReport); Clipboard.setString(displayMessage); diff --git a/src/pages/home/report/ContextMenu/PopoverReportActionContextMenu.tsx b/src/pages/home/report/ContextMenu/PopoverReportActionContextMenu.tsx index d6ecb440ec94..89b94da4da3b 100644 --- a/src/pages/home/report/ContextMenu/PopoverReportActionContextMenu.tsx +++ b/src/pages/home/report/ContextMenu/PopoverReportActionContextMenu.tsx @@ -14,7 +14,6 @@ import * as IOU from '@userActions/IOU'; import * as Report from '@userActions/Report'; import type {AnchorDimensions} from '@src/styles'; import type {ReportAction} from '@src/types/onyx'; -import type {IOUMessage} from '@src/types/onyx/OriginalMessage'; import BaseReportActionContextMenu from './BaseReportActionContextMenu'; import type {ContextMenuAction} from './ContextMenuActions'; import type {ContextMenuAnchor, ContextMenuType, ReportActionContextMenu} from './ReportActionContextMenu'; @@ -266,7 +265,7 @@ function PopoverReportActionContextMenu(_props: unknown, ref: ForwardedRef (onComfirmDeleteModal.current = runAndResetCallback(onComfirmDeleteModal.current)); const reportAction = reportActionRef.current; if (ReportActionsUtils.isMoneyRequestAction(reportAction)) { - const originalMessage = ReportActionsUtils.getReportActionOriginalMessage(reportAction); + const originalMessage = ReportActionsUtils.getOriginalMessage(reportAction); if (ReportActionsUtils.isTrackExpenseAction(reportAction)) { IOU.deleteTrackExpense(reportIDRef.current, originalMessage?.IOUTransactionID ?? '', reportAction); } else { diff --git a/src/pages/home/report/ReportActionItem.tsx b/src/pages/home/report/ReportActionItem.tsx index 924f956e3589..9645b29170ad 100644 --- a/src/pages/home/report/ReportActionItem.tsx +++ b/src/pages/home/report/ReportActionItem.tsx @@ -66,16 +66,6 @@ import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import type * as OnyxTypes from '@src/types/onyx'; import type {Errors} from '@src/types/onyx/OnyxCommon'; -import type { - IOUMessage, - OriginalMessageActionableMentionWhisper, - OriginalMessageActionableReportMentionWhisper, - OriginalMessageActionableTrackedExpenseWhisper, - OriginalMessageAddComment, - OriginalMessageDismissedViolation, - OriginalMessageJoinPolicyChangeLog, - OriginalMessageReimbursementQueued, -} from '@src/types/onyx/OriginalMessage'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; import AnimatedEmptyStateBackground from './AnimatedEmptyStateBackground'; import {RestrictedReadOnlyContextMenuActions} from './ContextMenu/ContextMenuActions'; @@ -171,9 +161,6 @@ type ReportActionItemProps = { shouldUseThreadDividerLine?: boolean; } & ReportActionItemOnyxProps; -const isIOUReport = (actionObj: OnyxEntry): actionObj is OnyxTypes.ReportActionBase & OnyxTypes.OriginalMessageIOU => - actionObj?.actionName === CONST.REPORT.ACTIONS.TYPE.IOU; - function ReportActionItem({ action, report, @@ -223,7 +210,7 @@ function ReportActionItem({ const reportScrollManager = useReportScrollManager(); const isActionableWhisper = ReportActionsUtils.isActionableMentionWhisper(action) || ReportActionsUtils.isActionableTrackExpense(action) || ReportActionsUtils.isActionableReportMentionWhisper(action); - const originalMessage = ReportActionsUtils.getReportActionOriginalMessage(action); + const originalMessage = ReportActionsUtils.getOriginalMessage(action); const highlightedBackgroundColorIfNeeded = useMemo( () => (isReportActionLinked ? StyleUtils.getBackgroundColorStyle(theme.messageHighlightBG) : {}), @@ -232,23 +219,19 @@ function ReportActionItem({ const isDeletedParentAction = ReportActionsUtils.isDeletedParentAction(action); const prevActionResolution = usePrevious( - isActionableWhisper - ? ( - originalMessage as - | OriginalMessageActionableMentionWhisper['originalMessage'] - | OriginalMessageActionableTrackedExpenseWhisper['originalMessage'] - | OriginalMessageActionableReportMentionWhisper['originalMessage'] - ).resolution + isActionableWhisper && 'resolution' in originalMessage ? + originalMessage.resolution : null, ); // IOUDetails only exists when we are sending money - const isSendingMoney = isIOUReport(action) && (originalMessage as IOUMessage).type === CONST.IOU.REPORT_ACTION_TYPE.PAY && (originalMessage as IOUMessage).IOUDetails; + const isSendingMoney = ReportActionsUtils.isMoneyRequestAction(action) && ReportActionsUtils.getOriginalMessage(action).type === CONST.IOU.REPORT_ACTION_TYPE.PAY && ReportActionsUtils.getOriginalMessage(action).IOUDetails; const updateHiddenState = useCallback( (isHiddenValue: boolean) => { setIsHidden(isHiddenValue); - const isAttachment = ReportUtils.isReportMessageAttachment(action.message?.at(-1)); + const message = Array.isArray(action.message) ? action.message?.at(-1) : action.message; + const isAttachment = ReportUtils.isReportMessageAttachment(message); if (!isAttachment) { return; } @@ -388,13 +371,7 @@ function ReportActionItem({ } if ( - prevActionResolution !== - (( - originalMessage as - | OriginalMessageActionableMentionWhisper['originalMessage'] - | OriginalMessageActionableTrackedExpenseWhisper['originalMessage'] - | OriginalMessageActionableReportMentionWhisper['originalMessage'] - ).resolution ?? null) + prevActionResolution !== ('resolution' in originalMessage ? originalMessage.resolution : null) ) { reportScrollManager.scrollToIndex(index); } @@ -421,12 +398,12 @@ function ReportActionItem({ const attachmentContextValue = useMemo(() => ({reportID: report.reportID, type: CONST.ATTACHMENT_TYPE.REPORT}), [report.reportID]); const actionableItemButtons: ActionableItem[] = useMemo(() => { - if (!isActionableWhisper && (!ReportActionsUtils.isActionableJoinRequest(action) || (originalMessage as OriginalMessageJoinPolicyChangeLog['originalMessage']).choice !== '')) { + if (!isActionableWhisper && (!ReportActionsUtils.isActionableJoinRequest(action) || ReportActionsUtils.getOriginalMessage(action).choice !== '')) { return []; } if (ReportActionsUtils.isActionableTrackExpense(action)) { - const transactionID = (originalMessage as OriginalMessageActionableTrackedExpenseWhisper['originalMessage'])?.transactionID; + const transactionID = ReportActionsUtils.getOriginalMessage(action)?.transactionID; return [ { text: 'actionableMentionTrackExpense.submit', @@ -537,24 +514,23 @@ function ReportActionItem({ */ const renderItemContent = (hovered = false, isWhisper = false, hasErrors = false): React.JSX.Element => { let children; - const iouOriginalMessage = originalMessage as IOUMessage; // Show the MoneyRequestPreview for when expense is present if ( - isIOUReport(action) && - iouOriginalMessage && + ReportActionsUtils.isMoneyRequestAction(action) && + ReportActionsUtils.getOriginalMessage(action) && // For the pay flow, we only want to show MoneyRequestAction when sending money. When paying, we display a regular system message - (iouOriginalMessage.type === CONST.IOU.REPORT_ACTION_TYPE.CREATE || - iouOriginalMessage.type === CONST.IOU.REPORT_ACTION_TYPE.SPLIT || - iouOriginalMessage.type === CONST.IOU.REPORT_ACTION_TYPE.TRACK || + (ReportActionsUtils.getOriginalMessage(action)?.type === CONST.IOU.REPORT_ACTION_TYPE.CREATE || + ReportActionsUtils.getOriginalMessage(action)?.type === CONST.IOU.REPORT_ACTION_TYPE.SPLIT || + ReportActionsUtils.getOriginalMessage(action)?.type === CONST.IOU.REPORT_ACTION_TYPE.TRACK || isSendingMoney) ) { // There is no single iouReport for bill splits, so only 1:1 requests require an iouReportID - const iouReportID = iouOriginalMessage.IOUReportID ? iouOriginalMessage.IOUReportID.toString() : '0'; + const iouReportID = ReportActionsUtils.getOriginalMessage(action)?.IOUReportID ? ReportActionsUtils.getOriginalMessage(action)?.IOUReportID?.toString() ?? '0' : '0'; children = ( ); - } else if (action.actionName === CONST.REPORT.ACTIONS.TYPE.REIMBURSEMENT_QUEUED) { + } else if (ReportActionsUtils.isReimbursementQueuedAction(action)) { const linkedReport = ReportUtils.isChatThread(report) ? ReportUtils.getReport(report.parentReportID) : report; const submitterDisplayName = PersonalDetailsUtils.getDisplayNameOrDefault(personalDetails[linkedReport?.ownerAccountID ?? -1]); - const paymentType = (originalMessage as OriginalMessageReimbursementQueued['originalMessage']).paymentType ?? ''; + const paymentType = ReportActionsUtils.getOriginalMessage(action).paymentType ?? ''; const missingPaymentMethod = ReportUtils.getIndicatedMissingPaymentMethod(userWallet, linkedReport?.reportID ?? '', action); children = ( @@ -662,9 +638,9 @@ function ReportActionItem({ children = ; } else if (action.actionName === CONST.REPORT.ACTIONS.TYPE.MERGED_WITH_CASH_TRANSACTION) { children = ; - } else if (action.actionName === CONST.REPORT.ACTIONS.TYPE.DISMISSED_VIOLATION) { + } else if (ReportActionsUtils.isActionOfType(action, CONST.REPORT.ACTIONS.TYPE.DISMISSED_VIOLATION)) { children = ( - + ); } else { const hasBeenFlagged = @@ -929,7 +905,7 @@ function ReportActionItem({ if (action.actionName === CONST.REPORT.ACTIONS.TYPE.RENAMED) { return ; } - if (action.actionName === CONST.REPORT.ACTIONS.TYPE.CHRONOS_OOO_LIST) { + if (ReportActionsUtils.isChronosOOOListAction(action)) { return ( 1; - const iouReportID = isIOUReport(action) && (originalMessage as IOUMessage).IOUReportID ? ((originalMessage as IOUMessage)?.IOUReportID ?? '').toString() : '0'; + const iouReportID = ReportActionsUtils.isMoneyRequestAction(action) && ReportActionsUtils.getOriginalMessage(action).IOUReportID ? (ReportActionsUtils.getOriginalMessage(action)?.IOUReportID ?? '').toString() : '0'; const transactionsWithReceipts = ReportUtils.getTransactionsWithReceipts(iouReportID); const isWhisper = whisperedTo.length > 0 && transactionsWithReceipts.length === 0 && !action.pendingAction; const whisperedToPersonalDetails = isWhisper @@ -1087,13 +1057,13 @@ export default withOnyx({ }, transaction: { key: ({parentReportActionForTransactionThread}) => { - const originalMessage = ReportActionsUtils.getReportActionOriginalMessage(parentReportActionForTransactionThread); + const originalMessage = !!parentReportActionForTransactionThread && ReportActionsUtils.isMoneyRequestAction(parentReportActionForTransactionThread) ? ReportActionsUtils.getOriginalMessage(parentReportActionForTransactionThread) : undefined; const transactionID = originalMessage?.IOUTransactionID ? originalMessage?.IOUTransactionID : 0; return `${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`; }, }, linkedTransactionRouteError: { - key: ({action}) => `${ONYXKEYS.COLLECTION.TRANSACTION}${ReportActionsUtils.getReportActionOriginalMessage(action)?.IOUTransactionID ?? 0}`, + key: ({action}) => `${ONYXKEYS.COLLECTION.TRANSACTION}${ReportActionsUtils.isMoneyRequestAction(action) ? ReportActionsUtils.getOriginalMessage(action)?.IOUTransactionID ?? 0 : 0}`, selector: (transaction: OnyxEntry) => transaction?.errorFields?.route ?? null, }, })( diff --git a/src/pages/home/report/ReportActionItemMessage.tsx b/src/pages/home/report/ReportActionItemMessage.tsx index 252066a68cc3..def7d76b5820 100644 --- a/src/pages/home/report/ReportActionItemMessage.tsx +++ b/src/pages/home/report/ReportActionItemMessage.tsx @@ -12,7 +12,6 @@ import * as ReportUtils from '@libs/ReportUtils'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import type {ReportAction, Transaction} from '@src/types/onyx'; -import type {IOUMessage, OriginalMessageAddComment} from '@src/types/onyx/OriginalMessage'; import TextCommentFragment from './comment/TextCommentFragment'; import ReportActionItemFragment from './ReportActionItemFragment'; @@ -42,7 +41,8 @@ function ReportActionItemMessage({action, transaction, displayAsGroup, reportID, const styles = useThemeStyles(); const {translate} = useLocalize(); - const fragments = (action.previousMessage ?? action.message ?? []).filter((item) => !!item); + const actionMessage = action.previousMessage ?? action.message; + const fragments = Array.isArray(actionMessage) ? actionMessage.filter((item) => !!item) : !!actionMessage ? [actionMessage] : []; const isIOUReport = ReportActionsUtils.isMoneyRequestAction(action); if (ReportActionsUtils.isMemberChangeAction(action)) { @@ -89,7 +89,7 @@ function ReportActionItemMessage({action, transaction, displayAsGroup, reportID, isThreadParentMessage={ReportActionsUtils.isThreadParentMessage(action, reportID)} pendingAction={action.pendingAction} actionName={action.actionName} - source={ReportActionsUtils.getReportActionOriginalMessage(action)?.source} + source={ReportActionsUtils.isAddCommentAction(action) ? ReportActionsUtils.getOriginalMessage(action)?.source : ''} accountID={action.actorAccountID ?? 0} style={style} displayAsGroup={displayAsGroup} diff --git a/src/pages/iou/SplitBillDetailsPage.tsx b/src/pages/iou/SplitBillDetailsPage.tsx index 396ae51a2ee4..e59a609830b3 100644 --- a/src/pages/iou/SplitBillDetailsPage.tsx +++ b/src/pages/iou/SplitBillDetailsPage.tsx @@ -23,7 +23,6 @@ import ONYXKEYS from '@src/ONYXKEYS'; import type SCREENS from '@src/SCREENS'; import type {PersonalDetailsList, Report, ReportAction, Session, Transaction} from '@src/types/onyx'; import type {Participant} from '@src/types/onyx/IOU'; -import type {IOUMessage} from '@src/types/onyx/OriginalMessage'; import type {ReportActions} from '@src/types/onyx/ReportAction'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; @@ -61,7 +60,7 @@ function SplitBillDetailsPage({personalDetails, report, route, reportActions, tr const {translate} = useLocalize(); const reportAction = useMemo(() => reportActions?.[route.params.reportActionID] ?? ({} as ReportAction), [reportActions, route.params.reportActionID]); const participantAccountIDs = - reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.IOU ? ReportActionsUtils.getOriginalMessage(reportAction).participantAccountIDs ?? [] : []; + ReportActionsUtils.isMoneyRequestAction(reportAction) ? ReportActionsUtils.getOriginalMessage(reportAction).participantAccountIDs ?? [] : []; // In case this is workspace split expense, we manually add the workspace as the second participant of the split expense // because we don't save any accountID in the report action's originalMessage other than the payee's accountID @@ -148,7 +147,7 @@ const WrappedComponent = withOnyx { const reportAction = reportActions?.[route.params.reportActionID]; - const originalMessage = ReportActionsUtils.getReportActionOriginalMessage(reportAction); + const originalMessage = reportAction && ReportActionsUtils.isMoneyRequestAction(reportAction) ? ReportActionsUtils.getOriginalMessage(reportAction) : undefined; const IOUTransactionID = reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.IOU && originalMessage?.IOUTransactionID ? originalMessage.IOUTransactionID : 0; return `${ONYXKEYS.COLLECTION.TRANSACTION}${IOUTransactionID}`; }, @@ -156,7 +155,7 @@ const WrappedComponent = withOnyx { const reportAction = reportActions?.[route.params.reportActionID]; - const originalMessage = ReportActionsUtils.getReportActionOriginalMessage(reportAction); + const originalMessage = reportAction && ReportActionsUtils.isMoneyRequestAction(reportAction) ? ReportActionsUtils.getOriginalMessage(reportAction) : undefined; const IOUTransactionID = reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.IOU && originalMessage?.IOUTransactionID ? originalMessage.IOUTransactionID : 0; return `${ONYXKEYS.COLLECTION.SPLIT_TRANSACTION_DRAFT}${IOUTransactionID}`; }, diff --git a/src/types/onyx/OriginalMessage.ts b/src/types/onyx/OriginalMessage.ts index 7eaf1d448b8d..336352e7b804 100644 --- a/src/types/onyx/OriginalMessage.ts +++ b/src/types/onyx/OriginalMessage.ts @@ -265,6 +265,7 @@ type OriginalMessageMap = { [CONST.REPORT.ACTIONS.TYPE.UNHOLD]: never; [CONST.REPORT.ACTIONS.TYPE.UNSHARE]: never; [CONST.REPORT.ACTIONS.TYPE.UPDATE_GROUP_CHAT_MEMBER_ROLE]: never; + [CONST.REPORT.ACTIONS.TYPE.REIMBURSEMENT_SETUP_REQUESTED]: never; } & { [T in ValueOf]: OriginalMessageChangeLog; } & { diff --git a/src/types/onyx/ReportAction.ts b/src/types/onyx/ReportAction.ts index d7e5aff17909..634788503cfe 100644 --- a/src/types/onyx/ReportAction.ts +++ b/src/types/onyx/ReportAction.ts @@ -230,10 +230,10 @@ type ReportAction = ReportActionB originalMessage: OriginalMessage; /** report action message */ - message?: OriginalMessage | Array; + message?: OriginalMessage & Message | Array; /** report action message */ - previousMessage?: OriginalMessage | Array; + previousMessage?: OriginalMessage & Message | Array; }; type ReportActionWithHTMLMessage = ReportAction; diff --git a/tests/actions/IOUTest.ts b/tests/actions/IOUTest.ts index d0439a21ff5e..aae355e5ba32 100644 --- a/tests/actions/IOUTest.ts +++ b/tests/actions/IOUTest.ts @@ -18,9 +18,7 @@ import * as ReportUtils from '@src/libs/ReportUtils'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import type * as OnyxTypes from '@src/types/onyx'; -import type {IOUMessage, OriginalMessageIOU, OriginalMessageModifiedExpense} from '@src/types/onyx/OriginalMessage'; import type {Participant} from '@src/types/onyx/Report'; -import type {ReportActionBase} from '@src/types/onyx/ReportAction'; import {toCollectionDataSet} from '@src/types/utils/CollectionDataSet'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; import PusherHelper from '../utils/PusherHelper'; @@ -128,13 +126,13 @@ describe('actions/IOU', () => { (reportAction) => reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.CREATED, ); const iouActions = Object.values(reportActionsForIOUReport ?? {}).filter( - (reportAction): reportAction is ReportActionBase & OriginalMessageIOU => reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.IOU, + (reportAction) => ReportActionsUtils.isMoneyRequestAction(reportAction) ); expect(Object.values(createdActions).length).toBe(1); expect(Object.values(iouActions).length).toBe(1); createdAction = createdActions?.[0] ?? null; iouAction = iouActions?.[0] ?? null; - const originalMessage = ReportActionsUtils.getReportActionOriginalMessage(iouAction); + const originalMessage = ReportActionsUtils.isMoneyRequestAction(iouAction) ? ReportActionsUtils.getOriginalMessage(iouAction) : undefined; // The CREATED action should not be created after the IOU action expect(Date.parse(createdAction?.created ?? '')).toBeLessThan(Date.parse(iouAction?.created ?? '')); @@ -265,7 +263,7 @@ describe('actions/IOU', () => { created: DateUtils.getDBTime(), }; let iouReportID: string | undefined; - let iouAction: OnyxEntry; + let iouAction: OnyxEntry>; let iouCreatedAction: OnyxEntry; let transactionID: string | undefined; mockFetch?.pause?.(); @@ -317,9 +315,9 @@ describe('actions/IOU', () => { iouCreatedAction = Object.values(allIOUReportActions ?? {}).find((reportAction) => reportAction.actionName === CONST.REPORT.ACTIONS.TYPE.CREATED) ?? null; iouAction = Object.values(allIOUReportActions ?? {}).find( - (reportAction): reportAction is ReportActionBase & OriginalMessageIOU => reportAction.actionName === CONST.REPORT.ACTIONS.TYPE.IOU, + (reportAction): reportAction is OnyxTypes.ReportAction => ReportActionsUtils.isMoneyRequestAction(reportAction) ) ?? null; - const originalMessage = ReportActionsUtils.getReportActionOriginalMessage(iouAction); + const originalMessage = iouAction ? ReportActionsUtils.getOriginalMessage(iouAction) : null; // The CREATED action should not be created after the IOU action expect(Date.parse(iouCreatedAction?.created ?? '')).toBeLessThan(Date.parse(iouAction?.created ?? '')); @@ -357,6 +355,7 @@ describe('actions/IOU', () => { expect(Object.values(allTransactions ?? {}).length).toBe(1); const transaction = Object.values(allTransactions ?? {}).find((t) => !isEmptyObject(t)); transactionID = transaction?.transactionID; + const originalMessage = iouAction ? ReportActionsUtils.getOriginalMessage(iouAction) : null // The transaction should be attached to the IOU report expect(transaction?.reportID).toBe(iouReportID); @@ -373,7 +372,7 @@ describe('actions/IOU', () => { expect(transaction?.pendingAction).toBe(CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD); // The transactionID on the iou action should match the one from the transactions collection - expect(ReportActionsUtils.getOriginalMessage(iouAction)?.IOUTransactionID).toBe(transactionID); + expect(originalMessage?.IOUTransactionID).toBe(transactionID); resolve(); }, @@ -448,7 +447,7 @@ describe('actions/IOU', () => { currency: CONST.CURRENCY.USD, total: existingTransaction.amount, }; - const iouAction: OnyxEntry = { + const iouAction: OnyxEntry> = { reportActionID: NumberUtils.rand64(), actionName: CONST.REPORT.ACTIONS.TYPE.IOU, actorAccountID: RORY_ACCOUNT_ID, @@ -462,7 +461,7 @@ describe('actions/IOU', () => { participantAccountIDs: [RORY_ACCOUNT_ID, CARLOS_ACCOUNT_ID], }, }; - let newIOUAction: OnyxEntry; + let newIOUAction: OnyxEntry>; let newTransaction: OnyxEntry; mockFetch?.pause?.(); return Onyx.set(`${ONYXKEYS.COLLECTION.REPORT}${chatReportID}`, chatReport) @@ -517,11 +516,11 @@ describe('actions/IOU', () => { expect(Object.values(reportActionsForIOUReport ?? {}).length).toBe(3); newIOUAction = Object.values(reportActionsForIOUReport ?? {}).find( - (reportAction): reportAction is ReportActionBase & OriginalMessageIOU => + (reportAction): reportAction is OnyxTypes.ReportAction => reportAction?.reportActionID !== createdAction.reportActionID && reportAction?.reportActionID !== iouAction?.reportActionID, ) ?? null; - const newOriginalMessage = ReportActionsUtils.getReportActionOriginalMessage(newIOUAction); + const newOriginalMessage = newIOUAction ? ReportActionsUtils.getOriginalMessage(newIOUAction) : null; // The IOUReportID should be correct expect(ReportActionsUtils.getOriginalMessage(iouAction).IOUReportID).toBe(iouReportID); @@ -564,7 +563,7 @@ describe('actions/IOU', () => { expect(newTransaction?.pendingAction).toBe(CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD); // The transactionID on the iou action should match the one from the transactions collection - expect(ReportActionsUtils.getOriginalMessage(newIOUAction)?.IOUTransactionID).toBe(newTransaction?.transactionID); + expect(ReportActionsUtils.isMoneyRequestAction(newIOUAction) ? ReportActionsUtils.getOriginalMessage(newIOUAction)?.IOUTransactionID : '0').toBe(newTransaction?.transactionID); resolve(); }, From 573e5d434fe375cdf18349c3ac6fb1db3d7e675d Mon Sep 17 00:00:00 2001 From: nkdengineer Date: Tue, 4 Jun 2024 14:30:47 +0700 Subject: [PATCH 18/45] fix type error --- src/libs/ReportActionsUtils.ts | 7 ++- src/libs/ReportUtils.ts | 80 +++++++++++++++++-------------- src/types/onyx/OriginalMessage.ts | 3 +- 3 files changed, 48 insertions(+), 42 deletions(-) diff --git a/src/libs/ReportActionsUtils.ts b/src/libs/ReportActionsUtils.ts index 5039ea98be61..e7ec5cd6473f 100644 --- a/src/libs/ReportActionsUtils.ts +++ b/src/libs/ReportActionsUtils.ts @@ -1102,9 +1102,7 @@ function getMemberChangeMessageElements(reportAction: OnyxEntry): } function getReportActionHtml(reportAction: PartialReportAction): string { - // @ts-expect-error Handle refactor not using message array, will remove when Back End is changed complete https://github.com/Expensify/App/issues/39797 - // eslint-disable-next-line @typescript-eslint/no-unsafe-return - return (reportAction?.message?.html as string) || reportAction?.message?.[0]?.html; + return getReportActionMessage(reportAction)?.html; } function getReportActionText(reportAction: PartialReportAction): string { @@ -1407,7 +1405,8 @@ export { isRenamedAction, isRoomChangeLogAction, isChronosOOOListAction, - isAddCommentAction + isAddCommentAction, + isPolicyChangelLogAction }; export type {LastVisibleMessage}; diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index aa2222379186..3edec9c057f0 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -38,23 +38,9 @@ import type { } from '@src/types/onyx'; import type {Participant} from '@src/types/onyx/IOU'; import type {Errors, Icon, PendingAction} from '@src/types/onyx/OnyxCommon'; -import type { - ChangeLog, - Closed, - IOUMessage, - OriginalMessageActionName, - OriginalMessageCreated, - OriginalMessageDismissedViolation, - OriginalMessageReimbursementDequeued, - OriginalMessageReimbursementQueued, - OriginalMessageRenamed, - OriginalMessageReportPreview, - PaymentMethodType, - ReimbursementDeQueuedMessage, -} from '@src/types/onyx/OriginalMessage'; import type {Status} from '@src/types/onyx/PersonalDetails'; import type {NotificationPreference, Participants, PendingChatMember, Participant as ReportParticipant} from '@src/types/onyx/Report'; -import type {Message, ReportActionBase, ReportActions, ReportPreviewAction} from '@src/types/onyx/ReportAction'; +import type {Message, ReportActions} from '@src/types/onyx/ReportAction'; import type {Comment, Receipt, TransactionChanges, WaypointCollection} from '@src/types/onyx/Transaction'; import type {EmptyObject} from '@src/types/utils/EmptyObject'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; @@ -86,6 +72,8 @@ import * as TransactionUtils from './TransactionUtils'; import * as Url from './Url'; import type {AvatarSource} from './UserUtils'; import * as UserUtils from './UserUtils'; +import { OriginalMessageChangeLog, PaymentMethodType } from '@src/types/onyx/OriginalMessage'; +import ReportActionName from '@src/types/onyx/ReportActionName'; type AvatarRange = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18; @@ -263,11 +251,11 @@ type OptimisticDismissedViolationReportAction = Pick< 'actionName' | 'actorAccountID' | 'avatar' | 'created' | 'message' | 'originalMessage' | 'person' | 'reportActionID' | 'shouldShow' | 'pendingAction' >; -type OptimisticCreatedReportAction = OriginalMessageCreated & - Pick; +type OptimisticCreatedReportAction = + Pick, 'actorAccountID' | 'automatic' | 'avatar' | 'created' | 'message' | 'person' | 'reportActionID' | 'shouldShow' | 'pendingAction' | 'actionName'>; -type OptimisticRenamedReportAction = OriginalMessageRenamed & - Pick; +type OptimisticRenamedReportAction = + Pick, 'actorAccountID' | 'automatic' | 'avatar' | 'created' | 'message' | 'person' | 'reportActionID' | 'shouldShow' | 'pendingAction' | 'actionName' | 'originalMessage'>; type OptimisticChatReport = Pick< Report, @@ -341,7 +329,7 @@ type OptimisticWorkspaceChats = { }; type OptimisticModifiedExpenseReportAction = Pick< - ReportAction, + ReportAction, 'actionName' | 'actorAccountID' | 'automatic' | 'avatar' | 'created' | 'isAttachment' | 'message' | 'originalMessage' | 'person' | 'pendingAction' | 'reportActionID' | 'shouldShow' > & {reportID?: string}; @@ -2199,11 +2187,11 @@ function getReimbursementQueuedActionMessage(reportAction: OnyxEntry, + reportAction: OnyxEntry>, report: OnyxEntry | EmptyObject, isLHNPreview = false, ): string { - if (!ReportActionsUtils.isMoneyRequestAction(reportAction)) { + if (!ReportActionsUtils.isReimbursementDeQueuedAction(reportAction)) { return ''; } const originalMessage = ReportActionsUtils.getOriginalMessage(reportAction); @@ -2625,12 +2613,12 @@ function canEditMoneyRequest(reportAction: OnyxEntry): boolean { } // If the report action is not IOU type, return true early - if (reportAction?.actionName !== CONST.REPORT.ACTIONS.TYPE.IOU) { + if (!ReportActionsUtils.isMoneyRequestAction(reportAction)) { return true; } const allowedReportActionType: Array> = [CONST.IOU.REPORT_ACTION_TYPE.TRACK, CONST.IOU.REPORT_ACTION_TYPE.CREATE]; - const originalMessage = ReportActionsUtils.getOriginalMessage(reportAction); + const originalMessage = ReportActionsUtils.getOriginalMessage(reportAction); if (!allowedReportActionType.includes(originalMessage.type)) { return false; @@ -2680,7 +2668,7 @@ function canEditFieldOfMoneyRequest(reportAction: OnyxEntry, field CONST.EDIT_REQUEST_FIELD.DISTANCE, ]; - if (!canEditMoneyRequest(reportAction)) { + if (!canEditMoneyRequest(reportAction) || !ReportActionsUtils.isMoneyRequestAction(reportAction)) { return false; } @@ -2689,7 +2677,7 @@ function canEditFieldOfMoneyRequest(reportAction: OnyxEntry, field return true; } - const iouMessage = ReportActionsUtils.getOriginalMessage(reportAction); + const iouMessage = ReportActionsUtils.getOriginalMessage(reportAction); const moneyRequestReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${iouMessage?.IOUReportID}`] ?? ({} as Report); const transaction = allTransactions?.[`${ONYXKEYS.COLLECTION.TRANSACTION}${iouMessage?.IOUTransactionID}`] ?? ({} as Transaction); @@ -2730,12 +2718,13 @@ function canEditFieldOfMoneyRequest(reportAction: OnyxEntry, field */ function canEditReportAction(reportAction: OnyxEntry): boolean { const isCommentOrIOU = reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.ADD_COMMENT || reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.IOU; + const message = Array.isArray(reportAction?.message) ? reportAction?.message?.[0]: reportAction?.message; return Boolean( reportAction?.actorAccountID === currentUserAccountID && isCommentOrIOU && canEditMoneyRequest(reportAction) && // Returns true for non-IOU actions - !isReportMessageAttachment(reportAction?.message?.[0]) && + !isReportMessageAttachment(message) && (isEmptyObject(reportAction.attachmentInfo) || !reportAction.isOptimisticAction) && !ReportActionsUtils.isDeletedAction(reportAction) && !ReportActionsUtils.isCreatedTaskReportAction(reportAction) && @@ -2776,8 +2765,8 @@ function areAllRequestsBeingSmartScanned(iouReportID: string, reportPreviewActio function getLinkedTransaction(reportAction: OnyxEntry): Transaction | EmptyObject { let transactionID = ''; - if (reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.IOU) { - transactionID = ReportActionsUtils.getOriginalMessage(reportAction)?.IOUTransactionID ?? ''; + if (ReportActionsUtils.isMoneyRequestAction(reportAction)) { + transactionID = ReportActionsUtils.getOriginalMessage(reportAction)?.IOUTransactionID ?? ''; } return allTransactions?.[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`] ?? {}; @@ -3090,7 +3079,7 @@ function getModifiedExpenseOriginalMessage( * Check if original message is an object and can be used as a ChangeLog type * @param originalMessage */ -function isChangeLogObject(originalMessage?: ChangeLog): ChangeLog | undefined { +function isChangeLogObject(originalMessage?: OriginalMessageChangeLog): OriginalMessageChangeLog | undefined { if (originalMessage && typeof originalMessage === 'object') { return originalMessage; } @@ -3102,10 +3091,17 @@ function isChangeLogObject(originalMessage?: ChangeLog): ChangeLog | undefined { * @param parentReportAction * @param parentReportActionMessage */ -function getAdminRoomInvitedParticipants(parentReportAction: ReportAction, parentReportActionMessage: string) { +function getAdminRoomInvitedParticipants(parentReportAction: ReportAction | EmptyObject, parentReportActionMessage: string) { + if (isEmptyObject(parentReportAction)) { + return parentReportActionMessage || Localize.translateLocal('parentReportAction.deletedMessage'); + } if (!ReportActionsUtils.getOriginalMessage(parentReportAction)) { return parentReportActionMessage || Localize.translateLocal('parentReportAction.deletedMessage'); } + if (!ReportActionsUtils.isPolicyChangelLogAction(parentReportAction) || !ReportActionsUtils.isRoomChangeLogAction(parentReportAction)) { + return parentReportActionMessage || Localize.translateLocal('parentReportAction.deletedMessage'); + } + const originalMessage = isChangeLogObject(ReportActionsUtils.getOriginalMessage(parentReportAction)); const participantAccountIDs = originalMessage?.targetAccountIDs ?? []; @@ -3169,7 +3165,7 @@ function getReportActionMessage(reportAction: ReportAction | EmptyObject, parent if (ReportActionsUtils.isReimbursementQueuedAction(reportAction)) { return getReimbursementQueuedActionMessage(reportAction, getReport(parentReportID), false); } - return Str.removeSMSDomain(reportAction?.message?.[0]?.text ?? ''); + return Str.removeSMSDomain(ReportActionsUtils.getReportActionText(reportAction) ?? ''); } /** @@ -3576,6 +3572,11 @@ function buildOptimisticAddCommentReportAction( text: textForNewComment, }, ], + originalMessage: { + html: htmlForNewComment, + text: textForNewComment, + whisperedTo: [] + }, isFirstItem: false, isAttachment, attachmentInfo, @@ -3647,15 +3648,18 @@ function buildOptimisticTaskCommentReportAction( createdOffset = 0, ): OptimisticReportAction { const reportAction = buildOptimisticAddCommentReportAction(text, undefined, undefined, createdOffset, undefined, taskReportID); - if (reportAction.reportAction.message?.[0]) { + if (Array.isArray(reportAction.reportAction.message) && reportAction.reportAction.message?.[0]) { reportAction.reportAction.message[0].taskReportID = taskReportID; + } else if (!Array.isArray(reportAction.reportAction.message) && reportAction.reportAction.message) { + reportAction.reportAction.message.taskReportID = taskReportID; } // These parameters are not saved on the reportAction, but are used to display the task in the UI // Added when we fetch the reportActions on a report reportAction.reportAction.originalMessage = { - html: ReportActionsUtils.getReportActionMessage(reportAction.reportAction)?.html, + html: ReportActionsUtils.getReportActionMessage(reportAction.reportAction)?.html ?? '', taskReportID: ReportActionsUtils.getReportActionMessage(reportAction.reportAction)?.taskReportID, + whisperedTo: [] }; reportAction.reportAction.childReportID = taskReportID; reportAction.reportAction.parentReportID = parentReportID; @@ -3995,7 +3999,7 @@ function buildOptimisticIOUReportAction( ): OptimisticIOUReportAction { const IOUReportID = iouReportID || generateReportID(); - const originalMessage: IOUMessage = { + const originalMessage: ReportAction['originalMessage'] = { amount, comment, currency, @@ -4339,7 +4343,7 @@ function updateReportPreview( isPayRequest = false, comment = '', transaction: OnyxEntry = null, -): ReportPreviewAction { +): ReportAction { const hasReceipt = TransactionUtils.hasReceipt(transaction); const recentReceiptTransactions = reportPreviewAction?.childRecentReceiptTransactionIDs ?? {}; const transactionsToKeep = TransactionUtils.getRecentTransactions(recentReceiptTransactions); @@ -4385,7 +4389,7 @@ function updateReportPreview( function buildOptimisticTaskReportAction( taskReportID: string, - actionName: OriginalMessageActionName, + actionName: typeof CONST.REPORT.ACTIONS.TYPE.TASK_COMPLETED | typeof CONST.REPORT.ACTIONS.TYPE.TASK_REOPENED | typeof CONST.REPORT.ACTIONS.TYPE.TASK_CANCELLED, message = '', actorAccountID = currentUserAccountID, createdOffset = 0, @@ -4394,6 +4398,8 @@ function buildOptimisticTaskReportAction( taskReportID, type: actionName, text: message, + html: message, + whisperedTo: [], }; return { actionName, diff --git a/src/types/onyx/OriginalMessage.ts b/src/types/onyx/OriginalMessage.ts index 336352e7b804..60a181b66c04 100644 --- a/src/types/onyx/OriginalMessage.ts +++ b/src/types/onyx/OriginalMessage.ts @@ -178,6 +178,7 @@ type OriginalMessageModifiedExpense = { oldBillable?: string; billable?: string; whisperedTo?: number[]; + movedToReportID?: string; }; type OriginalMessageReimbursementQueued = { @@ -296,4 +297,4 @@ type AssertAllActionsWithHTMLAreListed = AssertTypesEqual< export default OriginalMessage; export {REPORT_ACTIONS_WITH_HTML_MESSAGE}; -export type {ChronosOOOEvent, PaymentMethodType, OriginalMessageSource, ReportActionNamesWithHTMLMessage, Reaction, Decision}; +export type {ChronosOOOEvent, PaymentMethodType, OriginalMessageSource, ReportActionNamesWithHTMLMessage, Reaction, Decision, OriginalMessageChangeLog}; From 3d59b1a83bd964d33d3b62dd85780692510bacb2 Mon Sep 17 00:00:00 2001 From: nkdengineer Date: Tue, 4 Jun 2024 15:19:37 +0700 Subject: [PATCH 19/45] fix type --- src/libs/actions/Policy/Policy.ts | 1 - src/types/onyx/OriginalMessage.ts | 182 +++++++++++++++++++++++++++++- src/types/onyx/ReportAction.ts | 6 +- 3 files changed, 183 insertions(+), 6 deletions(-) diff --git a/src/libs/actions/Policy/Policy.ts b/src/libs/actions/Policy/Policy.ts index 1f0744c24fb9..bc5ed08e8218 100644 --- a/src/libs/actions/Policy/Policy.ts +++ b/src/libs/actions/Policy/Policy.ts @@ -80,7 +80,6 @@ import type { Transaction, } from '@src/types/onyx'; import type {ErrorFields, Errors, PendingAction} from '@src/types/onyx/OnyxCommon'; -import type {OriginalMessageJoinPolicyChangeLog} from '@src/types/onyx/OriginalMessage'; import type {Attributes, CompanyAddress, CustomUnit, Rate, TaxRate, Unit} from '@src/types/onyx/Policy'; import type {OnyxData} from '@src/types/onyx/Request'; import type {EmptyObject} from '@src/types/utils/EmptyObject'; diff --git a/src/types/onyx/OriginalMessage.ts b/src/types/onyx/OriginalMessage.ts index 60a181b66c04..ec251c907792 100644 --- a/src/types/onyx/OriginalMessage.ts +++ b/src/types/onyx/OriginalMessage.ts @@ -210,6 +210,185 @@ type OriginalMessageDismissedViolation = { violationName: string; }; +type OriginalMessageMap1 = { + [CONST.REPORT.ACTIONS.TYPE.ACTIONABLE_JOIN_REQUEST]: { + originalMessage: OriginalMessageJoinPolicyChangeLog + }; + [CONST.REPORT.ACTIONS.TYPE.ACTIONABLE_MENTION_WHISPER]: { + originalMessage: OriginalMessageActionableMentionWhisper; + }; + [CONST.REPORT.ACTIONS.TYPE.ACTIONABLE_REPORT_MENTION_WHISPER]: { + originalMessage: OriginalMessageActionableReportMentionWhisper + }; + [CONST.REPORT.ACTIONS.TYPE.ACTIONABLE_TRACK_EXPENSE_WHISPER]: { + originalMessage: OriginalMessageActionableTrackedExpenseWhisper; + } + [CONST.REPORT.ACTIONS.TYPE.ADD_COMMENT]: { + originalMessage: OriginalMessageAddComment; + }; + [CONST.REPORT.ACTIONS.TYPE.APPROVED]: { + originalMessage?: never + }; + [CONST.REPORT.ACTIONS.TYPE.CHANGE_FIELD]: { + originalMessage?: never + }; + [CONST.REPORT.ACTIONS.TYPE.CHANGE_POLICY]: { + originalMessage?: never + }; + [CONST.REPORT.ACTIONS.TYPE.CHANGE_TYPE]: { + originalMessage?: never + }; + [CONST.REPORT.ACTIONS.TYPE.CHRONOS_OOO_LIST]: { + originalMessage: OriginalMessageChronosOOOList; + }; + [CONST.REPORT.ACTIONS.TYPE.CLOSED]: { + originalMessage: OriginalMessageClosed; + }; + [CONST.REPORT.ACTIONS.TYPE.CREATED]: { + originalMessage?: never + }; + [CONST.REPORT.ACTIONS.TYPE.DELEGATE_SUBMIT]: { + originalMessage?: never + }; + [CONST.REPORT.ACTIONS.TYPE.DELETED_ACCOUNT]: { + originalMessage?: never + }; + [CONST.REPORT.ACTIONS.TYPE.DISMISSED_VIOLATION]: { + originalMessage: OriginalMessageDismissedViolation; + }; + [CONST.REPORT.ACTIONS.TYPE.DONATION]: { + originalMessage?: never + }; + [CONST.REPORT.ACTIONS.TYPE.EXPORTED_TO_CSV]: { + originalMessage?: never + }; + [CONST.REPORT.ACTIONS.TYPE.EXPORTED_TO_INTEGRATION]: { + originalMessage?: never + }; + [CONST.REPORT.ACTIONS.TYPE.EXPORTED_TO_QUICK_BOOKS]: { + originalMessage?: never + }; + [CONST.REPORT.ACTIONS.TYPE.FORWARDED]: { + originalMessage?: never + }; + [CONST.REPORT.ACTIONS.TYPE.HOLD]: { + originalMessage?: never + }; + [CONST.REPORT.ACTIONS.TYPE.HOLD_COMMENT]: { + originalMessage?: never + }; + [CONST.REPORT.ACTIONS.TYPE.INTEGRATIONS_MESSAGE]: { + originalMessage?: never + }; + [CONST.REPORT.ACTIONS.TYPE.IOU]: { + originalMessage: OriginalMessageIOU; + }; + [CONST.REPORT.ACTIONS.TYPE.MANAGER_ATTACH_RECEIPT]: { + originalMessage?: never + }; + [CONST.REPORT.ACTIONS.TYPE.MANAGER_DETACH_RECEIPT]: { + originalMessage?: never + }; + [CONST.REPORT.ACTIONS.TYPE.MARK_REIMBURSED_FROM_INTEGRATION]: { + originalMessage?: never + }; + [CONST.REPORT.ACTIONS.TYPE.MARKED_REIMBURSED]: { + originalMessage?: never + }; + [CONST.REPORT.ACTIONS.TYPE.MERGED_WITH_CASH_TRANSACTION]: { + originalMessage?: never + }; + [CONST.REPORT.ACTIONS.TYPE.MODIFIED_EXPENSE]: { + originalMessage: OriginalMessageModifiedExpense; + }; + [CONST.REPORT.ACTIONS.TYPE.MOVED]: { + originalMessage: OriginalMessageMoved; + }; + [CONST.REPORT.ACTIONS.TYPE.OUTDATED_BANK_ACCOUNT]: { + originalMessage?: never + }; + [CONST.REPORT.ACTIONS.TYPE.REIMBURSEMENT_ACH_BOUNCE]: { + originalMessage?: never + }; + [CONST.REPORT.ACTIONS.TYPE.REIMBURSEMENT_ACH_CANCELLED]: { + originalMessage?: never + }; + [CONST.REPORT.ACTIONS.TYPE.REIMBURSEMENT_ACCOUNT_CHANGED]: { + originalMessage?: never + }; + [CONST.REPORT.ACTIONS.TYPE.REIMBURSEMENT_DEQUEUED]: { + originalMessage: OriginalMessageReimbursementDequeued; + }; + [CONST.REPORT.ACTIONS.TYPE.REIMBURSEMENT_DELAYED]: { + originalMessage?: never + }; + [CONST.REPORT.ACTIONS.TYPE.REIMBURSEMENT_QUEUED]: { + originalMessage: OriginalMessageReimbursementQueued + }; + [CONST.REPORT.ACTIONS.TYPE.REIMBURSEMENT_REQUESTED]: { + originalMessage?: never + }; + [CONST.REPORT.ACTIONS.TYPE.REIMBURSEMENT_SETUP]: { + originalMessage?: never + }; + [CONST.REPORT.ACTIONS.TYPE.RENAMED]: { + originalMessage: OriginalMessageRenamed; + }; + [CONST.REPORT.ACTIONS.TYPE.REPORT_PREVIEW]: { + originalMessage: OriginalMessageReportPreview + }; + [CONST.REPORT.ACTIONS.TYPE.SELECTED_FOR_RANDOM_AUDIT]: { + originalMessage?: never + }; + [CONST.REPORT.ACTIONS.TYPE.SHARE]: { + originalMessage?: never + }; + [CONST.REPORT.ACTIONS.TYPE.STRIPE_PAID]: { + originalMessage?: never + }; + [CONST.REPORT.ACTIONS.TYPE.SUBMITTED]: { + originalMessage?: never + }; + [CONST.REPORT.ACTIONS.TYPE.TASK_CANCELLED]: { + originalMessage?: never + }; + [CONST.REPORT.ACTIONS.TYPE.TASK_COMPLETED]: { + originalMessage?: never + }; + [CONST.REPORT.ACTIONS.TYPE.TASK_EDITED]: { + originalMessage?: never + }; + [CONST.REPORT.ACTIONS.TYPE.TASK_REOPENED]: { + originalMessage?: never + }; + [CONST.REPORT.ACTIONS.TYPE.TAKE_CONTROL]: { + originalMessage?: never + }; + [CONST.REPORT.ACTIONS.TYPE.UNAPPROVED]: { + originalMessage?: never + }; + [CONST.REPORT.ACTIONS.TYPE.UNHOLD]: { + originalMessage?: never + }; + [CONST.REPORT.ACTIONS.TYPE.UNSHARE]: { + originalMessage?: never + }; + [CONST.REPORT.ACTIONS.TYPE.UPDATE_GROUP_CHAT_MEMBER_ROLE]: { + originalMessage?: never + }; + [CONST.REPORT.ACTIONS.TYPE.REIMBURSEMENT_SETUP_REQUESTED]: { + originalMessage?: never + }; +} & { + [T in ValueOf]: { + originalMessage: OriginalMessageChangeLog + }; +} & { + [T in ValueOf]: { + originalMessage: OriginalMessageChangeLog; + }; +}; + type OriginalMessageMap = { [CONST.REPORT.ACTIONS.TYPE.ACTIONABLE_JOIN_REQUEST]: OriginalMessageJoinPolicyChangeLog; [CONST.REPORT.ACTIONS.TYPE.ACTIONABLE_MENTION_WHISPER]: OriginalMessageActionableMentionWhisper; @@ -281,6 +460,7 @@ type AssertOriginalMessageDefinedForAllActions = AssertTypesEqual< >; type OriginalMessage = OriginalMessageMap[T]; +type OriginalMessageTemporary = OriginalMessageMap1[T]; // Note: type-fest's ConditionalKeys does not work correctly with objects containing `never`: https://github.com/sindresorhus/type-fest/issues/878 type ReportActionNamesWithHTMLMessage = { @@ -297,4 +477,4 @@ type AssertAllActionsWithHTMLAreListed = AssertTypesEqual< export default OriginalMessage; export {REPORT_ACTIONS_WITH_HTML_MESSAGE}; -export type {ChronosOOOEvent, PaymentMethodType, OriginalMessageSource, ReportActionNamesWithHTMLMessage, Reaction, Decision, OriginalMessageChangeLog}; +export type {ChronosOOOEvent, PaymentMethodType, OriginalMessageSource, ReportActionNamesWithHTMLMessage, Reaction, Decision, OriginalMessageChangeLog, OriginalMessageTemporary}; diff --git a/src/types/onyx/ReportAction.ts b/src/types/onyx/ReportAction.ts index 634788503cfe..c5526828c765 100644 --- a/src/types/onyx/ReportAction.ts +++ b/src/types/onyx/ReportAction.ts @@ -7,7 +7,7 @@ import type CollectionDataSet from '@src/types/utils/CollectionDataSet'; import type {EmptyObject} from '@src/types/utils/EmptyObject'; import type * as OnyxCommon from './OnyxCommon'; import type OriginalMessage from './OriginalMessage'; -import type {Decision, Reaction, ReportActionNamesWithHTMLMessage} from './OriginalMessage'; +import type {Decision, OriginalMessageTemporary, Reaction, ReportActionNamesWithHTMLMessage} from './OriginalMessage'; import type {NotificationPreference} from './Report'; import type ReportActionName from './ReportActionName'; import type {Receipt} from './Transaction'; @@ -226,9 +226,7 @@ type ReportActionBase = OnyxCommon.OnyxValueWithOfflineFeedback<{ adminAccountID?: number; }>; -type ReportAction = ReportActionBase & { - originalMessage: OriginalMessage; - +type ReportAction = ReportActionBase & OriginalMessageTemporary &{ /** report action message */ message?: OriginalMessage & Message | Array; From 8fb20ac954e5f8d5b6ba0fa44ff77dc3ede96c5d Mon Sep 17 00:00:00 2001 From: nkdengineer Date: Tue, 4 Jun 2024 19:25:32 +0700 Subject: [PATCH 20/45] complete type check --- src/components/AttachmentModal.tsx | 6 +- .../LHNOptionsList/LHNOptionsList.tsx | 12 +- src/components/MoneyReportHeader.tsx | 20 +- src/components/MoneyRequestHeader.tsx | 15 +- .../ChronosOOOListActions.tsx | 4 +- .../MoneyRequestPreviewContent.tsx | 9 +- .../MoneyRequestPreview/index.tsx | 3 +- .../ReportActionItem/MoneyRequestView.tsx | 5 +- .../ReportActionItem/RenameAction.tsx | 3 +- src/hooks/useReportIDs.tsx | 4 +- src/libs/ModifiedExpenseMessage.ts | 1 - .../LocalNotification/BrowserNotifications.ts | 7 +- src/libs/OptionsListUtils.ts | 9 +- src/libs/ReportActionsUtils.ts | 116 +++++----- src/libs/ReportUtils.ts | 76 ++++--- src/libs/actions/IOU.ts | 60 ++++-- src/libs/actions/Policy/Policy.ts | 4 +- src/libs/actions/Report.ts | 15 +- src/libs/actions/User.ts | 5 +- .../report/ContextMenu/ContextMenuActions.tsx | 4 +- .../ComposerWithSuggestions.tsx | 3 +- src/pages/home/report/ReportActionItem.tsx | 59 +++-- .../home/report/ReportActionItemFragment.tsx | 7 +- .../home/report/ReportActionItemMessage.tsx | 9 +- src/pages/home/report/ReportActionsView.tsx | 11 +- src/pages/iou/SplitBillDetailsPage.tsx | 3 +- src/types/onyx/OriginalMessage.ts | 107 ++++----- src/types/onyx/ReportAction.ts | 12 +- src/types/onyx/ReportActionName.ts | 2 +- src/types/onyx/index.ts | 3 +- tests/actions/IOUTest.ts | 204 +++++++++++------- tests/actions/PolicyMemberTest.ts | 11 +- tests/unit/ReportUtilsTest.ts | 3 +- tests/utils/LHNTestUtils.tsx | 16 +- tests/utils/ReportTestUtils.ts | 10 +- tests/utils/collections/reportActions.ts | 10 +- 36 files changed, 472 insertions(+), 376 deletions(-) diff --git a/src/components/AttachmentModal.tsx b/src/components/AttachmentModal.tsx index f9310d24c2f3..f1d5f44620dc 100644 --- a/src/components/AttachmentModal.tsx +++ b/src/components/AttachmentModal.tsx @@ -27,7 +27,6 @@ import type {TranslationPaths} from '@src/languages/types'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import type * as OnyxTypes from '@src/types/onyx'; -import type {IOUMessage} from '@src/types/onyx/OriginalMessage'; import type {EmptyObject} from '@src/types/utils/EmptyObject'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; import type ModalType from '@src/types/utils/ModalType'; @@ -618,10 +617,7 @@ export default withOnyx({ transaction: { key: ({report}) => { const parentReportAction = ReportActionsUtils.getReportAction(report?.parentReportID ?? '', report?.parentReportActionID ?? ''); - const transactionID = - parentReportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.IOU - ? ReportActionsUtils.getOriginalMessage(parentReportAction).IOUTransactionID ?? '0' - : '0'; + const transactionID = ReportActionsUtils.isMoneyRequestAction(parentReportAction) ? ReportActionsUtils.getOriginalMessage(parentReportAction)?.IOUTransactionID ?? '0' : '0'; return `${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`; }, initWithStoredValues: false, diff --git a/src/components/LHNOptionsList/LHNOptionsList.tsx b/src/components/LHNOptionsList/LHNOptionsList.tsx index e8cee57f463a..3b4340c09338 100644 --- a/src/components/LHNOptionsList/LHNOptionsList.tsx +++ b/src/components/LHNOptionsList/LHNOptionsList.tsx @@ -22,7 +22,6 @@ import * as ReportActionsUtils from '@libs/ReportActionsUtils'; import variables from '@styles/variables'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; -import type {IOUMessage} from '@src/types/onyx/OriginalMessage'; import OptionRowLHNData from './OptionRowLHNData'; import type {LHNOptionsListOnyxProps, LHNOptionsListProps, RenderItemProps} from './types'; @@ -112,10 +111,9 @@ function LHNOptionsList({ const itemParentReportActions = reportActions?.[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${itemFullReport?.parentReportID}`] ?? null; const itemParentReportAction = itemParentReportActions?.[itemFullReport?.parentReportActionID ?? ''] ?? null; const itemPolicy = policy?.[`${ONYXKEYS.COLLECTION.POLICY}${itemFullReport?.policyID}`] ?? null; - const transactionID = - itemParentReportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.IOU - ? ReportActionsUtils.getOriginalMessage(itemParentReportAction).IOUTransactionID ?? '' - : ''; + const transactionID = ReportActionsUtils.isMoneyRequestAction(itemParentReportAction) + ? ReportActionsUtils.getOriginalMessage(itemParentReportAction)?.IOUTransactionID ?? '' + : ''; const itemTransaction = transactions?.[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`] ?? null; const hasDraftComment = DraftCommentUtils.isValidDraftComment(draftComments?.[`${ONYXKEYS.COLLECTION.REPORT_DRAFT_COMMENT}${reportID}`]); const sortedReportActions = ReportActionsUtils.getSortedReportActionsForDisplay(itemReportActions); @@ -124,8 +122,8 @@ function LHNOptionsList({ // Get the transaction for the last report action let lastReportActionTransactionID = ''; - if (lastReportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.IOU) { - lastReportActionTransactionID = ReportActionsUtils.getOriginalMessage(lastReportAction)?.IOUTransactionID ?? ''; + if (ReportActionsUtils.isMoneyRequestAction(lastReportAction)) { + lastReportActionTransactionID = ReportActionsUtils.getOriginalMessage(lastReportAction)?.IOUTransactionID ?? ''; } const lastReportActionTransaction = transactions?.[`${ONYXKEYS.COLLECTION.TRANSACTION}${lastReportActionTransactionID}`] ?? {}; diff --git a/src/components/MoneyReportHeader.tsx b/src/components/MoneyReportHeader.tsx index 95c65d682f6b..bb3c2e19420b 100644 --- a/src/components/MoneyReportHeader.tsx +++ b/src/components/MoneyReportHeader.tsx @@ -18,7 +18,7 @@ import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import type * as OnyxTypes from '@src/types/onyx'; -import type {IOUMessage, PaymentMethodType} from '@src/types/onyx/OriginalMessage'; +import type {PaymentMethodType} from '@src/types/onyx/OriginalMessage'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; import Button from './Button'; import ConfirmModal from './ConfirmModal'; @@ -68,9 +68,9 @@ function MoneyReportHeader({policy, report: moneyRequestReport, transactionThrea if (!reportActions || !transactionThreadReport?.parentReportActionID) { return null; } - return reportActions.find((action) => action.reportActionID === transactionThreadReport.parentReportActionID); + return reportActions.find((action) => action.reportActionID === transactionThreadReport.parentReportActionID) ?? null; }, [reportActions, transactionThreadReport?.parentReportActionID]); - const isDeletedParentAction = ReportActionsUtils.isDeletedAction(requestParentReportAction as OnyxTypes.ReportAction); + const isDeletedParentAction = ReportActionsUtils.isDeletedAction(requestParentReportAction); // Only the requestor can delete the request, admins can only edit it. const isActionOwner = @@ -143,10 +143,9 @@ function MoneyReportHeader({policy, report: moneyRequestReport, transactionThrea const deleteTransaction = useCallback(() => { if (requestParentReportAction) { - const iouTransactionID = - requestParentReportAction.actionName === CONST.REPORT.ACTIONS.TYPE.IOU - ? ReportActionsUtils.getOriginalMessage(requestParentReportAction)?.IOUTransactionID ?? '' - : ''; + const iouTransactionID = ReportActionsUtils.isMoneyRequestAction(requestParentReportAction) + ? ReportActionsUtils.getOriginalMessage(requestParentReportAction)?.IOUTransactionID ?? '' + : ''; if (ReportActionsUtils.isTrackExpenseAction(requestParentReportAction)) { IOU.deleteTrackExpense(moneyRequestReport?.reportID ?? '', iouTransactionID, requestParentReportAction, true); return; @@ -161,10 +160,9 @@ function MoneyReportHeader({policy, report: moneyRequestReport, transactionThrea if (!requestParentReportAction) { return; } - const iouTransactionID = - requestParentReportAction.actionName === CONST.REPORT.ACTIONS.TYPE.IOU - ? ReportActionsUtils.getOriginalMessage(requestParentReportAction)?.IOUTransactionID ?? '' - : ''; + const iouTransactionID = ReportActionsUtils.isMoneyRequestAction(requestParentReportAction) + ? ReportActionsUtils.getOriginalMessage(requestParentReportAction)?.IOUTransactionID ?? '' + : ''; const reportID = transactionThreadReport?.reportID ?? ''; TransactionActions.markAsCash(iouTransactionID, reportID); diff --git a/src/components/MoneyRequestHeader.tsx b/src/components/MoneyRequestHeader.tsx index ff64661fa7ed..10748aa20ce0 100644 --- a/src/components/MoneyRequestHeader.tsx +++ b/src/components/MoneyRequestHeader.tsx @@ -19,7 +19,6 @@ import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import type {Policy, Report, ReportAction} from '@src/types/onyx'; -import type {IOUMessage} from '@src/types/onyx/OriginalMessage'; import type IconAsset from '@src/types/utils/IconAsset'; import Button from './Button'; import ConfirmModal from './ConfirmModal'; @@ -49,7 +48,11 @@ type MoneyRequestHeaderProps = { function MoneyRequestHeader({report, parentReportAction, policy, shouldUseNarrowLayout = false, onBackButtonPress}: MoneyRequestHeaderProps) { const [parentReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${report.parentReportID}`); - const [transaction] = useOnyx(`${ONYXKEYS.COLLECTION.TRANSACTION}${ReportActionsUtils.getOriginalMessage(parentReportAction)?.IOUTransactionID ?? 0}`); + const [transaction] = useOnyx( + `${ONYXKEYS.COLLECTION.TRANSACTION}${ + ReportActionsUtils.isMoneyRequestAction(parentReportAction) ? ReportActionsUtils.getOriginalMessage(parentReportAction)?.IOUTransactionID ?? 0 : 0 + }`, + ); const [transactionViolations] = useOnyx(ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS); const [session] = useOnyx(ONYXKEYS.SESSION); const [shownHoldUseExplanation] = useOnyx(ONYXKEYS.NVP_HOLD_USE_EXPLAINED, {initWithStoredValues: false}); @@ -75,10 +78,7 @@ function MoneyRequestHeader({report, parentReportAction, policy, shouldUseNarrow const deleteTransaction = useCallback(() => { if (parentReportAction) { - const iouTransactionID = - parentReportAction.actionName === CONST.REPORT.ACTIONS.TYPE.IOU - ? ReportActionsUtils.getOriginalMessage(parentReportAction)?.IOUTransactionID ?? '' - : ''; + const iouTransactionID = ReportActionsUtils.isMoneyRequestAction(parentReportAction) ? ReportActionsUtils.getOriginalMessage(parentReportAction)?.IOUTransactionID ?? '' : ''; if (ReportActionsUtils.isTrackExpenseAction(parentReportAction)) { IOU.deleteTrackExpense(parentReport?.reportID ?? '', iouTransactionID, parentReportAction, true); return; @@ -102,8 +102,7 @@ function MoneyRequestHeader({report, parentReportAction, policy, shouldUseNarrow const canDeleteRequest = isActionOwner && (ReportUtils.canAddOrDeleteTransactions(moneyRequestReport) || ReportUtils.isTrackExpenseReport(report)) && !isDeletedParentAction; const changeMoneyRequestStatus = () => { - const iouTransactionID = - parentReportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.IOU ? ReportActionsUtils.getOriginalMessage(parentReportAction)?.IOUTransactionID ?? '' : ''; + const iouTransactionID = ReportActionsUtils.isMoneyRequestAction(parentReportAction) ? ReportActionsUtils.getOriginalMessage(parentReportAction)?.IOUTransactionID ?? '' : ''; if (isOnHold) { IOU.unholdRequest(iouTransactionID, report?.reportID); diff --git a/src/components/ReportActionItem/ChronosOOOListActions.tsx b/src/components/ReportActionItem/ChronosOOOListActions.tsx index 26ddaf360b9d..460104a71d68 100644 --- a/src/components/ReportActionItem/ChronosOOOListActions.tsx +++ b/src/components/ReportActionItem/ChronosOOOListActions.tsx @@ -8,8 +8,8 @@ import useThemeStyles from '@hooks/useThemeStyles'; import DateUtils from '@libs/DateUtils'; import * as ReportActionsUtils from '@libs/ReportActionsUtils'; import * as Chronos from '@userActions/Chronos'; -import ReportAction from '@src/types/onyx/ReportAction'; -import CONST from '@src/CONST'; +import type CONST from '@src/CONST'; +import type ReportAction from '@src/types/onyx/ReportAction'; type ChronosOOOListActionsProps = { /** The ID of the report */ diff --git a/src/components/ReportActionItem/MoneyRequestPreview/MoneyRequestPreviewContent.tsx b/src/components/ReportActionItem/MoneyRequestPreview/MoneyRequestPreviewContent.tsx index 190abe61bc0d..949c007d6f3b 100644 --- a/src/components/ReportActionItem/MoneyRequestPreview/MoneyRequestPreviewContent.tsx +++ b/src/components/ReportActionItem/MoneyRequestPreview/MoneyRequestPreviewContent.tsx @@ -36,7 +36,7 @@ import variables from '@styles/variables'; import * as PaymentMethods from '@userActions/PaymentMethods'; import * as Report from '@userActions/Report'; import CONST from '@src/CONST'; -import type {IOUMessage} from '@src/types/onyx/OriginalMessage'; +import type {OriginalMessageIOU} from '@src/types/onyx/OriginalMessage'; import type {EmptyObject} from '@src/types/utils/EmptyObject'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; import type {MoneyRequestPreviewProps, PendingMessageProps} from './types'; @@ -75,9 +75,7 @@ function MoneyRequestPreviewContent({ const {canUseViolations} = usePermissions(); const participantAccountIDs = - action.actionName === CONST.REPORT.ACTIONS.TYPE.IOU && isBillSplit - ? ReportActionsUtils.getOriginalMessage(action).participantAccountIDs ?? [] - : [managerID, ownerAccountID]; + ReportActionsUtils.isMoneyRequestAction(action) && isBillSplit ? ReportActionsUtils.getOriginalMessage(action)?.participantAccountIDs ?? [] : [managerID, ownerAccountID]; const participantAvatars = OptionsListUtils.getAvatarsForAccountIDs(participantAccountIDs, personalDetails ?? {}); const sortedParticipantAvatars = lodashSortBy(participantAvatars, (avatar) => avatar.id); if (isPolicyExpenseChat && isBillSplit) { @@ -221,8 +219,7 @@ function MoneyRequestPreviewContent({ }; const getDisplayDeleteAmountText = (): string => { - const iouOriginalMessage: IOUMessage | EmptyObject = - action?.actionName === CONST.REPORT.ACTIONS.TYPE.IOU ? ReportActionsUtils.getOriginalMessage(action) : {}; + const iouOriginalMessage: OriginalMessageIOU | EmptyObject = ReportActionsUtils.isMoneyRequestAction(action) ? ReportActionsUtils.getOriginalMessage(action) ?? {} : {}; const {amount = 0, currency = CONST.CURRENCY.USD} = iouOriginalMessage; return CurrencyUtils.convertToDisplayString(amount, currency); diff --git a/src/components/ReportActionItem/MoneyRequestPreview/index.tsx b/src/components/ReportActionItem/MoneyRequestPreview/index.tsx index 3733cd553de3..c01206f83f55 100644 --- a/src/components/ReportActionItem/MoneyRequestPreview/index.tsx +++ b/src/components/ReportActionItem/MoneyRequestPreview/index.tsx @@ -3,7 +3,6 @@ import React from 'react'; import {withOnyx} from 'react-native-onyx'; import * as ReportActionsUtils from '@libs/ReportActionsUtils'; import ONYXKEYS from '@src/ONYXKEYS'; -import type {IOUMessage} from '@src/types/onyx/OriginalMessage'; import MoneyRequestPreviewContent from './MoneyRequestPreviewContent'; import type {MoneyRequestPreviewOnyxProps, MoneyRequestPreviewProps} from './types'; @@ -32,7 +31,7 @@ export default withOnyx( transaction: { key: ({action}) => { const isMoneyRequestAction = ReportActionsUtils.isMoneyRequestAction(action); - const transactionID = isMoneyRequestAction ? ReportActionsUtils.getOriginalMessage(action)?.IOUTransactionID : 0; + const transactionID = isMoneyRequestAction ? ReportActionsUtils.getOriginalMessage(action)?.IOUTransactionID : 0; return `${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`; }, }, diff --git a/src/components/ReportActionItem/MoneyRequestView.tsx b/src/components/ReportActionItem/MoneyRequestView.tsx index 1c50a474237c..6e0da7e3cfe1 100644 --- a/src/components/ReportActionItem/MoneyRequestView.tsx +++ b/src/components/ReportActionItem/MoneyRequestView.tsx @@ -41,7 +41,6 @@ import * as ReportActions from '@src/libs/actions/ReportActions'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import type * as OnyxTypes from '@src/types/onyx'; -import type {IOUMessage} from '@src/types/onyx/OriginalMessage'; import type {TransactionPendingFieldsKey} from '@src/types/onyx/Transaction'; import ReportActionItemImage from './ReportActionItemImage'; @@ -605,7 +604,7 @@ export default withOnyx { const parentReportAction = parentReportActions?.[report.parentReportActionID ?? '']; const originalMessage = - parentReportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.IOU ? ReportActionsUtils.getOriginalMessage(parentReportAction) : undefined; + parentReportAction && ReportActionsUtils.isMoneyRequestAction(parentReportAction) ? ReportActionsUtils.getOriginalMessage(parentReportAction) : undefined; const transactionID = originalMessage?.IOUTransactionID ?? 0; return `${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`; }, @@ -614,7 +613,7 @@ export default withOnyx { const parentReportAction = parentReportActions?.[report.parentReportActionID ?? '']; const originalMessage = - parentReportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.IOU ? ReportActionsUtils.getOriginalMessage(parentReportAction) : undefined; + parentReportAction && ReportActionsUtils.isMoneyRequestAction(parentReportAction) ? ReportActionsUtils.getOriginalMessage(parentReportAction) : undefined; const transactionID = originalMessage?.IOUTransactionID ?? 0; return `${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transactionID}`; }, diff --git a/src/components/ReportActionItem/RenameAction.tsx b/src/components/ReportActionItem/RenameAction.tsx index 37ee2f46c368..0113b9e5da16 100644 --- a/src/components/ReportActionItem/RenameAction.tsx +++ b/src/components/ReportActionItem/RenameAction.tsx @@ -20,8 +20,7 @@ function RenameAction({currentUserPersonalDetails, action}: RenameActionProps) { const userDisplayName = action.person?.[0]?.text; const actorAccountID = action.actorAccountID ?? ''; const displayName = actorAccountID === currentUserAccountID ? `${translate('common.you')}` : `${userDisplayName}`; - const originalMessage = - ReportActionsUtils.isRenamedAction(action) ? ReportActionsUtils.getOriginalMessage(action) : null; + const originalMessage = ReportActionsUtils.isRenamedAction(action) ? ReportActionsUtils.getOriginalMessage(action) : null; const oldName = originalMessage?.oldName ?? ''; const newName = originalMessage?.newName ?? ''; diff --git a/src/hooks/useReportIDs.tsx b/src/hooks/useReportIDs.tsx index 46ffa7d999ee..55a6424f2372 100644 --- a/src/hooks/useReportIDs.tsx +++ b/src/hooks/useReportIDs.tsx @@ -2,6 +2,7 @@ import React, {createContext, useCallback, useContext, useMemo} from 'react'; import type {OnyxEntry} from 'react-native-onyx'; import {useOnyx} from 'react-native-onyx'; import {getPolicyEmployeeListByIdWithoutCurrentUser} from '@libs/PolicyUtils'; +import * as ReportActionsUtils from '@libs/ReportActionsUtils'; import * as ReportUtils from '@libs/ReportUtils'; import SidebarUtils from '@libs/SidebarUtils'; import CONST from '@src/CONST'; @@ -78,7 +79,8 @@ const reportActionsSelector = (reportActions: OnyxEntry (reportActions && Object.values(reportActions).map((reportAction) => { const {reportActionID, actionName, errors = [], originalMessage} = reportAction; - const decision = reportAction.message?.[0]?.moderationDecision?.decision; + const message = ReportActionsUtils.getReportActionMessage(reportAction); + const decision = message?.moderationDecision?.decision; return { reportActionID, diff --git a/src/libs/ModifiedExpenseMessage.ts b/src/libs/ModifiedExpenseMessage.ts index 6e8e4c138995..677eb875cf66 100644 --- a/src/libs/ModifiedExpenseMessage.ts +++ b/src/libs/ModifiedExpenseMessage.ts @@ -9,7 +9,6 @@ import getReportPolicyID from './getReportPolicyID'; import * as Localize from './Localize'; import * as PolicyUtils from './PolicyUtils'; import * as ReportActionsUtils from './ReportActionsUtils'; -import type {ExpenseOriginalMessage} from './ReportUtils'; import * as TransactionUtils from './TransactionUtils'; let allPolicyTags: OnyxCollection = {}; diff --git a/src/libs/Notification/LocalNotification/BrowserNotifications.ts b/src/libs/Notification/LocalNotification/BrowserNotifications.ts index 18fd8256a5ec..90f73217885d 100644 --- a/src/libs/Notification/LocalNotification/BrowserNotifications.ts +++ b/src/libs/Notification/LocalNotification/BrowserNotifications.ts @@ -101,7 +101,12 @@ export default { const plainTextPerson = person?.map((f) => f.text).join() ?? ''; // Specifically target the comment part of the message - const plainTextMessage = message?.find((f) => f?.type === 'COMMENT')?.text ?? ''; + let plainTextMessage = ''; + if (Array.isArray(message)) { + plainTextMessage = message?.find((f) => f?.type === 'COMMENT')?.text ?? ''; + } else { + plainTextMessage = message?.type === 'COMMENT' ? message?.text ?? '' : ''; + } if (isChatRoom) { const roomName = ReportUtils.getReportName(report); diff --git a/src/libs/OptionsListUtils.ts b/src/libs/OptionsListUtils.ts index ca7a43d2291b..ad6fed305973 100644 --- a/src/libs/OptionsListUtils.ts +++ b/src/libs/OptionsListUtils.ts @@ -33,7 +33,6 @@ import type { } from '@src/types/onyx'; import type {Participant} from '@src/types/onyx/IOU'; import type * as OnyxCommon from '@src/types/onyx/OnyxCommon'; -import type {Closed, IOUMessage} from '@src/types/onyx/OriginalMessage'; import type DeepValueOf from '@src/types/utils/DeepValueOf'; import type {EmptyObject} from '@src/types/utils/EmptyObject'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; @@ -533,7 +532,7 @@ function getAllReportErrors(report: OnyxEntry, reportActions: OnyxEntry< !report?.parentReportID || !report?.parentReportActionID ? null : allReportActions?.[report.parentReportID ?? '']?.[report.parentReportActionID ?? ''] ?? null; if (ReportActionUtils.wasActionTakenByCurrentUser(parentReportAction) && ReportActionUtils.isTransactionThread(parentReportAction)) { - const transactionID = parentReportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.IOU ? parentReportAction?.originalMessage?.IOUTransactionID : null; + const transactionID = ReportActionUtils.isMoneyRequestAction(parentReportAction) ? ReportActionUtils.getOriginalMessage(parentReportAction)?.IOUTransactionID : null; const transaction = allTransactions?.[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`]; if (TransactionUtils.hasMissingSmartscanFields(transaction ?? null) && !ReportUtils.isSettled(transaction?.reportID)) { reportActionErrors.smartscan = ErrorUtils.getMicroSecondOnyxError('report.genericSmartscanFailureMessage'); @@ -614,8 +613,8 @@ function getLastMessageTextForReport(report: OnyxEntry, lastActorDetails if (ReportUtils.isArchivedRoom(report)) { const archiveReason = - (ReportActionUtils.isClosedAction(lastOriginalReportAction) && ReportActionUtils.getOriginalMessage(lastOriginalReportAction)?.reason) || - CONST.REPORT.ARCHIVE_REASON.DEFAULT; + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing + (ReportActionUtils.isClosedAction(lastOriginalReportAction) && ReportActionUtils.getOriginalMessage(lastOriginalReportAction)?.reason) || CONST.REPORT.ARCHIVE_REASON.DEFAULT; switch (archiveReason) { case CONST.REPORT.ARCHIVE_REASON.ACCOUNT_CLOSED: case CONST.REPORT.ARCHIVE_REASON.REMOVED_FROM_POLICY: @@ -636,7 +635,7 @@ function getLastMessageTextForReport(report: OnyxEntry, lastActorDetails } else if (ReportActionUtils.isReportPreviewAction(lastReportAction)) { const iouReport = ReportUtils.getReport(ReportActionUtils.getIOUReportIDFromReportActionPreview(lastReportAction)); const lastIOUMoneyReportAction = allSortedReportActions[iouReport?.reportID ?? '']?.find( - (reportAction, key) => + (reportAction, key): reportAction is ReportAction => ReportActionUtils.shouldReportActionBeVisible(reportAction, key) && reportAction.pendingAction !== CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE && ReportActionUtils.isMoneyRequestAction(reportAction), diff --git a/src/libs/ReportActionsUtils.ts b/src/libs/ReportActionsUtils.ts index e7ec5cd6473f..2e67356530e0 100644 --- a/src/libs/ReportActionsUtils.ts +++ b/src/libs/ReportActionsUtils.ts @@ -11,6 +11,7 @@ import ONYXKEYS from '@src/ONYXKEYS'; import type Report from '@src/types/onyx/Report'; import type {Message, OriginalMessage, ReportActions} from '@src/types/onyx/ReportAction'; import type ReportAction from '@src/types/onyx/ReportAction'; +import type ReportActionName from '@src/types/onyx/ReportActionName'; import type {EmptyObject} from '@src/types/utils/EmptyObject'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; import DateUtils from './DateUtils'; @@ -23,7 +24,6 @@ import * as PersonalDetailsUtils from './PersonalDetailsUtils'; import type {OptimisticIOUReportAction, PartialReportAction} from './ReportUtils'; import StringUtils from './StringUtils'; import * as TransactionUtils from './TransactionUtils'; -import ReportActionName from '@src/types/onyx/ReportActionName'; type LastVisibleMessage = { lastMessageTranslationKey?: string; @@ -44,8 +44,6 @@ type MemberChangeMessageRoomReferenceElement = { type MemberChangeMessageElement = MessageTextElement | MemberChangeMessageUserMentionElement | MemberChangeMessageRoomReferenceElement; -const policyChangeActionsSet = new Set(Object.values(CONST.REPORT.ACTIONS.TYPE.POLICY_CHANGE_LOG)); - let allReports: OnyxCollection = {}; Onyx.connect({ key: ONYXKEYS.COLLECTION.REPORT, @@ -157,17 +155,16 @@ function isAddCommentAction(reportAction: OnyxEntry): reportAction return isActionOfType(reportAction, CONST.REPORT.ACTIONS.TYPE.ADD_COMMENT); } -function getReportActionOriginalMessage(reportAction: PartialReportAction) { - return (reportAction?.originalMessage ?? reportAction?.message?.[0] ?? reportAction?.message) as T; -} - -function isActionOfType(action: OnyxEntry, ...actionNames: T): action is ({ - [K in keyof T]: ReportAction -}[number]) { +function isActionOfType( + action: OnyxEntry, + ...actionNames: T +): action is { + [K in keyof T]: ReportAction; +}[number] { return actionNames.includes(action?.actionName as T[number]); } -function getOriginalMessage(reportAction: ReportAction): OriginalMessage { +function getOriginalMessage(reportAction: ReportAction): OriginalMessage | undefined { if (!Array.isArray(reportAction?.message)) { return reportAction?.message ?? reportAction?.originalMessage; } @@ -192,16 +189,16 @@ function getWhisperedTo(reportAction: OnyxEntry): number[] { const originalMessage = getOriginalMessage(reportAction); const message = reportAction?.message; - if (! ('whisperedTo' in originalMessage) && ! (!!message && 'whisperedTo' in message)) { - return [] + if (!(originalMessage && 'whisperedTo' in originalMessage) && !(message && 'whisperedTo' in message)) { + return []; } if (!Array.isArray(message) && typeof message === 'object' && 'whisperedTo' in message) { - return (message)?.whisperedTo ?? []; + return message?.whisperedTo ?? []; } if (originalMessage && 'whisperedTo' in originalMessage) { - return (originalMessage)?.whisperedTo ?? []; + return originalMessage?.whisperedTo ?? []; } return []; @@ -226,14 +223,25 @@ function isReimbursementQueuedAction(reportAction: OnyxEntry): rep } function isMemberChangeAction(reportAction: OnyxEntry) { - return isActionOfType(reportAction, CONST.REPORT.ACTIONS.TYPE.ROOM_CHANGE_LOG.INVITE_TO_ROOM, CONST.REPORT.ACTIONS.TYPE.ROOM_CHANGE_LOG.REMOVE_FROM_ROOM, CONST.REPORT.ACTIONS.TYPE.POLICY_CHANGE_LOG.INVITE_TO_ROOM, CONST.REPORT.ACTIONS.TYPE.POLICY_CHANGE_LOG.REMOVE_FROM_ROOM, CONST.REPORT.ACTIONS.TYPE.POLICY_CHANGE_LOG.LEAVE_POLICY); + return isActionOfType( + reportAction, + CONST.REPORT.ACTIONS.TYPE.ROOM_CHANGE_LOG.INVITE_TO_ROOM, + CONST.REPORT.ACTIONS.TYPE.ROOM_CHANGE_LOG.REMOVE_FROM_ROOM, + CONST.REPORT.ACTIONS.TYPE.POLICY_CHANGE_LOG.INVITE_TO_ROOM, + CONST.REPORT.ACTIONS.TYPE.POLICY_CHANGE_LOG.REMOVE_FROM_ROOM, + CONST.REPORT.ACTIONS.TYPE.POLICY_CHANGE_LOG.LEAVE_POLICY, + ); } -function isInviteMemberAction(reportAction: OnyxEntry): reportAction is ReportAction { +function isInviteMemberAction( + reportAction: OnyxEntry, +): reportAction is ReportAction { return isActionOfType(reportAction, CONST.REPORT.ACTIONS.TYPE.ROOM_CHANGE_LOG.INVITE_TO_ROOM, CONST.REPORT.ACTIONS.TYPE.POLICY_CHANGE_LOG.INVITE_TO_ROOM); } -function isLeavePolicyAction(reportAction: OnyxEntry): reportAction is ReportAction { +function isLeavePolicyAction( + reportAction: OnyxEntry, +): reportAction is ReportAction { return isActionOfType(reportAction, CONST.REPORT.ACTIONS.TYPE.POLICY_CHANGE_LOG.LEAVE_POLICY); } @@ -277,7 +285,11 @@ function getParentReportAction(report: OnyxEntry | EmptyObject): ReportA * Determines if the given report action is sent money report action by checking for 'pay' type and presence of IOUDetails object. */ function isSentMoneyReportAction(reportAction: OnyxEntry): boolean { - return isActionOfType(reportAction, CONST.REPORT.ACTIONS.TYPE.IOU) && getOriginalMessage(reportAction)?.type === CONST.IOU.REPORT_ACTION_TYPE.PAY && !!getOriginalMessage(reportAction)?.IOUDetails; + return ( + isActionOfType(reportAction, CONST.REPORT.ACTIONS.TYPE.IOU) && + getOriginalMessage(reportAction)?.type === CONST.IOU.REPORT_ACTION_TYPE.PAY && + !!getOriginalMessage(reportAction)?.IOUDetails + ); } /** @@ -288,11 +300,11 @@ function isTransactionThread(parentReportAction: OnyxEntry | Empty if (isEmptyObject(parentReportAction) || !isMoneyRequestAction(parentReportAction)) { return false; } - const originalMessage = getOriginalMessage(parentReportAction); + const originalMessage = getOriginalMessage(parentReportAction); return ( - (originalMessage?.type === CONST.IOU.REPORT_ACTION_TYPE.CREATE || - originalMessage?.type === CONST.IOU.REPORT_ACTION_TYPE.TRACK || - (originalMessage?.type === CONST.IOU.REPORT_ACTION_TYPE.PAY && !!originalMessage?.IOUDetails)) + originalMessage?.type === CONST.IOU.REPORT_ACTION_TYPE.CREATE || + originalMessage?.type === CONST.IOU.REPORT_ACTION_TYPE.TRACK || + (originalMessage?.type === CONST.IOU.REPORT_ACTION_TYPE.PAY && !!originalMessage?.IOUDetails) ); } @@ -442,7 +454,16 @@ function getMostRecentIOURequestActionID(reportActions: ReportAction[] | null): CONST.IOU.REPORT_ACTION_TYPE.TRACK, ]; const iouRequestActions = - reportActions?.filter((action) => isActionOfType(action, CONST.REPORT.ACTIONS.TYPE.IOU) && iouRequestTypes.includes(getOriginalMessage(action).type)) ?? []; + reportActions?.filter((action) => { + if (!isActionOfType(action, CONST.REPORT.ACTIONS.TYPE.IOU)) { + return false; + } + const actionType = getOriginalMessage(action)?.type; + if (!actionType) { + return false; + } + return iouRequestTypes.includes(actionType); + }) ?? []; if (iouRequestActions.length === 0) { return null; @@ -869,10 +890,7 @@ function getMostRecentReportActionLastModified(): string { function getReportPreviewAction(chatReportID: string, iouReportID: string): OnyxEntry { return ( Object.values(allReportActions?.[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chatReportID}`] ?? {}).find( - (reportAction) => - reportAction && - isActionOfType(reportAction, CONST.REPORT.ACTIONS.TYPE.REPORT_PREVIEW) && - getOriginalMessage(reportAction)?.linkedReportID === iouReportID, + (reportAction) => reportAction && isActionOfType(reportAction, CONST.REPORT.ACTIONS.TYPE.REPORT_PREVIEW) && getOriginalMessage(reportAction)?.linkedReportID === iouReportID, ) ?? null ); } @@ -881,9 +899,7 @@ function getReportPreviewAction(chatReportID: string, iouReportID: string): Onyx * Get the iouReportID for a given report action. */ function getIOUReportIDFromReportActionPreview(reportAction: OnyxEntry): string { - return isActionOfType(reportAction, CONST.REPORT.ACTIONS.TYPE.REPORT_PREVIEW) - ? getOriginalMessage(reportAction)?.linkedReportID ?? '0' - : '0'; + return isActionOfType(reportAction, CONST.REPORT.ACTIONS.TYPE.REPORT_PREVIEW) ? getOriginalMessage(reportAction)?.linkedReportID ?? '0' : '0'; } function isCreatedTaskReportAction(reportAction: OnyxEntry): boolean { @@ -957,20 +973,26 @@ function getOneTransactionThreadReportID( CONST.IOU.REPORT_ACTION_TYPE.TRACK, ]; - const iouRequestActions = reportActionsArray.filter( - (action) => - isMoneyRequestAction(action) && - (iouRequestTypes.includes(getOriginalMessage(action).type) ?? []) && + const iouRequestActions = reportActionsArray.filter((action) => { + if (!isMoneyRequestAction(action)) { + return false; + } + const originalMessage = getOriginalMessage(action); + const actionType = originalMessage?.type; + return ( + actionType && + (iouRequestTypes.includes(actionType) ?? []) && action.childReportID && // Include deleted IOU reportActions if: // - they have an assocaited IOU transaction ID or // - they have visibile childActions (like comments) that we'd want to display // - the action is pending deletion and the user is offline - (Boolean(getOriginalMessage(action).IOUTransactionID) || + (Boolean(originalMessage?.IOUTransactionID) || // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing (isMessageDeleted(action) && action.childVisibleActionCount) || - (action.pendingAction === CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE && (isOffline ?? isNetworkOffline))), - ); + (action.pendingAction === CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE && (isOffline ?? isNetworkOffline))) + ); + }); // If we don't have any IOU request actions, or we have more than one IOU request actions, this isn't a oneTransaction report if (!iouRequestActions.length || iouRequestActions.length > 1) { @@ -1102,7 +1124,7 @@ function getMemberChangeMessageElements(reportAction: OnyxEntry): } function getReportActionHtml(reportAction: PartialReportAction): string { - return getReportActionMessage(reportAction)?.html; + return getReportActionMessage(reportAction)?.html ?? ''; } function getReportActionText(reportAction: PartialReportAction): string { @@ -1215,7 +1237,7 @@ function isActionableMentionWhisper(reportAction: OnyxEntry): repo * @param reportAction */ function isActionableReportMentionWhisper(reportAction: OnyxEntry): reportAction is ReportAction { - return isActionOfType(reportAction,CONST.REPORT.ACTIONS.TYPE.ACTIONABLE_REPORT_MENTION_WHISPER); + return isActionOfType(reportAction, CONST.REPORT.ACTIONS.TYPE.ACTIONABLE_REPORT_MENTION_WHISPER); } /** @@ -1283,10 +1305,7 @@ function isActionableJoinRequest(reportAction: OnyxEntry): reportA */ function isActionableJoinRequestPending(reportID: string): boolean { const sortedReportActions = getSortedReportActions(Object.values(getAllReportActions(reportID))); - const findPendingRequest = sortedReportActions.find( - (reportActionItem) => - isActionableJoinRequest(reportActionItem) && getOriginalMessage(reportActionItem).choice === '', - ); + const findPendingRequest = sortedReportActions.find((reportActionItem) => isActionableJoinRequest(reportActionItem) && getOriginalMessage(reportActionItem)?.choice === ''); return !!findPendingRequest; } @@ -1305,8 +1324,8 @@ function getReportActionMessageText(reportAction: OnyxEntry | Empt } function getDismissedViolationMessageText(originalMessage: ReportAction['originalMessage']): string { - const reason = originalMessage.reason; - const violationName = originalMessage.violationName; + const reason = originalMessage?.reason; + const violationName = originalMessage?.violationName; return Localize.translateLocal(`violationDismissal.${violationName}.${reason}` as TranslationPaths); } @@ -1392,9 +1411,8 @@ export { getReportActionText, getReportActionHtml, getReportActionMessage, - getReportActionOriginalMessage, getOriginalMessage, - isActionOfType, + isActionOfType, getMessage, isActionableTrackExpense, getAllReportActions, @@ -1406,7 +1424,7 @@ export { isRoomChangeLogAction, isChronosOOOListAction, isAddCommentAction, - isPolicyChangelLogAction + isPolicyChangelLogAction, }; export type {LastVisibleMessage}; diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 3edec9c057f0..96796dc47b1c 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -1,7 +1,7 @@ import {format} from 'date-fns'; import ExpensiMark from 'expensify-common/lib/ExpensiMark'; import Str from 'expensify-common/lib/str'; -import {isEmpty, last} from 'lodash'; +import {isEmpty} from 'lodash'; import lodashEscape from 'lodash/escape'; import lodashFindLastIndex from 'lodash/findLastIndex'; import lodashIntersection from 'lodash/intersection'; @@ -22,6 +22,7 @@ import type {Route} from '@src/ROUTES'; import ROUTES from '@src/ROUTES'; import type { Beta, + OriginalMessageIOU, PersonalDetails, PersonalDetailsList, Policy, @@ -38,6 +39,7 @@ import type { } from '@src/types/onyx'; import type {Participant} from '@src/types/onyx/IOU'; import type {Errors, Icon, PendingAction} from '@src/types/onyx/OnyxCommon'; +import type {OriginalMessageChangeLog, PaymentMethodType} from '@src/types/onyx/OriginalMessage'; import type {Status} from '@src/types/onyx/PersonalDetails'; import type {NotificationPreference, Participants, PendingChatMember, Participant as ReportParticipant} from '@src/types/onyx/Report'; import type {Message, ReportActions} from '@src/types/onyx/ReportAction'; @@ -72,8 +74,6 @@ import * as TransactionUtils from './TransactionUtils'; import * as Url from './Url'; import type {AvatarSource} from './UserUtils'; import * as UserUtils from './UserUtils'; -import { OriginalMessageChangeLog, PaymentMethodType } from '@src/types/onyx/OriginalMessage'; -import ReportActionName from '@src/types/onyx/ReportActionName'; type AvatarRange = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18; @@ -242,7 +242,7 @@ type OptimisticEditedTaskReportAction = Pick< >; type OptimisticClosedReportAction = Pick< - ReportAction, + ReportAction, 'actionName' | 'actorAccountID' | 'automatic' | 'avatar' | 'created' | 'message' | 'originalMessage' | 'pendingAction' | 'person' | 'reportActionID' | 'shouldShow' >; @@ -251,11 +251,15 @@ type OptimisticDismissedViolationReportAction = Pick< 'actionName' | 'actorAccountID' | 'avatar' | 'created' | 'message' | 'originalMessage' | 'person' | 'reportActionID' | 'shouldShow' | 'pendingAction' >; -type OptimisticCreatedReportAction = - Pick, 'actorAccountID' | 'automatic' | 'avatar' | 'created' | 'message' | 'person' | 'reportActionID' | 'shouldShow' | 'pendingAction' | 'actionName'>; +type OptimisticCreatedReportAction = Pick< + ReportAction, + 'actorAccountID' | 'automatic' | 'avatar' | 'created' | 'message' | 'person' | 'reportActionID' | 'shouldShow' | 'pendingAction' | 'actionName' +>; -type OptimisticRenamedReportAction = - Pick, 'actorAccountID' | 'automatic' | 'avatar' | 'created' | 'message' | 'person' | 'reportActionID' | 'shouldShow' | 'pendingAction' | 'actionName' | 'originalMessage'>; +type OptimisticRenamedReportAction = Pick< + ReportAction, + 'actorAccountID' | 'automatic' | 'avatar' | 'created' | 'message' | 'person' | 'reportActionID' | 'shouldShow' | 'pendingAction' | 'actionName' | 'originalMessage' +>; type OptimisticChatReport = Pick< Report, @@ -1532,9 +1536,9 @@ function canDeleteReportAction(reportAction: OnyxEntry, reportID: const isActionOwner = reportAction?.actorAccountID === currentUserAccountID; const policy = allPolicies?.[`${ONYXKEYS.COLLECTION.POLICY}${report?.policyID}`] ?? null; - if (reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.IOU) { + if (ReportActionsUtils.isMoneyRequestAction(reportAction)) { // For now, users cannot delete split actions - const isSplitAction = ReportActionsUtils.getOriginalMessage(reportAction)?.type === CONST.IOU.REPORT_ACTION_TYPE.SPLIT; + const isSplitAction = ReportActionsUtils.getOriginalMessage(reportAction)?.type === CONST.IOU.REPORT_ACTION_TYPE.SPLIT; if (isSplitAction) { return false; @@ -2395,8 +2399,7 @@ function getPolicyExpenseChatName(report: OnyxEntry, policy: OnyxEntry

): boolean { const allowedReportActionType: Array> = [CONST.IOU.REPORT_ACTION_TYPE.TRACK, CONST.IOU.REPORT_ACTION_TYPE.CREATE]; const originalMessage = ReportActionsUtils.getOriginalMessage(reportAction); + const actionType = originalMessage?.type; - if (!allowedReportActionType.includes(originalMessage.type)) { + if (!actionType || !allowedReportActionType.includes(actionType)) { return false; } const moneyRequestReportID = originalMessage?.IOUReportID ?? 0; if (!moneyRequestReportID) { - return originalMessage.type === CONST.IOU.REPORT_ACTION_TYPE.TRACK; + return actionType === CONST.IOU.REPORT_ACTION_TYPE.TRACK; } const moneyRequestReport = getReport(String(moneyRequestReportID)); @@ -2718,7 +2722,7 @@ function canEditFieldOfMoneyRequest(reportAction: OnyxEntry, field */ function canEditReportAction(reportAction: OnyxEntry): boolean { const isCommentOrIOU = reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.ADD_COMMENT || reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.IOU; - const message = Array.isArray(reportAction?.message) ? reportAction?.message?.[0]: reportAction?.message; + const message = Array.isArray(reportAction?.message) ? reportAction?.message?.[0] : reportAction?.message; return Boolean( reportAction?.actorAccountID === currentUserAccountID && @@ -2853,7 +2857,7 @@ function getTransactionReportName(reportAction: OnyxEntry | EmptyObject, - iouReportAction: OnyxEntry> | EmptyObject = {}, + iouReportAction: OnyxEntry | EmptyObject = {}, shouldConsiderScanningReceiptOrPendingRoute = false, isPreviewMessageForParentChatReport = false, policy: OnyxEntry = null, @@ -3575,7 +3579,7 @@ function buildOptimisticAddCommentReportAction( originalMessage: { html: htmlForNewComment, text: textForNewComment, - whisperedTo: [] + whisperedTo: [], }, isFirstItem: false, isAttachment, @@ -3659,7 +3663,7 @@ function buildOptimisticTaskCommentReportAction( reportAction.reportAction.originalMessage = { html: ReportActionsUtils.getReportActionMessage(reportAction.reportAction)?.html ?? '', taskReportID: ReportActionsUtils.getReportActionMessage(reportAction.reportAction)?.taskReportID, - whisperedTo: [] + whisperedTo: [], }; reportAction.reportAction.childReportID = taskReportID; reportAction.reportAction.parentReportID = parentReportID; @@ -4383,6 +4387,7 @@ function updateReportPreview( originalMessage: { ...(originalMessage ?? {}), whisperedTo: hasReceipt ? originalMessage?.whisperedTo : [], + linkedReportID: originalMessage?.linkedReportID ?? '0', }, }; } @@ -4770,7 +4775,11 @@ function buildOptimisticChangedTaskAssigneeReportAction(assigneeAccountID: numbe * * @param reason - A reason why the chat has been archived */ -function buildOptimisticClosedReportAction(emailClosingReport: string, policyName: string, reason: string = CONST.REPORT.ARCHIVE_REASON.DEFAULT): OptimisticClosedReportAction { +function buildOptimisticClosedReportAction( + emailClosingReport: string, + policyName: string, + reason: ValueOf = CONST.REPORT.ARCHIVE_REASON.DEFAULT, +): OptimisticClosedReportAction { return { actionName: CONST.REPORT.ACTIONS.TYPE.CLOSED, actorAccountID: currentUserAccountID, @@ -4810,7 +4819,9 @@ function buildOptimisticClosedReportAction(emailClosingReport: string, policyNam * Returns an optimistic Dismissed Violation Report Action. Use the originalMessage customize this to the type of * violation being dismissed. */ -function buildOptimisticDismissedViolationReportAction(originalMessage: OriginalMessageDismissedViolation['originalMessage']): OptimisticDismissedViolationReportAction { +function buildOptimisticDismissedViolationReportAction( + originalMessage: ReportAction['originalMessage'], +): OptimisticDismissedViolationReportAction { return { actionName: CONST.REPORT.ACTIONS.TYPE.DISMISSED_VIOLATION, actorAccountID: currentUserAccountID, @@ -5167,10 +5178,10 @@ function shouldHideReport(report: OnyxEntry, currentReportId: string): b * Checks to see if a report's parentAction is an expense that contains a violation */ function doesTransactionThreadHaveViolations(report: OnyxEntry, transactionViolations: OnyxCollection, parentReportAction: OnyxEntry): boolean { - if (parentReportAction?.actionName !== CONST.REPORT.ACTIONS.TYPE.IOU) { + if (!ReportActionsUtils.isMoneyRequestAction(parentReportAction)) { return false; } - const {IOUTransactionID, IOUReportID} = ReportActionsUtils.getOriginalMessage(parentReportAction) ?? {}; + const {IOUTransactionID, IOUReportID} = ReportActionsUtils.getOriginalMessage(parentReportAction) ?? {}; if (!IOUTransactionID || !IOUReportID) { return false; } @@ -5191,7 +5202,10 @@ function shouldDisplayTransactionThreadViolations( transactionViolations: OnyxCollection, parentReportAction: OnyxEntry, ): boolean { - const {IOUReportID} = ReportActionsUtils.getOriginalMessage(parentReportAction) ?? {}; + if (!ReportActionsUtils.isMoneyRequestAction(parentReportAction)) { + return false; + } + const {IOUReportID} = ReportActionsUtils.getOriginalMessage(parentReportAction) ?? {}; if (isSettled(IOUReportID)) { return false; } @@ -6148,18 +6162,18 @@ function getTaskAssigneeChatOnyxData( * Return iou report action display message */ function getIOUReportActionDisplayMessage(reportAction: OnyxEntry, transaction?: OnyxEntry): string { - if (reportAction?.actionName !== CONST.REPORT.ACTIONS.TYPE.IOU) { + if (!ReportActionsUtils.isMoneyRequestAction(reportAction)) { return ''; } - const originalMessage = ReportActionsUtils.getOriginalMessage(reportAction); - const {IOUReportID} = originalMessage; + const originalMessage = ReportActionsUtils.getOriginalMessage(reportAction); + const {IOUReportID} = originalMessage ?? {}; const iouReport = getReport(IOUReportID); let translationKey: TranslationPaths; - if (originalMessage.type === CONST.IOU.REPORT_ACTION_TYPE.PAY) { + if (originalMessage?.type === CONST.IOU.REPORT_ACTION_TYPE.PAY) { // The `REPORT_ACTION_TYPE.PAY` action type is used for both fulfilling existing requests and sending money. To // differentiate between these two scenarios, we check if the `originalMessage` contains the `IOUDetails` // property. If it does, it indicates that this is a 'Pay someone' action. - const {amount, currency} = originalMessage.IOUDetails ?? originalMessage; + const {amount, currency} = originalMessage?.IOUDetails ?? originalMessage ?? {}; const formattedAmount = CurrencyUtils.convertToDisplayString(Math.abs(amount), currency) ?? ''; switch (originalMessage.paymentType) { @@ -6179,7 +6193,7 @@ function getIOUReportActionDisplayMessage(reportAction: OnyxEntry, const transactionDetails = getTransactionDetails(!isEmptyObject(transaction) ? transaction : null); const formattedAmount = CurrencyUtils.convertToDisplayString(transactionDetails?.amount ?? 0, transactionDetails?.currency); - const isRequestSettled = isSettled(originalMessage.IOUReportID); + const isRequestSettled = isSettled(originalMessage?.IOUReportID); const isApproved = isReportApproved(iouReport); if (isRequestSettled) { return Localize.translateLocal('iou.payerSettled', { @@ -6309,7 +6323,7 @@ function hasSmartscanError(reportActions: ReportAction[]) { } const IOUReportID = ReportActionsUtils.getIOUReportIDFromReportActionPreview(action); const isReportPreviewError = ReportActionsUtils.isReportPreviewAction(action) && shouldShowRBRForMissingSmartscanFields(IOUReportID) && !isSettled(IOUReportID); - const transactionID = (action.originalMessage as IOUMessage).IOUTransactionID ?? '0'; + const transactionID = (action.originalMessage as OriginalMessageIOU)?.IOUTransactionID ?? '0'; const transaction = allTransactions?.[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`] ?? {}; const isSplitBillError = ReportActionsUtils.isSplitBillAction(action) && TransactionUtils.hasMissingSmartscanFields(transaction as Transaction); @@ -6752,7 +6766,7 @@ function createDraftTransactionAndNavigateToParticipantSelector(transactionID: s } const linkedTrackedExpenseReportAction = Object.values(reportActions).find( - (action) => ReportActionsUtils.getOriginalMessage(action)?.IOUTransactionID === transactionID, + (action) => ReportActionsUtils.isMoneyRequestAction(action) && ReportActionsUtils.getOriginalMessage(action)?.IOUTransactionID === transactionID, ); const {created, amount, currency, merchant, mccGroup} = getTransactionDetails(transaction) ?? {}; diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 5699c903fee6..3cf5df1ce59d 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -52,9 +52,8 @@ import ROUTES from '@src/ROUTES'; import type * as OnyxTypes from '@src/types/onyx'; import type {Participant, Split} from '@src/types/onyx/IOU'; import type {ErrorFields, Errors} from '@src/types/onyx/OnyxCommon'; -import type {IOUMessage, OriginalMessageReportPreview, PaymentMethodType} from '@src/types/onyx/OriginalMessage'; +import type {PaymentMethodType} from '@src/types/onyx/OriginalMessage'; import type ReportAction from '@src/types/onyx/ReportAction'; -import type {ReportPreviewAction} from '@src/types/onyx/ReportAction'; import type {OnyxData} from '@src/types/onyx/Request'; import type {Comment, Receipt, ReceiptSource, Routes, SplitShares, TransactionChanges, WaypointCollection} from '@src/types/onyx/Transaction'; import type DeepValueOf from '@src/types/utils/DeepValueOf'; @@ -293,10 +292,7 @@ function getReportPreviewAction(chatReportID: string, iouReportID: string): Onyx // Find the report preview action from the chat report return ( Object.values(reportActions).find( - (reportAction) => - reportAction && - ReportActionsUtils.isReportPreviewAction(reportAction) && - ReportActionsUtils.getOriginalMessage(reportAction).linkedReportID === iouReportID, + (reportAction) => reportAction && ReportActionsUtils.isReportPreviewAction(reportAction) && ReportActionsUtils.getOriginalMessage(reportAction)?.linkedReportID === iouReportID, ) ?? null ); } @@ -865,8 +861,8 @@ function buildOnyxDataForInvoice( key: `${ONYXKEYS.COLLECTION.REPORT}${iouReport.reportID}`, value: { ...iouReport, - lastMessageText: iouAction.message?.[0]?.text, - lastMessageHtml: iouAction.message?.[0]?.html, + lastMessageText: ReportActionsUtils.getReportActionText(iouAction), + lastMessageHtml: ReportActionsUtils.getReportActionHtml(iouAction), pendingFields: { createChat: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, }, @@ -1983,7 +1979,13 @@ function getMoneyRequestInformation( let reportPreviewAction = shouldCreateNewMoneyRequestReport ? null : getReportPreviewAction(chatReport.reportID, iouReport.reportID); if (reportPreviewAction) { - reportPreviewAction = ReportUtils.updateReportPreview(iouReport, reportPreviewAction as ReportPreviewAction, false, comment, optimisticTransaction); + reportPreviewAction = ReportUtils.updateReportPreview( + iouReport, + reportPreviewAction as ReportAction, + false, + comment, + optimisticTransaction, + ); } else { reportPreviewAction = ReportUtils.buildOptimisticReportPreview(chatReport, iouReport, comment, optimisticTransaction); @@ -2210,7 +2212,13 @@ function getTrackExpenseInformation( reportPreviewAction = shouldCreateNewMoneyRequestReport ? null : getReportPreviewAction(chatReport.reportID, iouReport.reportID); if (reportPreviewAction) { - reportPreviewAction = ReportUtils.updateReportPreview(iouReport, reportPreviewAction as ReportPreviewAction, false, comment, optimisticTransaction); + reportPreviewAction = ReportUtils.updateReportPreview( + iouReport, + reportPreviewAction as ReportAction, + false, + comment, + optimisticTransaction, + ); } else { reportPreviewAction = ReportUtils.buildOptimisticReportPreview(chatReport, iouReport, comment, optimisticTransaction); // Generated ReportPreview action is a parent report action of the iou report. @@ -3418,7 +3426,9 @@ function requestMoney( currentCreated, merchant, receipt, - isMovingTransactionFromTrackExpense ? ReportActionsUtils.getOriginalMessage(linkedTrackedExpenseReportAction)?.IOUTransactionID : undefined, + isMovingTransactionFromTrackExpense && linkedTrackedExpenseReportAction && ReportActionsUtils.isMoneyRequestAction(linkedTrackedExpenseReportAction) + ? ReportActionsUtils.getOriginalMessage(linkedTrackedExpenseReportAction)?.IOUTransactionID + : undefined, category, tag, taxCode, @@ -3620,7 +3630,9 @@ function trackExpense( payeeAccountID, moneyRequestReportID, linkedTrackedExpenseReportAction, - isMovingTransactionFromTrackExpense ? ReportActionsUtils.getOriginalMessage(linkedTrackedExpenseReportAction)?.IOUTransactionID : undefined, + isMovingTransactionFromTrackExpense && linkedTrackedExpenseReportAction && ReportActionsUtils.isMoneyRequestAction(linkedTrackedExpenseReportAction) + ? ReportActionsUtils.getOriginalMessage(linkedTrackedExpenseReportAction)?.IOUTransactionID + : undefined, ); const activeReportID = isMoneyRequestReport ? report.reportID : chatReport.reportID; @@ -4098,7 +4110,7 @@ function createSplitsAndOnyxData( let oneOnOneReportPreviewAction = getReportPreviewAction(oneOnOneChatReport.reportID, oneOnOneIOUReport.reportID); if (oneOnOneReportPreviewAction) { - oneOnOneReportPreviewAction = ReportUtils.updateReportPreview(oneOnOneIOUReport, oneOnOneReportPreviewAction as ReportPreviewAction); + oneOnOneReportPreviewAction = ReportUtils.updateReportPreview(oneOnOneIOUReport, oneOnOneReportPreviewAction as ReportAction); } else { oneOnOneReportPreviewAction = ReportUtils.buildOptimisticReportPreview(oneOnOneChatReport, oneOnOneIOUReport); } @@ -4793,7 +4805,7 @@ function completeSplitBill(chatReportID: string, reportAction: OnyxTypes.ReportA let oneOnOneReportPreviewAction = getReportPreviewAction(oneOnOneChatReport?.reportID ?? '', oneOnOneIOUReport?.reportID ?? ''); if (oneOnOneReportPreviewAction) { - oneOnOneReportPreviewAction = ReportUtils.updateReportPreview(oneOnOneIOUReport, oneOnOneReportPreviewAction as ReportPreviewAction); + oneOnOneReportPreviewAction = ReportUtils.updateReportPreview(oneOnOneIOUReport, oneOnOneReportPreviewAction as ReportAction); } else { oneOnOneReportPreviewAction = ReportUtils.buildOptimisticReportPreview(oneOnOneChatReport, oneOnOneIOUReport, '', oneOnOneTransaction); } @@ -5200,10 +5212,11 @@ function updateMoneyRequestAmountAndCurrency({ function deleteMoneyRequest(transactionID: string, reportAction: OnyxTypes.ReportAction, isSingleTransactionView = false) { // STEP 1: Get all collections we're updating - const iouReportID = reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.IOU ? ReportActionsUtils.getOriginalMessage(reportAction).IOUReportID : ''; + const iouReportID = ReportActionsUtils.isMoneyRequestAction(reportAction) ? ReportActionsUtils.getOriginalMessage(reportAction)?.IOUReportID : ''; const iouReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${iouReportID}`] ?? null; const chatReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${iouReport?.chatReportID}`]; - const reportPreviewAction = getReportPreviewAction(iouReport?.chatReportID ?? '', iouReport?.reportID ?? ''); + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + const reportPreviewAction = getReportPreviewAction(iouReport?.chatReportID ?? '', iouReport?.reportID ?? '')!; const transaction = allTransactions[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`]; const transactionViolations = allTransactionViolations[`${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transactionID}`]; const transactionThreadID = reportAction.childReportID; @@ -5233,7 +5246,7 @@ function deleteMoneyRequest(transactionID: string, reportAction: OnyxTypes.Repor }, ], originalMessage: { - IOUTransactionID: null, + IOUTransactionID: undefined, }, errors: undefined, }, @@ -5247,7 +5260,7 @@ function deleteMoneyRequest(transactionID: string, reportAction: OnyxTypes.Repor // STEP 4: Update the iouReport and reportPreview with new totals and messages if it wasn't deleted let updatedIOUReport: OnyxTypes.Report | null; const currency = TransactionUtils.getCurrency(transaction); - const updatedReportPreviewAction: OnyxTypes.ReportAction | EmptyObject = {...reportPreviewAction}; + const updatedReportPreviewAction: OnyxTypes.ReportAction = {...reportPreviewAction}; updatedReportPreviewAction.pendingAction = shouldDeleteIOUReport ? CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE : CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE; if (iouReport && ReportUtils.isExpenseReport(iouReport)) { updatedIOUReport = {...iouReport}; @@ -5277,8 +5290,13 @@ function deleteMoneyRequest(transactionID: string, reportAction: OnyxTypes.Repor }); if (ReportActionsUtils.getReportActionMessage(updatedReportPreviewAction)) { - ReportActionsUtils.getReportActionMessage(updatedReportPreviewAction).text = messageText; - ReportActionsUtils.getReportActionMessage(updatedReportPreviewAction).deleted = shouldDeleteIOUReport ? DateUtils.getDBTime() : ''; + if (Array.isArray(updatedReportPreviewAction?.message) && updatedReportPreviewAction.message?.[0]) { + updatedReportPreviewAction.message[0].text = messageText; + updatedReportPreviewAction.message[0].deleted = shouldDeleteIOUReport ? DateUtils.getDBTime() : ''; + } else if (!Array.isArray(updatedReportPreviewAction.message) && updatedReportPreviewAction.message) { + updatedReportPreviewAction.message.text = messageText; + updatedReportPreviewAction.message.deleted = shouldDeleteIOUReport ? DateUtils.getDBTime() : ''; + } } if (updatedReportPreviewAction && reportPreviewAction?.childMoneyRequestCount && reportPreviewAction?.childMoneyRequestCount > 0) { @@ -5875,7 +5893,7 @@ function getPayMoneyRequestParams( let optimisticReportPreviewAction = null; const reportPreviewAction = getReportPreviewAction(chatReport.reportID, iouReport.reportID); if (reportPreviewAction) { - optimisticReportPreviewAction = ReportUtils.updateReportPreview(iouReport, reportPreviewAction as ReportPreviewAction, true); + optimisticReportPreviewAction = ReportUtils.updateReportPreview(iouReport, reportPreviewAction as ReportAction, true); } const currentNextStep = allNextSteps[`${ONYXKEYS.COLLECTION.NEXT_STEP}${iouReport.reportID}`] ?? null; diff --git a/src/libs/actions/Policy/Policy.ts b/src/libs/actions/Policy/Policy.ts index bc5ed08e8218..0211d43809c1 100644 --- a/src/libs/actions/Policy/Policy.ts +++ b/src/libs/actions/Policy/Policy.ts @@ -3147,7 +3147,7 @@ function acceptJoinRequest(reportID: string, reportAction: OnyxEntry reportAction.actionName === CONST.REPORT.ACTIONS.TYPE.IOU) - .map((reportAction) => ReportActionsUtils.getOriginalMessage(reportAction).IOUTransactionID); + .filter((reportAction): reportAction is ReportAction => ReportActionsUtils.isMoneyRequestAction(reportAction)) + .map((reportAction) => ReportActionsUtils.getOriginalMessage(reportAction)?.IOUTransactionID); [...new Set(transactionIDs)].forEach((transactionID) => { onyxData[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`] = null; @@ -3611,8 +3611,9 @@ function resolveActionableReportMentionWhisper( } function dismissTrackExpenseActionableWhisper(reportID: string, reportAction: OnyxEntry): void { - const message = reportAction?.message?.[0]; - if (!message) { + const isArrayMessage = Array.isArray(reportAction?.message); + const message = ReportActionsUtils.getReportActionMessage(reportAction); + if (!message || !reportAction) { return; } @@ -3627,7 +3628,7 @@ function dismissTrackExpenseActionableWhisper(reportID: string, reportAction: On key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`, value: { [reportAction.reportActionID]: { - message: [updatedMessage], + message: isArrayMessage ? [updatedMessage] : updatedMessage, originalMessage: { resolution: CONST.REPORT.ACTIONABLE_TRACK_EXPENSE_WHISPER_RESOLUTION.NOTHING, }, diff --git a/src/libs/actions/User.ts b/src/libs/actions/User.ts index cab0c1c6f152..91681091b1d4 100644 --- a/src/libs/actions/User.ts +++ b/src/libs/actions/User.ts @@ -42,7 +42,6 @@ import type {OnyxServerUpdate} from '@src/types/onyx/OnyxUpdatesFromServer'; import type OnyxPersonalDetails from '@src/types/onyx/PersonalDetails'; import type {Status} from '@src/types/onyx/PersonalDetails'; import type ReportAction from '@src/types/onyx/ReportAction'; -import type {OriginalMessage} from '@src/types/onyx/ReportAction'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; import type {EmptyObject} from '@src/types/utils/EmptyObject'; import applyOnyxUpdatesReliably from './applyOnyxUpdatesReliably'; @@ -526,6 +525,10 @@ function playSoundForMessageType(pushJSON: OnyxServerUpdate[]) { const types = flatten.map((data) => ReportActionsUtils.getOriginalMessage(data)).filter(Boolean); for (const message of types) { + if (!message) { + return; + } + // Pay someone flow if ('IOUDetails' in message) { return playSound(SOUNDS.SUCCESS); diff --git a/src/pages/home/report/ContextMenu/ContextMenuActions.tsx b/src/pages/home/report/ContextMenu/ContextMenuActions.tsx index ade0ca7da227..181d52c29a67 100644 --- a/src/pages/home/report/ContextMenu/ContextMenuActions.tsx +++ b/src/pages/home/report/ContextMenu/ContextMenuActions.tsx @@ -35,7 +35,7 @@ import {hideContextMenu, showDeleteModal} from './ReportActionContextMenu'; /** Gets the HTML version of the message in an action */ function getActionHtml(reportAction: OnyxEntry): string { - const message = reportAction?.message?.at(-1) ?? null; + const message = Array.isArray(reportAction?.message) ? reportAction?.message?.at(-1) ?? null : reportAction?.message ?? null; return message?.html ?? ''; } @@ -342,7 +342,7 @@ const ContextMenuActions: ContextMenuAction[] = [ const modifyExpenseMessage = ModifiedExpenseMessage.getForReportAction(reportID, reportAction); Clipboard.setString(modifyExpenseMessage); } else if (ReportActionsUtils.isReimbursementDeQueuedAction(reportAction)) { - const {expenseReportID} = ReportActionsUtils.getOriginalMessage(reportAction); + const {expenseReportID} = ReportActionsUtils.getOriginalMessage(reportAction) ?? {}; const expenseReport = ReportUtils.getReport(expenseReportID); const displayMessage = ReportUtils.getReimbursementDeQueuedActionMessage(reportAction, expenseReport); Clipboard.setString(displayMessage); diff --git a/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions/ComposerWithSuggestions.tsx b/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions/ComposerWithSuggestions.tsx index cd92f8c75ae1..ba984b8e16ae 100644 --- a/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions/ComposerWithSuggestions.tsx +++ b/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions/ComposerWithSuggestions.tsx @@ -541,7 +541,8 @@ function ComposerWithSuggestions( event.preventDefault(); if (lastReportAction) { const parser = new ExpensiMark(); - Report.saveReportActionDraft(reportID, lastReportAction, parser.htmlToMarkdown(lastReportAction.message?.at(-1)?.html ?? '')); + const message = Array.isArray(lastReportAction?.message) ? lastReportAction?.message?.at(-1) ?? null : lastReportAction?.message ?? null; + Report.saveReportActionDraft(reportID, lastReportAction, parser.htmlToMarkdown(message?.html ?? '')); } } }, diff --git a/src/pages/home/report/ReportActionItem.tsx b/src/pages/home/report/ReportActionItem.tsx index 9645b29170ad..6bf79ee134fc 100644 --- a/src/pages/home/report/ReportActionItem.tsx +++ b/src/pages/home/report/ReportActionItem.tsx @@ -218,14 +218,13 @@ function ReportActionItem({ ); const isDeletedParentAction = ReportActionsUtils.isDeletedParentAction(action); - const prevActionResolution = usePrevious( - isActionableWhisper && 'resolution' in originalMessage ? - originalMessage.resolution - : null, - ); + const prevActionResolution = usePrevious(isActionableWhisper && originalMessage && 'resolution' in originalMessage ? originalMessage?.resolution : null); // IOUDetails only exists when we are sending money - const isSendingMoney = ReportActionsUtils.isMoneyRequestAction(action) && ReportActionsUtils.getOriginalMessage(action).type === CONST.IOU.REPORT_ACTION_TYPE.PAY && ReportActionsUtils.getOriginalMessage(action).IOUDetails; + const isSendingMoney = + ReportActionsUtils.isMoneyRequestAction(action) && + ReportActionsUtils.getOriginalMessage(action)?.type === CONST.IOU.REPORT_ACTION_TYPE.PAY && + ReportActionsUtils.getOriginalMessage(action)?.IOUDetails; const updateHiddenState = useCallback( (isHiddenValue: boolean) => { @@ -370,9 +369,7 @@ function ReportActionItem({ return; } - if ( - prevActionResolution !== ('resolution' in originalMessage ? originalMessage.resolution : null) - ) { + if (prevActionResolution !== (originalMessage && 'resolution' in originalMessage ? originalMessage.resolution : null)) { reportScrollManager.scrollToIndex(index); } }, [index, originalMessage, prevActionResolution, reportScrollManager, isActionableWhisper]); @@ -398,7 +395,7 @@ function ReportActionItem({ const attachmentContextValue = useMemo(() => ({reportID: report.reportID, type: CONST.ATTACHMENT_TYPE.REPORT}), [report.reportID]); const actionableItemButtons: ActionableItem[] = useMemo(() => { - if (!isActionableWhisper && (!ReportActionsUtils.isActionableJoinRequest(action) || ReportActionsUtils.getOriginalMessage(action).choice !== '')) { + if (!isActionableWhisper && (!ReportActionsUtils.isActionableJoinRequest(action) || ReportActionsUtils.getOriginalMessage(action)?.choice !== '')) { return []; } @@ -409,7 +406,7 @@ function ReportActionItem({ text: 'actionableMentionTrackExpense.submit', key: `${action.reportActionID}-actionableMentionTrackExpense-submit`, onPress: () => { - ReportUtils.createDraftTransactionAndNavigateToParticipantSelector(transactionID, report.reportID, CONST.IOU.ACTION.SUBMIT, action.reportActionID); + ReportUtils.createDraftTransactionAndNavigateToParticipantSelector(transactionID ?? '0', report.reportID, CONST.IOU.ACTION.SUBMIT, action.reportActionID); }, isMediumSized: true, }, @@ -417,7 +414,7 @@ function ReportActionItem({ text: 'actionableMentionTrackExpense.categorize', key: `${action.reportActionID}-actionableMentionTrackExpense-categorize`, onPress: () => { - ReportUtils.createDraftTransactionAndNavigateToParticipantSelector(transactionID, report.reportID, CONST.IOU.ACTION.CATEGORIZE, action.reportActionID); + ReportUtils.createDraftTransactionAndNavigateToParticipantSelector(transactionID ?? '0', report.reportID, CONST.IOU.ACTION.CATEGORIZE, action.reportActionID); }, isMediumSized: true, }, @@ -425,7 +422,7 @@ function ReportActionItem({ text: 'actionableMentionTrackExpense.share', key: `${action.reportActionID}-actionableMentionTrackExpense-share`, onPress: () => { - ReportUtils.createDraftTransactionAndNavigateToParticipantSelector(transactionID, report.reportID, CONST.IOU.ACTION.SHARE, action.reportActionID); + ReportUtils.createDraftTransactionAndNavigateToParticipantSelector(transactionID ?? '0', report.reportID, CONST.IOU.ACTION.SHARE, action.reportActionID); }, isMediumSized: true, }, @@ -564,11 +561,7 @@ function ReportActionItem({ children = ( ); - } else if (action.actionName === CONST.REPORT.ACTIONS.TYPE.REIMBURSEMENT_DEQUEUED) { + } else if (ReportActionsUtils.isReimbursementDeQueuedAction(action)) { children = ; } else if (action.actionName === CONST.REPORT.ACTIONS.TYPE.MODIFIED_EXPENSE) { children = ; @@ -639,9 +632,7 @@ function ReportActionItem({ } else if (action.actionName === CONST.REPORT.ACTIONS.TYPE.MERGED_WITH_CASH_TRANSACTION) { children = ; } else if (ReportActionsUtils.isActionOfType(action, CONST.REPORT.ACTIONS.TYPE.DISMISSED_VIOLATION)) { - children = ( - - ); + children = ; } else { const hasBeenFlagged = ![CONST.MODERATION.MODERATOR_DECISION_APPROVED, CONST.MODERATION.MODERATOR_DECISION_PENDING].some((item) => item === moderationDecision) && @@ -916,15 +907,17 @@ function ReportActionItem({ // For the `pay` IOU action on non-pay expense flow, we don't want to render anything if `isWaitingOnBankAccount` is true // Otherwise, we will see two system messages informing the payee needs to add a bank account or wallet - if (ReportActionsUtils.isMoneyRequestAction(action) && !!report?.isWaitingOnBankAccount && ReportActionsUtils.getOriginalMessage(action).type === CONST.IOU.REPORT_ACTION_TYPE.PAY && !isSendingMoney) { + if ( + ReportActionsUtils.isMoneyRequestAction(action) && + !!report?.isWaitingOnBankAccount && + ReportActionsUtils.getOriginalMessage(action)?.type === CONST.IOU.REPORT_ACTION_TYPE.PAY && + !isSendingMoney + ) { return null; } // If action is actionable whisper and resolved by user, then we don't want to render anything - if ( - isActionableWhisper && - ('resolution' in originalMessage ? originalMessage.resolution : null) - ) { + if (isActionableWhisper && (originalMessage && 'resolution' in originalMessage ? originalMessage.resolution : null)) { return null; } @@ -939,7 +932,10 @@ function ReportActionItem({ const whisperedTo = ReportActionsUtils.getWhisperedTo(action); const isMultipleParticipant = whisperedTo.length > 1; - const iouReportID = ReportActionsUtils.isMoneyRequestAction(action) && ReportActionsUtils.getOriginalMessage(action).IOUReportID ? (ReportActionsUtils.getOriginalMessage(action)?.IOUReportID ?? '').toString() : '0'; + const iouReportID = + ReportActionsUtils.isMoneyRequestAction(action) && ReportActionsUtils.getOriginalMessage(action)?.IOUReportID + ? (ReportActionsUtils.getOriginalMessage(action)?.IOUReportID ?? '').toString() + : '0'; const transactionsWithReceipts = ReportUtils.getTransactionsWithReceipts(iouReportID); const isWhisper = whisperedTo.length > 0 && transactionsWithReceipts.length === 0 && !action.pendingAction; const whisperedToPersonalDetails = isWhisper @@ -1057,7 +1053,10 @@ export default withOnyx({ }, transaction: { key: ({parentReportActionForTransactionThread}) => { - const originalMessage = !!parentReportActionForTransactionThread && ReportActionsUtils.isMoneyRequestAction(parentReportActionForTransactionThread) ? ReportActionsUtils.getOriginalMessage(parentReportActionForTransactionThread) : undefined; + const originalMessage = + !!parentReportActionForTransactionThread && ReportActionsUtils.isMoneyRequestAction(parentReportActionForTransactionThread) + ? ReportActionsUtils.getOriginalMessage(parentReportActionForTransactionThread) + : undefined; const transactionID = originalMessage?.IOUTransactionID ? originalMessage?.IOUTransactionID : 0; return `${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`; }, diff --git a/src/pages/home/report/ReportActionItemFragment.tsx b/src/pages/home/report/ReportActionItemFragment.tsx index 8f19d452f150..27227251b0b6 100644 --- a/src/pages/home/report/ReportActionItemFragment.tsx +++ b/src/pages/home/report/ReportActionItemFragment.tsx @@ -10,8 +10,9 @@ import convertToLTR from '@libs/convertToLTR'; import * as ReportUtils from '@libs/ReportUtils'; import CONST from '@src/CONST'; import type * as OnyxCommon from '@src/types/onyx/OnyxCommon'; -import type {ActionName, DecisionName, OriginalMessageSource} from '@src/types/onyx/OriginalMessage'; +import type {DecisionName, OriginalMessageSource} from '@src/types/onyx/OriginalMessage'; import type {Message} from '@src/types/onyx/ReportAction'; +import type ReportActionName from '@src/types/onyx/ReportActionName'; import AttachmentCommentFragment from './comment/AttachmentCommentFragment'; import TextCommentFragment from './comment/TextCommentFragment'; @@ -59,7 +60,7 @@ type ReportActionItemFragmentProps = { pendingAction?: OnyxCommon.PendingAction; /** The report action name */ - actionName?: ActionName; + actionName?: ReportActionName; moderationDecision?: DecisionName; }; @@ -70,7 +71,7 @@ const MUTED_ACTIONS = [ CONST.REPORT.ACTIONS.TYPE.APPROVED, CONST.REPORT.ACTIONS.TYPE.MOVED, CONST.REPORT.ACTIONS.TYPE.ACTIONABLE_JOIN_REQUEST, -] as ActionName[]; +] as ReportActionName[]; function ReportActionItemFragment({ pendingAction, diff --git a/src/pages/home/report/ReportActionItemMessage.tsx b/src/pages/home/report/ReportActionItemMessage.tsx index def7d76b5820..1feaa2ddf1b5 100644 --- a/src/pages/home/report/ReportActionItemMessage.tsx +++ b/src/pages/home/report/ReportActionItemMessage.tsx @@ -42,7 +42,12 @@ function ReportActionItemMessage({action, transaction, displayAsGroup, reportID, const {translate} = useLocalize(); const actionMessage = action.previousMessage ?? action.message; - const fragments = Array.isArray(actionMessage) ? actionMessage.filter((item) => !!item) : !!actionMessage ? [actionMessage] : []; + let fragments = []; + if (Array.isArray(actionMessage)) { + fragments = actionMessage.filter((item) => !!item); + } else { + fragments = actionMessage ? [actionMessage] : []; + } const isIOUReport = ReportActionsUtils.isMoneyRequestAction(action); if (ReportActionsUtils.isMemberChangeAction(action)) { @@ -63,7 +68,7 @@ function ReportActionItemMessage({action, transaction, displayAsGroup, reportID, let iouMessage: string | undefined; if (isIOUReport) { - const originalMessage = action.actionName === CONST.REPORT.ACTIONS.TYPE.IOU ? ReportActionsUtils.getOriginalMessage(action) : null; + const originalMessage = action.actionName === CONST.REPORT.ACTIONS.TYPE.IOU ? ReportActionsUtils.getOriginalMessage(action) : null; const iouReportID = originalMessage?.IOUReportID; if (iouReportID) { iouMessage = ReportUtils.getIOUReportActionDisplayMessage(action, transaction); diff --git a/src/pages/home/report/ReportActionsView.tsx b/src/pages/home/report/ReportActionsView.tsx index d1fa94e3e640..aa85b53d3e16 100755 --- a/src/pages/home/report/ReportActionsView.tsx +++ b/src/pages/home/report/ReportActionsView.tsx @@ -28,7 +28,6 @@ import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import type SCREENS from '@src/SCREENS'; import type * as OnyxTypes from '@src/types/onyx'; -import type {IOUMessage} from '@src/types/onyx/OriginalMessage'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; import getInitialPaginationSize from './getInitialPaginationSize'; import PopoverReactionList from './ReactionList/PopoverReactionList'; @@ -482,13 +481,13 @@ function ReportActionsView({ const reportPreviewAction = ReportActionsUtils.getReportPreviewAction(report.chatReportID ?? '', report.reportID); const moneyRequestActions = reportActions.filter((action) => { - const originalMessage = ReportActionsUtils.getOriginalMessage(action); + const originalMessage = ReportActionsUtils.isMoneyRequestAction(action) ? ReportActionsUtils.getOriginalMessage(action) : undefined; return ( - action.actionName === CONST.REPORT.ACTIONS.TYPE.IOU && + ReportActionsUtils.isMoneyRequestAction(action) && originalMessage && - (originalMessage.type === CONST.IOU.REPORT_ACTION_TYPE.CREATE || - Boolean(originalMessage.type === CONST.IOU.REPORT_ACTION_TYPE.PAY && originalMessage.IOUDetails) || - originalMessage.type === CONST.IOU.REPORT_ACTION_TYPE.TRACK) + (originalMessage?.type === CONST.IOU.REPORT_ACTION_TYPE.CREATE || + Boolean(originalMessage?.type === CONST.IOU.REPORT_ACTION_TYPE.PAY && originalMessage?.IOUDetails) || + originalMessage?.type === CONST.IOU.REPORT_ACTION_TYPE.TRACK) ); }); diff --git a/src/pages/iou/SplitBillDetailsPage.tsx b/src/pages/iou/SplitBillDetailsPage.tsx index 2a1c5fd9fff9..561e7e676145 100644 --- a/src/pages/iou/SplitBillDetailsPage.tsx +++ b/src/pages/iou/SplitBillDetailsPage.tsx @@ -64,8 +64,7 @@ function SplitBillDetailsPage({personalDetails, report, route, reportActions, tr const {translate} = useLocalize(); const theme = useTheme(); const reportAction = useMemo(() => reportActions?.[route.params.reportActionID] ?? ({} as ReportAction), [reportActions, route.params.reportActionID]); - const participantAccountIDs = - ReportActionsUtils.isMoneyRequestAction(reportAction) ? ReportActionsUtils.getOriginalMessage(reportAction).participantAccountIDs ?? [] : []; + const participantAccountIDs = ReportActionsUtils.isMoneyRequestAction(reportAction) ? ReportActionsUtils.getOriginalMessage(reportAction)?.participantAccountIDs ?? [] : []; // In case this is workspace split expense, we manually add the workspace as the second participant of the split expense // because we don't save any accountID in the report action's originalMessage other than the payee's accountID diff --git a/src/types/onyx/OriginalMessage.ts b/src/types/onyx/OriginalMessage.ts index ec251c907792..a56d47854e91 100644 --- a/src/types/onyx/OriginalMessage.ts +++ b/src/types/onyx/OriginalMessage.ts @@ -212,31 +212,31 @@ type OriginalMessageDismissedViolation = { type OriginalMessageMap1 = { [CONST.REPORT.ACTIONS.TYPE.ACTIONABLE_JOIN_REQUEST]: { - originalMessage: OriginalMessageJoinPolicyChangeLog + originalMessage: OriginalMessageJoinPolicyChangeLog; }; [CONST.REPORT.ACTIONS.TYPE.ACTIONABLE_MENTION_WHISPER]: { originalMessage: OriginalMessageActionableMentionWhisper; }; [CONST.REPORT.ACTIONS.TYPE.ACTIONABLE_REPORT_MENTION_WHISPER]: { - originalMessage: OriginalMessageActionableReportMentionWhisper + originalMessage: OriginalMessageActionableReportMentionWhisper; }; [CONST.REPORT.ACTIONS.TYPE.ACTIONABLE_TRACK_EXPENSE_WHISPER]: { originalMessage: OriginalMessageActionableTrackedExpenseWhisper; - } + }; [CONST.REPORT.ACTIONS.TYPE.ADD_COMMENT]: { originalMessage: OriginalMessageAddComment; }; [CONST.REPORT.ACTIONS.TYPE.APPROVED]: { - originalMessage?: never + originalMessage?: never; }; [CONST.REPORT.ACTIONS.TYPE.CHANGE_FIELD]: { - originalMessage?: never + originalMessage?: never; }; [CONST.REPORT.ACTIONS.TYPE.CHANGE_POLICY]: { - originalMessage?: never + originalMessage?: never; }; [CONST.REPORT.ACTIONS.TYPE.CHANGE_TYPE]: { - originalMessage?: never + originalMessage?: never; }; [CONST.REPORT.ACTIONS.TYPE.CHRONOS_OOO_LIST]: { originalMessage: OriginalMessageChronosOOOList; @@ -245,58 +245,58 @@ type OriginalMessageMap1 = { originalMessage: OriginalMessageClosed; }; [CONST.REPORT.ACTIONS.TYPE.CREATED]: { - originalMessage?: never + originalMessage?: never; }; [CONST.REPORT.ACTIONS.TYPE.DELEGATE_SUBMIT]: { - originalMessage?: never + originalMessage?: never; }; [CONST.REPORT.ACTIONS.TYPE.DELETED_ACCOUNT]: { - originalMessage?: never + originalMessage?: never; }; [CONST.REPORT.ACTIONS.TYPE.DISMISSED_VIOLATION]: { originalMessage: OriginalMessageDismissedViolation; }; [CONST.REPORT.ACTIONS.TYPE.DONATION]: { - originalMessage?: never + originalMessage?: never; }; [CONST.REPORT.ACTIONS.TYPE.EXPORTED_TO_CSV]: { - originalMessage?: never + originalMessage?: never; }; [CONST.REPORT.ACTIONS.TYPE.EXPORTED_TO_INTEGRATION]: { - originalMessage?: never + originalMessage?: never; }; [CONST.REPORT.ACTIONS.TYPE.EXPORTED_TO_QUICK_BOOKS]: { - originalMessage?: never + originalMessage?: never; }; [CONST.REPORT.ACTIONS.TYPE.FORWARDED]: { - originalMessage?: never + originalMessage?: never; }; [CONST.REPORT.ACTIONS.TYPE.HOLD]: { - originalMessage?: never + originalMessage?: never; }; [CONST.REPORT.ACTIONS.TYPE.HOLD_COMMENT]: { - originalMessage?: never + originalMessage?: never; }; [CONST.REPORT.ACTIONS.TYPE.INTEGRATIONS_MESSAGE]: { - originalMessage?: never + originalMessage?: never; }; [CONST.REPORT.ACTIONS.TYPE.IOU]: { originalMessage: OriginalMessageIOU; }; [CONST.REPORT.ACTIONS.TYPE.MANAGER_ATTACH_RECEIPT]: { - originalMessage?: never + originalMessage?: never; }; [CONST.REPORT.ACTIONS.TYPE.MANAGER_DETACH_RECEIPT]: { - originalMessage?: never + originalMessage?: never; }; [CONST.REPORT.ACTIONS.TYPE.MARK_REIMBURSED_FROM_INTEGRATION]: { - originalMessage?: never + originalMessage?: never; }; [CONST.REPORT.ACTIONS.TYPE.MARKED_REIMBURSED]: { - originalMessage?: never + originalMessage?: never; }; [CONST.REPORT.ACTIONS.TYPE.MERGED_WITH_CASH_TRANSACTION]: { - originalMessage?: never + originalMessage?: never; }; [CONST.REPORT.ACTIONS.TYPE.MODIFIED_EXPENSE]: { originalMessage: OriginalMessageModifiedExpense; @@ -305,83 +305,83 @@ type OriginalMessageMap1 = { originalMessage: OriginalMessageMoved; }; [CONST.REPORT.ACTIONS.TYPE.OUTDATED_BANK_ACCOUNT]: { - originalMessage?: never + originalMessage?: never; }; [CONST.REPORT.ACTIONS.TYPE.REIMBURSEMENT_ACH_BOUNCE]: { - originalMessage?: never + originalMessage?: never; }; [CONST.REPORT.ACTIONS.TYPE.REIMBURSEMENT_ACH_CANCELLED]: { - originalMessage?: never + originalMessage?: never; }; [CONST.REPORT.ACTIONS.TYPE.REIMBURSEMENT_ACCOUNT_CHANGED]: { - originalMessage?: never + originalMessage?: never; }; [CONST.REPORT.ACTIONS.TYPE.REIMBURSEMENT_DEQUEUED]: { originalMessage: OriginalMessageReimbursementDequeued; }; [CONST.REPORT.ACTIONS.TYPE.REIMBURSEMENT_DELAYED]: { - originalMessage?: never + originalMessage?: never; }; [CONST.REPORT.ACTIONS.TYPE.REIMBURSEMENT_QUEUED]: { - originalMessage: OriginalMessageReimbursementQueued + originalMessage: OriginalMessageReimbursementQueued; }; [CONST.REPORT.ACTIONS.TYPE.REIMBURSEMENT_REQUESTED]: { - originalMessage?: never + originalMessage?: never; }; [CONST.REPORT.ACTIONS.TYPE.REIMBURSEMENT_SETUP]: { - originalMessage?: never + originalMessage?: never; }; [CONST.REPORT.ACTIONS.TYPE.RENAMED]: { originalMessage: OriginalMessageRenamed; }; [CONST.REPORT.ACTIONS.TYPE.REPORT_PREVIEW]: { - originalMessage: OriginalMessageReportPreview + originalMessage: OriginalMessageReportPreview; }; [CONST.REPORT.ACTIONS.TYPE.SELECTED_FOR_RANDOM_AUDIT]: { - originalMessage?: never + originalMessage?: never; }; [CONST.REPORT.ACTIONS.TYPE.SHARE]: { - originalMessage?: never + originalMessage?: never; }; [CONST.REPORT.ACTIONS.TYPE.STRIPE_PAID]: { - originalMessage?: never + originalMessage?: never; }; [CONST.REPORT.ACTIONS.TYPE.SUBMITTED]: { - originalMessage?: never + originalMessage?: never; }; [CONST.REPORT.ACTIONS.TYPE.TASK_CANCELLED]: { - originalMessage?: never + originalMessage?: never; }; [CONST.REPORT.ACTIONS.TYPE.TASK_COMPLETED]: { - originalMessage?: never + originalMessage?: never; }; [CONST.REPORT.ACTIONS.TYPE.TASK_EDITED]: { - originalMessage?: never + originalMessage?: never; }; [CONST.REPORT.ACTIONS.TYPE.TASK_REOPENED]: { - originalMessage?: never + originalMessage?: never; }; [CONST.REPORT.ACTIONS.TYPE.TAKE_CONTROL]: { - originalMessage?: never + originalMessage?: never; }; [CONST.REPORT.ACTIONS.TYPE.UNAPPROVED]: { - originalMessage?: never + originalMessage?: never; }; [CONST.REPORT.ACTIONS.TYPE.UNHOLD]: { - originalMessage?: never + originalMessage?: never; }; [CONST.REPORT.ACTIONS.TYPE.UNSHARE]: { - originalMessage?: never + originalMessage?: never; }; [CONST.REPORT.ACTIONS.TYPE.UPDATE_GROUP_CHAT_MEMBER_ROLE]: { - originalMessage?: never + originalMessage?: never; }; [CONST.REPORT.ACTIONS.TYPE.REIMBURSEMENT_SETUP_REQUESTED]: { - originalMessage?: never + originalMessage?: never; }; } & { [T in ValueOf]: { - originalMessage: OriginalMessageChangeLog + originalMessage: OriginalMessageChangeLog; }; } & { [T in ValueOf]: { @@ -477,4 +477,15 @@ type AssertAllActionsWithHTMLAreListed = AssertTypesEqual< export default OriginalMessage; export {REPORT_ACTIONS_WITH_HTML_MESSAGE}; -export type {ChronosOOOEvent, PaymentMethodType, OriginalMessageSource, ReportActionNamesWithHTMLMessage, Reaction, Decision, OriginalMessageChangeLog, OriginalMessageTemporary}; +export type { + DecisionName, + OriginalMessageIOU, + ChronosOOOEvent, + PaymentMethodType, + OriginalMessageSource, + ReportActionNamesWithHTMLMessage, + Reaction, + Decision, + OriginalMessageChangeLog, + OriginalMessageTemporary, +}; diff --git a/src/types/onyx/ReportAction.ts b/src/types/onyx/ReportAction.ts index c5526828c765..c59db714cae7 100644 --- a/src/types/onyx/ReportAction.ts +++ b/src/types/onyx/ReportAction.ts @@ -1,4 +1,4 @@ -import type {Spread, TupleToUnion, ValueOf} from 'type-fest'; +import type {Spread, ValueOf} from 'type-fest'; import type {FileObject} from '@components/AttachmentModal'; import type {AvatarSource} from '@libs/UserUtils'; import type CONST from '@src/CONST'; @@ -7,7 +7,7 @@ import type CollectionDataSet from '@src/types/utils/CollectionDataSet'; import type {EmptyObject} from '@src/types/utils/EmptyObject'; import type * as OnyxCommon from './OnyxCommon'; import type OriginalMessage from './OriginalMessage'; -import type {Decision, OriginalMessageTemporary, Reaction, ReportActionNamesWithHTMLMessage} from './OriginalMessage'; +import type {Decision, Reaction, ReportActionNamesWithHTMLMessage} from './OriginalMessage'; import type {NotificationPreference} from './Report'; import type ReportActionName from './ReportActionName'; import type {Receipt} from './Transaction'; @@ -226,12 +226,14 @@ type ReportActionBase = OnyxCommon.OnyxValueWithOfflineFeedback<{ adminAccountID?: number; }>; -type ReportAction = ReportActionBase & OriginalMessageTemporary &{ +type ReportAction = ReportActionBase & { + originalMessage?: OriginalMessage; + /** report action message */ - message?: OriginalMessage & Message | Array; + message?: (OriginalMessage & Message) | Array; /** report action message */ - previousMessage?: OriginalMessage & Message | Array; + previousMessage?: (OriginalMessage & Message) | Array; }; type ReportActionWithHTMLMessage = ReportAction; diff --git a/src/types/onyx/ReportActionName.ts b/src/types/onyx/ReportActionName.ts index 08b67db6f84c..4639ab893a98 100644 --- a/src/types/onyx/ReportActionName.ts +++ b/src/types/onyx/ReportActionName.ts @@ -3,4 +3,4 @@ import type DeepValueOf from '@src/types/utils/DeepValueOf'; type ReportActionName = DeepValueOf; -export default ReportActionName; \ No newline at end of file +export default ReportActionName; diff --git a/src/types/onyx/index.ts b/src/types/onyx/index.ts index d0fcae44ef31..3f1d551b5378 100644 --- a/src/types/onyx/index.ts +++ b/src/types/onyx/index.ts @@ -52,7 +52,7 @@ import type RecentlyUsedTags from './RecentlyUsedTags'; import type RecentWaypoint from './RecentWaypoint'; import type ReimbursementAccount from './ReimbursementAccount'; import type Report from './Report'; -import type {ReportActionBase, ReportActions} from './ReportAction'; +import type {ReportActions} from './ReportAction'; import type ReportAction from './ReportAction'; import type ReportActionReactions from './ReportActionReactions'; import type ReportActionsDraft from './ReportActionsDraft'; @@ -174,7 +174,6 @@ export type { RecentlyUsedReportFields, DecisionName, OriginalMessageIOU, - ReportActionBase, LastPaymentMethod, LastSelectedDistanceRates, InvitedEmailsToAccountIDs, diff --git a/tests/actions/IOUTest.ts b/tests/actions/IOUTest.ts index aae355e5ba32..e25d7a5a32c5 100644 --- a/tests/actions/IOUTest.ts +++ b/tests/actions/IOUTest.ts @@ -73,7 +73,7 @@ describe('actions/IOU', () => { const merchant = 'KFC'; let iouReportID: string | undefined; let createdAction: OnyxEntry; - let iouAction: OnyxEntry; + let iouAction: OnyxEntry>; let transactionID: string | undefined; let transactionThread: OnyxEntry; let transactionThreadCreatedAction: OnyxEntry; @@ -126,7 +126,7 @@ describe('actions/IOU', () => { (reportAction) => reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.CREATED, ); const iouActions = Object.values(reportActionsForIOUReport ?? {}).filter( - (reportAction) => ReportActionsUtils.isMoneyRequestAction(reportAction) + (reportAction): reportAction is OnyxTypes.ReportAction => ReportActionsUtils.isMoneyRequestAction(reportAction), ); expect(Object.values(createdActions).length).toBe(1); expect(Object.values(iouActions).length).toBe(1); @@ -208,7 +208,7 @@ describe('actions/IOU', () => { expect(transaction?.pendingAction).toBe(CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD); // The transactionID on the iou action should match the one from the transactions collection - expect(ReportActionsUtils.getOriginalMessage(iouAction)?.IOUTransactionID).toBe(transactionID); + expect(iouAction && ReportActionsUtils.getOriginalMessage(iouAction)?.IOUTransactionID).toBe(transactionID); expect(transaction?.merchant).toBe(merchant); @@ -314,8 +314,8 @@ describe('actions/IOU', () => { iouCreatedAction = Object.values(allIOUReportActions ?? {}).find((reportAction) => reportAction.actionName === CONST.REPORT.ACTIONS.TYPE.CREATED) ?? null; iouAction = - Object.values(allIOUReportActions ?? {}).find( - (reportAction): reportAction is OnyxTypes.ReportAction => ReportActionsUtils.isMoneyRequestAction(reportAction) + Object.values(allIOUReportActions ?? {}).find((reportAction): reportAction is OnyxTypes.ReportAction => + ReportActionsUtils.isMoneyRequestAction(reportAction), ) ?? null; const originalMessage = iouAction ? ReportActionsUtils.getOriginalMessage(iouAction) : null; @@ -355,7 +355,7 @@ describe('actions/IOU', () => { expect(Object.values(allTransactions ?? {}).length).toBe(1); const transaction = Object.values(allTransactions ?? {}).find((t) => !isEmptyObject(t)); transactionID = transaction?.transactionID; - const originalMessage = iouAction ? ReportActionsUtils.getOriginalMessage(iouAction) : null + const originalMessage = iouAction ? ReportActionsUtils.getOriginalMessage(iouAction) : null; // The transaction should be attached to the IOU report expect(transaction?.reportID).toBe(iouReportID); @@ -523,7 +523,7 @@ describe('actions/IOU', () => { const newOriginalMessage = newIOUAction ? ReportActionsUtils.getOriginalMessage(newIOUAction) : null; // The IOUReportID should be correct - expect(ReportActionsUtils.getOriginalMessage(iouAction).IOUReportID).toBe(iouReportID); + expect(ReportActionsUtils.getOriginalMessage(iouAction)?.IOUReportID).toBe(iouReportID); // The comment should be included in the IOU action expect(newOriginalMessage?.comment).toBe(comment); @@ -563,7 +563,9 @@ describe('actions/IOU', () => { expect(newTransaction?.pendingAction).toBe(CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD); // The transactionID on the iou action should match the one from the transactions collection - expect(ReportActionsUtils.isMoneyRequestAction(newIOUAction) ? ReportActionsUtils.getOriginalMessage(newIOUAction)?.IOUTransactionID : '0').toBe(newTransaction?.transactionID); + expect(ReportActionsUtils.isMoneyRequestAction(newIOUAction) ? ReportActionsUtils.getOriginalMessage(newIOUAction)?.IOUTransactionID : '0').toBe( + newTransaction?.transactionID, + ); resolve(); }, @@ -609,7 +611,7 @@ describe('actions/IOU', () => { let chatReportID: string | undefined; let iouReportID: string | undefined; let createdAction: OnyxEntry; - let iouAction: OnyxEntry; + let iouAction: OnyxEntry>; let transactionID: string; let transactionThreadReport: OnyxEntry; let transactionThreadAction: OnyxEntry; @@ -664,13 +666,14 @@ describe('actions/IOU', () => { Object.values(reportActionsForIOUReport ?? {}).filter((reportAction) => reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.CREATED) ?? null; const iouActions = Object.values(reportActionsForIOUReport ?? {}).filter( - (reportAction): reportAction is ReportActionBase & OriginalMessageIOU => reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.IOU, + (reportAction): reportAction is OnyxTypes.ReportAction => + ReportActionsUtils.isMoneyRequestAction(reportAction), ) ?? null; expect(Object.values(createdActions).length).toBe(1); expect(Object.values(iouActions).length).toBe(1); createdAction = createdActions[0]; iouAction = iouActions[0]; - const originalMessage = ReportActionsUtils.getReportActionOriginalMessage(iouAction); + const originalMessage = ReportActionsUtils.getOriginalMessage(iouAction); // The CREATED action should not be created after the IOU action expect(Date.parse(createdAction?.created ?? '')).toBeLessThan(Date.parse(iouAction?.created ?? {})); @@ -717,7 +720,7 @@ describe('actions/IOU', () => { expect(transaction?.pendingAction).toBe(CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD); // The transactionID on the iou action should match the one from the transactions collection - expect(ReportActionsUtils.getOriginalMessage(iouAction)?.IOUTransactionID).toBe(transactionID); + expect(iouAction && ReportActionsUtils.getOriginalMessage(iouAction)?.IOUTransactionID).toBe(transactionID); resolve(); }, @@ -737,7 +740,11 @@ describe('actions/IOU', () => { callback: (reportActionsForIOUReport) => { Onyx.disconnect(connectionID); expect(Object.values(reportActionsForIOUReport ?? {}).length).toBe(2); - iouAction = Object.values(reportActionsForIOUReport ?? {}).find((reportAction) => reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.IOU) ?? null; + iouAction = + Object.values(reportActionsForIOUReport ?? {}).find( + (reportAction): reportAction is OnyxTypes.ReportAction => + ReportActionsUtils.isMoneyRequestAction(reportAction), + ) ?? null; expect(iouAction?.pendingAction).toBe(CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD); resolve(); }, @@ -798,7 +805,10 @@ describe('actions/IOU', () => { waitForCollectionCallback: false, callback: (reportActionsForReport) => { Onyx.disconnect(connectionID); - iouAction = Object.values(reportActionsForReport ?? {}).find((reportAction) => reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.IOU) ?? null; + iouAction = + Object.values(reportActionsForReport ?? {}).find((reportAction): reportAction is OnyxTypes.ReportAction => + ReportActionsUtils.isMoneyRequestAction(reportAction), + ) ?? null; expect(iouAction).toBeFalsy(); resolve(); }, @@ -815,7 +825,10 @@ describe('actions/IOU', () => { waitForCollectionCallback: false, callback: (reportActionsForReport) => { Onyx.disconnect(connectionID); - iouAction = Object.values(reportActionsForReport ?? {}).find((reportAction) => reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.IOU) ?? null; + iouAction = + Object.values(reportActionsForReport ?? {}).find((reportAction): reportAction is OnyxTypes.ReportAction => + ReportActionsUtils.isMoneyRequestAction(reportAction), + ) ?? null; expect(iouAction).toBeFalsy(); resolve(); }, @@ -1000,23 +1013,23 @@ describe('actions/IOU', () => { }; let carlosIOUReport: OnyxEntry; - let carlosIOUAction: OnyxEntry; + let carlosIOUAction: OnyxEntry>; let carlosIOUCreatedAction: OnyxEntry; let carlosTransaction: OnyxEntry; - let julesIOUAction: OnyxEntry; + let julesIOUAction: OnyxEntry>; let julesIOUCreatedAction: OnyxEntry; let julesTransaction: OnyxEntry; let vitChatReport: OnyxEntry; let vitIOUReport: OnyxEntry; let vitCreatedAction: OnyxEntry; - let vitIOUAction: OnyxEntry; + let vitIOUAction: OnyxEntry>; let vitTransaction: OnyxEntry; let groupChat: OnyxEntry; let groupCreatedAction: OnyxEntry; - let groupIOUAction: OnyxEntry; + let groupIOUAction: OnyxEntry>; let groupTransaction: OnyxEntry; const reportCollectionDataSet = toCollectionDataSet(ONYXKEYS.COLLECTION.REPORT, [carlosChatReport, julesChatReport, julesIOUReport], (item) => item.reportID); @@ -1189,19 +1202,20 @@ describe('actions/IOU', () => { expect(Object.values(carlosReportActions ?? {}).length).toBe(2); carlosIOUCreatedAction = Object.values(carlosReportActions ?? {}).find( - (reportAction): reportAction is ReportActionBase & OriginalMessageIOU => reportAction.actionName === CONST.REPORT.ACTIONS.TYPE.CREATED, + (reportAction): reportAction is OnyxTypes.ReportAction => + reportAction.actionName === CONST.REPORT.ACTIONS.TYPE.CREATED, ) ?? null; carlosIOUAction = - Object.values(carlosReportActions ?? {}).find( - (reportAction): reportAction is ReportActionBase & OriginalMessageIOU => reportAction.actionName === CONST.REPORT.ACTIONS.TYPE.IOU, + Object.values(carlosReportActions ?? {}).find((reportAction): reportAction is OnyxTypes.ReportAction => + ReportActionsUtils.isMoneyRequestAction(reportAction), ) ?? null; - const carlosOriginalMessage = ReportActionsUtils.getOriginalMessage(carlosIOUAction); + const carlosOriginalMessage = carlosIOUAction ? ReportActionsUtils.getOriginalMessage(carlosIOUAction) : undefined; expect(carlosIOUAction?.pendingAction).toBe(CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD); - expect(carlosOriginalMessage.IOUReportID).toBe(carlosIOUReport?.reportID); - expect(carlosOriginalMessage.amount).toBe(amount / 4); - expect(carlosOriginalMessage.comment).toBe(comment); - expect(carlosOriginalMessage.type).toBe(CONST.IOU.REPORT_ACTION_TYPE.CREATE); + expect(carlosOriginalMessage?.IOUReportID).toBe(carlosIOUReport?.reportID); + expect(carlosOriginalMessage?.amount).toBe(amount / 4); + expect(carlosOriginalMessage?.comment).toBe(comment); + expect(carlosOriginalMessage?.type).toBe(CONST.IOU.REPORT_ACTION_TYPE.CREATE); expect(Date.parse(carlosIOUCreatedAction?.created ?? '')).toBeLessThan(Date.parse(carlosIOUAction?.created ?? '')); // Jules DM should have three reportActions, the existing CREATED action, the existing IOU action, and a new pending IOU action @@ -1209,40 +1223,42 @@ describe('actions/IOU', () => { expect(julesReportActions?.[julesCreatedAction.reportActionID]).toStrictEqual(julesCreatedAction); julesIOUCreatedAction = Object.values(julesReportActions ?? {}).find( - (reportAction): reportAction is ReportActionBase & OriginalMessageIOU => reportAction.actionName === CONST.REPORT.ACTIONS.TYPE.CREATED, + (reportAction): reportAction is OnyxTypes.ReportAction => + reportAction.actionName === CONST.REPORT.ACTIONS.TYPE.CREATED, ) ?? null; julesIOUAction = Object.values(julesReportActions ?? {}).find( - (reportAction): reportAction is ReportActionBase & OriginalMessageIOU => + (reportAction): reportAction is OnyxTypes.ReportAction => reportAction.reportActionID !== julesCreatedAction.reportActionID && reportAction.reportActionID !== julesExistingIOUAction.reportActionID, ) ?? null; - const julesOriginalMessage = ReportActionsUtils.getOriginalMessage(julesIOUAction); + const julesOriginalMessage = julesIOUAction ? ReportActionsUtils.getOriginalMessage(julesIOUAction) : undefined; expect(julesIOUAction?.pendingAction).toBe(CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD); - expect(julesOriginalMessage.IOUReportID).toBe(julesIOUReport?.reportID); - expect(julesOriginalMessage.amount).toBe(amount / 4); - expect(julesOriginalMessage.comment).toBe(comment); - expect(julesOriginalMessage.type).toBe(CONST.IOU.REPORT_ACTION_TYPE.CREATE); + expect(julesOriginalMessage?.IOUReportID).toBe(julesIOUReport?.reportID); + expect(julesOriginalMessage?.amount).toBe(amount / 4); + expect(julesOriginalMessage?.comment).toBe(comment); + expect(julesOriginalMessage?.type).toBe(CONST.IOU.REPORT_ACTION_TYPE.CREATE); expect(Date.parse(julesIOUCreatedAction?.created ?? '')).toBeLessThan(Date.parse(julesIOUAction?.created ?? '')); // Vit DM should have two reportActions – a pending CREATED action and a pending IOU action expect(Object.values(vitReportActions ?? {}).length).toBe(2); vitCreatedAction = Object.values(vitReportActions ?? {}).find( - (reportAction): reportAction is ReportActionBase & OriginalMessageIOU => reportAction.actionName === CONST.REPORT.ACTIONS.TYPE.CREATED, + (reportAction): reportAction is OnyxTypes.ReportAction => + reportAction.actionName === CONST.REPORT.ACTIONS.TYPE.CREATED, ) ?? null; vitIOUAction = - Object.values(vitReportActions ?? {}).find( - (reportAction): reportAction is ReportActionBase & OriginalMessageIOU => reportAction.actionName === CONST.REPORT.ACTIONS.TYPE.IOU, + Object.values(vitReportActions ?? {}).find((reportAction): reportAction is OnyxTypes.ReportAction => + ReportActionsUtils.isMoneyRequestAction(reportAction), ) ?? null; - const vitOriginalMessage = ReportActionsUtils.getOriginalMessage(vitIOUAction); + const vitOriginalMessage = vitIOUAction ? ReportActionsUtils.getOriginalMessage(vitIOUAction) : undefined; expect(vitCreatedAction?.pendingAction).toBe(CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD); expect(vitIOUAction?.pendingAction).toBe(CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD); - expect(vitOriginalMessage.IOUReportID).toBe(vitIOUReport?.reportID); - expect(vitOriginalMessage.amount).toBe(amount / 4); - expect(vitOriginalMessage.comment).toBe(comment); - expect(vitOriginalMessage.type).toBe(CONST.IOU.REPORT_ACTION_TYPE.CREATE); + expect(vitOriginalMessage?.IOUReportID).toBe(vitIOUReport?.reportID); + expect(vitOriginalMessage?.amount).toBe(amount / 4); + expect(vitOriginalMessage?.comment).toBe(comment); + expect(vitOriginalMessage?.type).toBe(CONST.IOU.REPORT_ACTION_TYPE.CREATE); expect(Date.parse(vitCreatedAction?.created ?? '')).toBeLessThan(Date.parse(vitIOUAction?.created ?? '')); // Group chat should have two reportActions – a pending CREATED action and a pending IOU action w/ type SPLIT @@ -1250,10 +1266,10 @@ describe('actions/IOU', () => { groupCreatedAction = Object.values(groupReportActions ?? {}).find((reportAction) => reportAction.actionName === CONST.REPORT.ACTIONS.TYPE.CREATED) ?? null; groupIOUAction = - Object.values(groupReportActions ?? {}).find( - (reportAction): reportAction is ReportActionBase & OriginalMessageIOU => reportAction.actionName === CONST.REPORT.ACTIONS.TYPE.IOU, + Object.values(groupReportActions ?? {}).find((reportAction): reportAction is OnyxTypes.ReportAction => + ReportActionsUtils.isMoneyRequestAction(reportAction), ) ?? null; - const groupOriginalMessage = ReportActionsUtils.getOriginalMessage(groupIOUAction); + const groupOriginalMessage = groupIOUAction ? ReportActionsUtils.getOriginalMessage(groupIOUAction) : undefined; expect(groupCreatedAction?.pendingAction).toBe(CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD); expect(groupIOUAction?.pendingAction).toBe(CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD); @@ -1285,15 +1301,15 @@ describe('actions/IOU', () => { carlosTransaction = Object.values(allTransactions ?? {}).find( - (transaction) => transaction?.transactionID === ReportActionsUtils.getOriginalMessage(carlosIOUAction)?.IOUTransactionID, + (transaction) => carlosIOUAction && transaction?.transactionID === ReportActionsUtils.getOriginalMessage(carlosIOUAction)?.IOUTransactionID, ) ?? null; julesTransaction = Object.values(allTransactions ?? {}).find( - (transaction) => transaction?.transactionID === ReportActionsUtils.getOriginalMessage(julesIOUAction)?.IOUTransactionID, + (transaction) => julesIOUAction && transaction?.transactionID === ReportActionsUtils.getOriginalMessage(julesIOUAction)?.IOUTransactionID, ) ?? null; vitTransaction = Object.values(allTransactions ?? {}).find( - (transaction) => transaction?.transactionID === ReportActionsUtils.getOriginalMessage(vitIOUAction)?.IOUTransactionID, + (transaction) => vitIOUAction && transaction?.transactionID === ReportActionsUtils.getOriginalMessage(vitIOUAction)?.IOUTransactionID, ) ?? null; groupTransaction = Object.values(allTransactions ?? {}).find((transaction) => transaction?.reportID === CONST.REPORT.SPLIT_REPORTID) ?? null; @@ -1413,7 +1429,7 @@ describe('actions/IOU', () => { const comment = 'Giv money plz'; let chatReport: OnyxEntry; let iouReport: OnyxEntry; - let createIOUAction: OnyxEntry; + let createIOUAction: OnyxEntry>; let payIOUAction: OnyxEntry; let transaction: OnyxEntry; IOU.requestMoney({reportID: ''}, amount, CONST.CURRENCY.USD, '', '', RORY_EMAIL, RORY_ACCOUNT_ID, {login: CARLOS_EMAIL, accountID: CARLOS_ACCOUNT_ID}, comment, {}); @@ -1463,9 +1479,11 @@ describe('actions/IOU', () => { const reportActionsForIOUReport = allReportActions?.[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chatReport?.iouReportID}`]; createIOUAction = - Object.values(reportActionsForIOUReport ?? {}).find((reportAction) => reportAction.actionName === CONST.REPORT.ACTIONS.TYPE.IOU) ?? null; + Object.values(reportActionsForIOUReport ?? {}).find((reportAction): reportAction is OnyxTypes.ReportAction => + ReportActionsUtils.isMoneyRequestAction(reportAction), + ) ?? null; expect(createIOUAction).toBeTruthy(); - expect(ReportActionsUtils.getOriginalMessage(createIOUAction)?.IOUReportID).toBe(iouReport?.reportID); + expect(createIOUAction && ReportActionsUtils.getOriginalMessage(createIOUAction)?.IOUReportID).toBe(iouReport?.reportID); resolve(); }, @@ -1485,7 +1503,7 @@ describe('actions/IOU', () => { expect(transaction).toBeTruthy(); expect(transaction?.amount).toBe(amount); expect(transaction?.reportID).toBe(iouReport?.reportID); - expect(ReportActionsUtils.getOriginalMessage(createIOUAction)?.IOUTransactionID).toBe(transaction?.transactionID); + expect(createIOUAction && ReportActionsUtils.getOriginalMessage(createIOUAction)?.IOUTransactionID).toBe(transaction?.transactionID); resolve(); }, }); @@ -1537,8 +1555,8 @@ describe('actions/IOU', () => { payIOUAction = Object.values(reportActionsForIOUReport ?? {}).find( (reportAction) => - reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.IOU && - ReportActionsUtils.getOriginalMessage(reportAction)?.type === CONST.IOU.REPORT_ACTION_TYPE.PAY, + ReportActionsUtils.isMoneyRequestAction(reportAction) && + ReportActionsUtils.getOriginalMessage(reportAction)?.type === CONST.IOU.REPORT_ACTION_TYPE.PAY, ) ?? null; expect(payIOUAction).toBeTruthy(); expect(payIOUAction?.pendingAction).toBe(CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD); @@ -1588,8 +1606,8 @@ describe('actions/IOU', () => { payIOUAction = Object.values(reportActionsForIOUReport ?? {}).find( (reportAction) => - reportAction.actionName === CONST.REPORT.ACTIONS.TYPE.IOU && - ReportActionsUtils.getOriginalMessage(reportAction).type === CONST.IOU.REPORT_ACTION_TYPE.PAY, + ReportActionsUtils.isMoneyRequestAction(reportAction) && + ReportActionsUtils.getOriginalMessage(reportAction)?.type === CONST.IOU.REPORT_ACTION_TYPE.PAY, ) ?? null; expect(payIOUAction).toBeTruthy(); @@ -1613,7 +1631,7 @@ describe('actions/IOU', () => { it('updates the IOU request and IOU report when offline', () => { let thread: OptimisticChatReport; let iouReport: OnyxEntry = null; - let iouAction: OnyxEntry = null; + let iouAction: OnyxEntry> = null; let transaction: OnyxEntry = null; mockFetch?.pause?.(); @@ -1647,7 +1665,9 @@ describe('actions/IOU', () => { callback: (reportActionsForIOUReport) => { Onyx.disconnect(connectionID); - [iouAction] = Object.values(reportActionsForIOUReport ?? {}).filter((reportAction) => reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.IOU); + [iouAction] = Object.values(reportActionsForIOUReport ?? {}).filter( + (reportAction): reportAction is OnyxTypes.ReportAction => ReportActionsUtils.isMoneyRequestAction(reportAction), + ); resolve(); }, }); @@ -1721,7 +1741,7 @@ describe('actions/IOU', () => { Onyx.disconnect(connectionID); const updatedAction = Object.values(allActions ?? {}).find((reportAction) => !isEmptyObject(reportAction)); expect(updatedAction?.actionName).toEqual('MODIFIEDEXPENSE'); - expect(ReportActionsUtils.getReportActionOriginalMessage(updatedAction)).toEqual( + expect(updatedAction && ReportActionsUtils.getOriginalMessage(updatedAction)).toEqual( expect.objectContaining({amount: 20000, newComment: 'Double the amount!', oldAmount: amount, oldComment: comment}), ); resolve(); @@ -1766,7 +1786,7 @@ describe('actions/IOU', () => { it('resets the IOU request and IOU report when api returns an error', () => { let thread: OptimisticChatReport; let iouReport: OnyxEntry; - let iouAction: OnyxEntry; + let iouAction: OnyxEntry>; let transaction: OnyxEntry; IOU.requestMoney({reportID: ''}, amount, CONST.CURRENCY.USD, '', merchant, RORY_EMAIL, RORY_ACCOUNT_ID, {login: CARLOS_EMAIL, accountID: CARLOS_ACCOUNT_ID}, comment, {}); @@ -1798,7 +1818,9 @@ describe('actions/IOU', () => { callback: (reportActionsForIOUReport) => { Onyx.disconnect(connectionID); - [iouAction] = Object.values(reportActionsForIOUReport ?? {}).filter((reportAction) => reportAction.actionName === CONST.REPORT.ACTIONS.TYPE.IOU); + [iouAction] = Object.values(reportActionsForIOUReport ?? {}).filter( + (reportAction): reportAction is OnyxTypes.ReportAction => ReportActionsUtils.isMoneyRequestAction(reportAction), + ); resolve(); }, }); @@ -2111,7 +2133,7 @@ describe('actions/IOU', () => { const comment = 'Send me money please'; let chatReport: OnyxEntry; let iouReport: OnyxEntry; - let createIOUAction: OnyxEntry; + let createIOUAction: OnyxEntry>; let transaction: OnyxEntry; let thread: OptimisticChatReport; const TEST_USER_ACCOUNT_ID = 1; @@ -2202,11 +2224,11 @@ describe('actions/IOU', () => { // Then we should find an IOU action with specific properties const reportActionsForIOUReport = allReportActions?.[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chatReport?.iouReportID}`]; createIOUAction = - Object.values(reportActionsForIOUReport ?? {}).find( - (reportAction): reportAction is ReportActionBase & OriginalMessageIOU => reportAction.actionName === CONST.REPORT.ACTIONS.TYPE.IOU, + Object.values(reportActionsForIOUReport ?? {}).find((reportAction): reportAction is OnyxTypes.ReportAction => + ReportActionsUtils.isMoneyRequestAction(reportAction), ) ?? null; expect(createIOUAction).toBeTruthy(); - expect(ReportActionsUtils.getOriginalMessage(createIOUAction).IOUReportID).toBe(iouReport?.reportID); + expect(createIOUAction && ReportActionsUtils.getOriginalMessage(createIOUAction)?.IOUReportID).toBe(iouReport?.reportID); // When fetching all transactions from Onyx const allTransactions = await new Promise>((resolve) => { @@ -2225,7 +2247,7 @@ describe('actions/IOU', () => { expect(transaction).toBeTruthy(); expect(transaction?.amount).toBe(amount); expect(transaction?.reportID).toBe(iouReport?.reportID); - expect(ReportActionsUtils.getOriginalMessage(createIOUAction).IOUTransactionID).toBe(transaction?.transactionID); + expect(createIOUAction && ReportActionsUtils.getOriginalMessage(createIOUAction)?.IOUTransactionID).toBe(transaction?.transactionID); }); afterEach(PusherHelper.teardown); @@ -2252,7 +2274,10 @@ describe('actions/IOU', () => { }); }); - createIOUAction = Object.values(reportActionsForReport ?? {}).find((reportAction) => reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.IOU) ?? null; + createIOUAction = + Object.values(reportActionsForReport ?? {}).find((reportAction): reportAction is OnyxTypes.ReportAction => + ReportActionsUtils.isMoneyRequestAction(reportAction), + ) ?? null; // Then the IOU Action should be truthy for offline support. expect(createIOUAction).toBeTruthy(); @@ -2286,7 +2311,10 @@ describe('actions/IOU', () => { }); }); - createIOUAction = Object.values(reportActionsForReport ?? {}).find((reportAction) => reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.IOU) ?? null; + createIOUAction = + Object.values(reportActionsForReport ?? {}).find((reportAction): reportAction is OnyxTypes.ReportAction => + ReportActionsUtils.isMoneyRequestAction(reportAction), + ) ?? null; expect(createIOUAction).toBeFalsy(); // Then we recheck the transaction from the transactions collection @@ -2465,7 +2493,10 @@ describe('actions/IOU', () => { }); }); const reportActionsForIOUReport = allReportActions?.[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chatReport?.iouReportID}`]; - createIOUAction = Object.values(reportActionsForIOUReport ?? {}).find((reportAction) => reportAction.actionName === CONST.REPORT.ACTIONS.TYPE.IOU) ?? null; + createIOUAction = + Object.values(reportActionsForIOUReport ?? {}).find((reportAction): reportAction is OnyxTypes.ReportAction => + ReportActionsUtils.isMoneyRequestAction(reportAction), + ) ?? null; expect(createIOUAction?.childReportID).toBe(thread.reportID); await waitForBatchedUpdates(); @@ -2547,7 +2578,10 @@ describe('actions/IOU', () => { }); }); const reportActionsForIOUReport = allReportActions?.[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chatReport?.iouReportID}`]; - createIOUAction = Object.values(reportActionsForIOUReport ?? {}).find((reportAction) => reportAction.actionName === CONST.REPORT.ACTIONS.TYPE.IOU) ?? null; + createIOUAction = + Object.values(reportActionsForIOUReport ?? {}).find((reportAction): reportAction is OnyxTypes.ReportAction => + ReportActionsUtils.isMoneyRequestAction(reportAction), + ) ?? null; expect(createIOUAction?.childReportID).toBe(thread.reportID); await waitForBatchedUpdates(); @@ -2583,7 +2617,10 @@ describe('actions/IOU', () => { waitForCollectionCallback: false, callback: (reportActionsForReport) => { Onyx.disconnect(connectionID); - createIOUAction = Object.values(reportActionsForReport ?? {}).find((reportAction) => reportAction.actionName === CONST.REPORT.ACTIONS.TYPE.IOU) ?? null; + createIOUAction = + Object.values(reportActionsForReport ?? {}).find((reportAction): reportAction is OnyxTypes.ReportAction => + ReportActionsUtils.isMoneyRequestAction(reportAction), + ) ?? null; resolve(); }, }); @@ -2732,7 +2769,10 @@ describe('actions/IOU', () => { }); const reportActionsForIOUReport = allReportActions?.[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chatReport?.iouReportID}`]; - createIOUAction = Object.values(reportActionsForIOUReport ?? {}).find((reportAction) => reportAction.actionName === CONST.REPORT.ACTIONS.TYPE.IOU) ?? null; + createIOUAction = + Object.values(reportActionsForIOUReport ?? {}).find((reportAction): reportAction is OnyxTypes.ReportAction => + ReportActionsUtils.isMoneyRequestAction(reportAction), + ) ?? null; expect(createIOUAction?.childReportID).toBe(thread.reportID); await waitForBatchedUpdates(); @@ -2752,7 +2792,10 @@ describe('actions/IOU', () => { waitForCollectionCallback: false, callback: (reportActionsForReport) => { Onyx.disconnect(connectionID); - createIOUAction = Object.values(reportActionsForReport ?? {}).find((reportAction) => reportAction.actionName === CONST.REPORT.ACTIONS.TYPE.IOU) ?? null; + createIOUAction = + Object.values(reportActionsForReport ?? {}).find((reportAction): reportAction is OnyxTypes.ReportAction => + ReportActionsUtils.isMoneyRequestAction(reportAction), + ) ?? null; resolve(); }, }); @@ -2822,7 +2865,10 @@ describe('actions/IOU', () => { waitForCollectionCallback: false, callback: (reportActionsForReport) => { Onyx.disconnect(connectionID); - createIOUAction = Object.values(reportActionsForReport ?? {}).find((reportAction) => reportAction.actionName === CONST.REPORT.ACTIONS.TYPE.IOU) ?? null; + createIOUAction = + Object.values(reportActionsForReport ?? {}).find((reportAction): reportAction is OnyxTypes.ReportAction => + ReportActionsUtils.isMoneyRequestAction(reportAction), + ) ?? null; expect(ReportActionsUtils.getReportActionMessage(createIOUAction)?.isDeletedParentAction).toBeTruthy(); resolve(); }, @@ -2840,7 +2886,10 @@ describe('actions/IOU', () => { waitForCollectionCallback: false, callback: (reportActionsForReport) => { Onyx.disconnect(connectionID); - createIOUAction = Object.values(reportActionsForReport ?? {}).find((reportAction) => reportAction.actionName === CONST.REPORT.ACTIONS.TYPE.IOU) ?? null; + createIOUAction = + Object.values(reportActionsForReport ?? {}).find((reportAction): reportAction is OnyxTypes.ReportAction => + ReportActionsUtils.isMoneyRequestAction(reportAction), + ) ?? null; expect(ReportActionsUtils.getReportActionMessage(createIOUAction)?.isDeletedParentAction).toBeTruthy(); resolve(); }, @@ -2963,7 +3012,10 @@ describe('actions/IOU', () => { }); const reportActionsForIOUReport = allReportActions?.[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chatReport?.iouReportID}`]; - createIOUAction = Object.values(reportActionsForIOUReport ?? {}).find((reportAction) => reportAction.actionName === CONST.REPORT.ACTIONS.TYPE.IOU) ?? null; + createIOUAction = + Object.values(reportActionsForIOUReport ?? {}).find((reportAction): reportAction is OnyxTypes.ReportAction => + ReportActionsUtils.isMoneyRequestAction(reportAction), + ) ?? null; expect(createIOUAction?.childReportID).toBe(thread.reportID); await waitForBatchedUpdates(); diff --git a/tests/actions/PolicyMemberTest.ts b/tests/actions/PolicyMemberTest.ts index 2642c823469b..f432664b1116 100644 --- a/tests/actions/PolicyMemberTest.ts +++ b/tests/actions/PolicyMemberTest.ts @@ -5,7 +5,6 @@ import * as Policy from '@src/libs/actions/Policy/Policy'; import * as ReportActionsUtils from '@src/libs/ReportActionsUtils'; import ONYXKEYS from '@src/ONYXKEYS'; import type {Policy as PolicyType, Report, ReportAction} from '@src/types/onyx'; -import type {OriginalMessageJoinPolicyChangeLog} from '@src/types/onyx/OriginalMessage'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; import createPersonalDetails from '../utils/collections/personalDetails'; import createRandomPolicy from '../utils/collections/policies'; @@ -37,10 +36,10 @@ describe('actions/PolicyMember', () => { ...createRandomReport(0), policyID: fakePolicy.id, }; - const fakeReportAction: ReportAction = { + const fakeReportAction = { ...createRandomReportAction(0), actionName: CONST.REPORT.ACTIONS.TYPE.ACTIONABLE_JOIN_REQUEST, - } as ReportAction; + } as ReportAction; mockFetch?.pause?.(); Onyx.set(`${ONYXKEYS.COLLECTION.POLICY}${fakePolicy.id}`, fakePolicy); @@ -57,12 +56,10 @@ describe('actions/PolicyMember', () => { callback: (reportActions) => { Onyx.disconnect(connectionID); - const reportAction = reportActions?.[fakeReportAction.reportActionID]; + const reportAction = reportActions?.[fakeReportAction.reportActionID] as ReportAction; if (!isEmptyObject(reportAction)) { - expect(ReportActionsUtils.getReportActionOriginalMessage(reportAction)?.choice)?.toBe( - CONST.REPORT.ACTIONABLE_MENTION_JOIN_WORKSPACE_RESOLUTION.ACCEPT, - ); + expect(ReportActionsUtils.getOriginalMessage(reportAction)?.choice)?.toBe(CONST.REPORT.ACTIONABLE_MENTION_JOIN_WORKSPACE_RESOLUTION.ACCEPT); expect(reportAction?.pendingAction).toBe(CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE); } resolve(); diff --git a/tests/unit/ReportUtilsTest.ts b/tests/unit/ReportUtilsTest.ts index 81d8bd8357f0..1ee6d9196b51 100644 --- a/tests/unit/ReportUtilsTest.ts +++ b/tests/unit/ReportUtilsTest.ts @@ -5,7 +5,6 @@ import * as ReportUtils from '@libs/ReportUtils'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import type {PersonalDetailsList, Policy, Report, ReportAction} from '@src/types/onyx'; -import type {ModifiedExpenseAction} from '@src/types/onyx/ReportAction'; import {toCollectionDataSet} from '@src/types/utils/CollectionDataSet'; import * as NumberUtils from '../../src/libs/NumberUtils'; import * as LHNTestUtils from '../utils/LHNTestUtils'; @@ -766,7 +765,7 @@ describe('ReportUtils', () => { originalMessage: { whisperedTo: [123456], }, - } as ModifiedExpenseAction; + } as ReportAction; expect(ReportUtils.shouldDisableThread(reportAction, reportID)).toBeTruthy(); }); diff --git a/tests/utils/LHNTestUtils.tsx b/tests/utils/LHNTestUtils.tsx index d35eb61feb35..a6729df6ca7d 100644 --- a/tests/utils/LHNTestUtils.tsx +++ b/tests/utils/LHNTestUtils.tsx @@ -15,7 +15,7 @@ import ReportActionItemSingle from '@pages/home/report/ReportActionItemSingle'; import SidebarLinksData from '@pages/home/sidebar/SidebarLinksData'; import CONST from '@src/CONST'; import type {PersonalDetailsList, Policy, Report, ReportAction} from '@src/types/onyx'; -import type {ActionName} from '@src/types/onyx/OriginalMessage'; +import type ReportActionName from '@src/types/onyx/ReportActionName'; type MockedReportActionItemSingleProps = { /** Determines if the avatar is displayed as a subscript (positioned lower than normal) */ @@ -184,18 +184,6 @@ function getFakeReportAction(actor = 'email1@test.com', millisecondsInThePast = originalMessage: { whisperedTo: [], childReportID: `${reportActionID}`, - emojiReactions: { - heart: { - createdAt: '2023-08-28 15:27:52', - users: { - 1: { - skinTones: { - '-1': '2023-08-28 15:27:52', - }, - }, - }, - }, - }, html: 'hey', lastModified: '2023-08-28 15:28:12.432', reactions: [ @@ -270,7 +258,7 @@ function getFakePolicy(id = '1', name = 'Workspace-Test-001'): Policy { /** * @param millisecondsInThePast the number of milliseconds in the past for the last message timestamp (to order reports by most recent messages) */ -function getFakeAdvancedReportAction(actionName: ActionName = 'IOU', actor = 'email1@test.com', millisecondsInThePast = 0): ReportAction { +function getFakeAdvancedReportAction(actionName: ReportActionName = 'IOU', actor = 'email1@test.com', millisecondsInThePast = 0): ReportAction { return { ...getFakeReportAction(actor, millisecondsInThePast), actionName, diff --git a/tests/utils/ReportTestUtils.ts b/tests/utils/ReportTestUtils.ts index b9dc50aecec0..e365db9834d0 100644 --- a/tests/utils/ReportTestUtils.ts +++ b/tests/utils/ReportTestUtils.ts @@ -1,10 +1,10 @@ import type {ReportAction, ReportActions} from '@src/types/onyx'; -import type {ActionName} from '@src/types/onyx/OriginalMessage'; +import type ReportActionName from '@src/types/onyx/ReportActionName'; import createRandomReportAction from './collections/reportActions'; -const actionNames: ActionName[] = ['ADDCOMMENT', 'IOU', 'REPORTPREVIEW', 'CLOSED']; +const actionNames: ReportActionName[] = ['ADDCOMMENT', 'IOU', 'REPORTPREVIEW', 'CLOSED']; -const getFakeReportAction = (index: number, actionName?: ActionName): ReportAction => +const getFakeReportAction = (index: number, actionName?: ReportActionName): ReportAction => ({ actionName, actorAccountID: index, @@ -50,14 +50,14 @@ const getFakeReportAction = (index: number, actionName?: ActionName): ReportActi const getMockedSortedReportActions = (length = 100): ReportAction[] => Array.from({length}, (element, index): ReportAction => { - const actionName: ActionName = index === 0 ? 'CREATED' : 'ADDCOMMENT'; + const actionName: ReportActionName = index === 0 ? 'CREATED' : 'ADDCOMMENT'; return getFakeReportAction(index + 1, actionName); }).reverse(); const getMockedReportActionsMap = (length = 100): ReportActions => { const mockReports: ReportActions[] = Array.from({length}, (element, index): ReportActions => { const reportID = index + 1; - const actionName: ActionName = index === 0 ? 'CREATED' : actionNames[index % actionNames.length]; + const actionName: ReportActionName = index === 0 ? 'CREATED' : actionNames[index % actionNames.length]; const reportAction = { ...createRandomReportAction(reportID), actionName, diff --git a/tests/utils/collections/reportActions.ts b/tests/utils/collections/reportActions.ts index 6dd82c3134ab..8289e2f3f639 100644 --- a/tests/utils/collections/reportActions.ts +++ b/tests/utils/collections/reportActions.ts @@ -2,11 +2,11 @@ import {rand, randAggregation, randBoolean, randWord} from '@ngneat/falso'; import {format} from 'date-fns'; import CONST from '@src/CONST'; import type {ReportAction} from '@src/types/onyx'; -import type {ActionName} from '@src/types/onyx/OriginalMessage'; +import type ReportActionName from '@src/types/onyx/ReportActionName'; import type DeepRecord from '@src/types/utils/DeepRecord'; -const flattenActionNamesValues = (actionNames: DeepRecord) => { - let result: ActionName[] = []; +const flattenActionNamesValues = (actionNames: DeepRecord) => { + let result: ReportActionName[] = []; Object.values(actionNames).forEach((value) => { if (typeof value === 'object') { result = result.concat(flattenActionNamesValues(value)); @@ -26,7 +26,7 @@ const getRandomDate = (): string => { return formattedDate; }; -const deprecatedReportActions: ActionName[] = [ +const deprecatedReportActions: ReportActionName[] = [ CONST.REPORT.ACTIONS.TYPE.DELETED_ACCOUNT, CONST.REPORT.ACTIONS.TYPE.REIMBURSEMENT_REQUESTED, CONST.REPORT.ACTIONS.TYPE.REIMBURSEMENT_SETUP_REQUESTED, @@ -37,7 +37,7 @@ export default function createRandomReportAction(index: number): ReportAction { return { // we need to add any here because of the way we are generating random values // eslint-disable-next-line @typescript-eslint/no-explicit-any - actionName: rand(flattenActionNamesValues(CONST.REPORT.ACTIONS.TYPE).filter((actionType: ActionName) => !deprecatedReportActions.includes(actionType))) as any, + actionName: rand(flattenActionNamesValues(CONST.REPORT.ACTIONS.TYPE).filter((actionType: ReportActionName) => !deprecatedReportActions.includes(actionType))) as any, reportActionID: index.toString(), previousReportActionID: (index === 0 ? 0 : index - 1).toString(), actorAccountID: index, From 2c7649f56a6b698c13830d255da3cc9390a9e023 Mon Sep 17 00:00:00 2001 From: nkdengineer Date: Tue, 4 Jun 2024 19:28:22 +0700 Subject: [PATCH 21/45] remove unnecessary type --- src/types/onyx/OriginalMessage.ts | 193 +----------------------------- 1 file changed, 1 insertion(+), 192 deletions(-) diff --git a/src/types/onyx/OriginalMessage.ts b/src/types/onyx/OriginalMessage.ts index a56d47854e91..0effe84d5d78 100644 --- a/src/types/onyx/OriginalMessage.ts +++ b/src/types/onyx/OriginalMessage.ts @@ -210,185 +210,6 @@ type OriginalMessageDismissedViolation = { violationName: string; }; -type OriginalMessageMap1 = { - [CONST.REPORT.ACTIONS.TYPE.ACTIONABLE_JOIN_REQUEST]: { - originalMessage: OriginalMessageJoinPolicyChangeLog; - }; - [CONST.REPORT.ACTIONS.TYPE.ACTIONABLE_MENTION_WHISPER]: { - originalMessage: OriginalMessageActionableMentionWhisper; - }; - [CONST.REPORT.ACTIONS.TYPE.ACTIONABLE_REPORT_MENTION_WHISPER]: { - originalMessage: OriginalMessageActionableReportMentionWhisper; - }; - [CONST.REPORT.ACTIONS.TYPE.ACTIONABLE_TRACK_EXPENSE_WHISPER]: { - originalMessage: OriginalMessageActionableTrackedExpenseWhisper; - }; - [CONST.REPORT.ACTIONS.TYPE.ADD_COMMENT]: { - originalMessage: OriginalMessageAddComment; - }; - [CONST.REPORT.ACTIONS.TYPE.APPROVED]: { - originalMessage?: never; - }; - [CONST.REPORT.ACTIONS.TYPE.CHANGE_FIELD]: { - originalMessage?: never; - }; - [CONST.REPORT.ACTIONS.TYPE.CHANGE_POLICY]: { - originalMessage?: never; - }; - [CONST.REPORT.ACTIONS.TYPE.CHANGE_TYPE]: { - originalMessage?: never; - }; - [CONST.REPORT.ACTIONS.TYPE.CHRONOS_OOO_LIST]: { - originalMessage: OriginalMessageChronosOOOList; - }; - [CONST.REPORT.ACTIONS.TYPE.CLOSED]: { - originalMessage: OriginalMessageClosed; - }; - [CONST.REPORT.ACTIONS.TYPE.CREATED]: { - originalMessage?: never; - }; - [CONST.REPORT.ACTIONS.TYPE.DELEGATE_SUBMIT]: { - originalMessage?: never; - }; - [CONST.REPORT.ACTIONS.TYPE.DELETED_ACCOUNT]: { - originalMessage?: never; - }; - [CONST.REPORT.ACTIONS.TYPE.DISMISSED_VIOLATION]: { - originalMessage: OriginalMessageDismissedViolation; - }; - [CONST.REPORT.ACTIONS.TYPE.DONATION]: { - originalMessage?: never; - }; - [CONST.REPORT.ACTIONS.TYPE.EXPORTED_TO_CSV]: { - originalMessage?: never; - }; - [CONST.REPORT.ACTIONS.TYPE.EXPORTED_TO_INTEGRATION]: { - originalMessage?: never; - }; - [CONST.REPORT.ACTIONS.TYPE.EXPORTED_TO_QUICK_BOOKS]: { - originalMessage?: never; - }; - [CONST.REPORT.ACTIONS.TYPE.FORWARDED]: { - originalMessage?: never; - }; - [CONST.REPORT.ACTIONS.TYPE.HOLD]: { - originalMessage?: never; - }; - [CONST.REPORT.ACTIONS.TYPE.HOLD_COMMENT]: { - originalMessage?: never; - }; - [CONST.REPORT.ACTIONS.TYPE.INTEGRATIONS_MESSAGE]: { - originalMessage?: never; - }; - [CONST.REPORT.ACTIONS.TYPE.IOU]: { - originalMessage: OriginalMessageIOU; - }; - [CONST.REPORT.ACTIONS.TYPE.MANAGER_ATTACH_RECEIPT]: { - originalMessage?: never; - }; - [CONST.REPORT.ACTIONS.TYPE.MANAGER_DETACH_RECEIPT]: { - originalMessage?: never; - }; - [CONST.REPORT.ACTIONS.TYPE.MARK_REIMBURSED_FROM_INTEGRATION]: { - originalMessage?: never; - }; - [CONST.REPORT.ACTIONS.TYPE.MARKED_REIMBURSED]: { - originalMessage?: never; - }; - [CONST.REPORT.ACTIONS.TYPE.MERGED_WITH_CASH_TRANSACTION]: { - originalMessage?: never; - }; - [CONST.REPORT.ACTIONS.TYPE.MODIFIED_EXPENSE]: { - originalMessage: OriginalMessageModifiedExpense; - }; - [CONST.REPORT.ACTIONS.TYPE.MOVED]: { - originalMessage: OriginalMessageMoved; - }; - [CONST.REPORT.ACTIONS.TYPE.OUTDATED_BANK_ACCOUNT]: { - originalMessage?: never; - }; - [CONST.REPORT.ACTIONS.TYPE.REIMBURSEMENT_ACH_BOUNCE]: { - originalMessage?: never; - }; - [CONST.REPORT.ACTIONS.TYPE.REIMBURSEMENT_ACH_CANCELLED]: { - originalMessage?: never; - }; - [CONST.REPORT.ACTIONS.TYPE.REIMBURSEMENT_ACCOUNT_CHANGED]: { - originalMessage?: never; - }; - [CONST.REPORT.ACTIONS.TYPE.REIMBURSEMENT_DEQUEUED]: { - originalMessage: OriginalMessageReimbursementDequeued; - }; - [CONST.REPORT.ACTIONS.TYPE.REIMBURSEMENT_DELAYED]: { - originalMessage?: never; - }; - [CONST.REPORT.ACTIONS.TYPE.REIMBURSEMENT_QUEUED]: { - originalMessage: OriginalMessageReimbursementQueued; - }; - [CONST.REPORT.ACTIONS.TYPE.REIMBURSEMENT_REQUESTED]: { - originalMessage?: never; - }; - [CONST.REPORT.ACTIONS.TYPE.REIMBURSEMENT_SETUP]: { - originalMessage?: never; - }; - [CONST.REPORT.ACTIONS.TYPE.RENAMED]: { - originalMessage: OriginalMessageRenamed; - }; - [CONST.REPORT.ACTIONS.TYPE.REPORT_PREVIEW]: { - originalMessage: OriginalMessageReportPreview; - }; - [CONST.REPORT.ACTIONS.TYPE.SELECTED_FOR_RANDOM_AUDIT]: { - originalMessage?: never; - }; - [CONST.REPORT.ACTIONS.TYPE.SHARE]: { - originalMessage?: never; - }; - [CONST.REPORT.ACTIONS.TYPE.STRIPE_PAID]: { - originalMessage?: never; - }; - [CONST.REPORT.ACTIONS.TYPE.SUBMITTED]: { - originalMessage?: never; - }; - [CONST.REPORT.ACTIONS.TYPE.TASK_CANCELLED]: { - originalMessage?: never; - }; - [CONST.REPORT.ACTIONS.TYPE.TASK_COMPLETED]: { - originalMessage?: never; - }; - [CONST.REPORT.ACTIONS.TYPE.TASK_EDITED]: { - originalMessage?: never; - }; - [CONST.REPORT.ACTIONS.TYPE.TASK_REOPENED]: { - originalMessage?: never; - }; - [CONST.REPORT.ACTIONS.TYPE.TAKE_CONTROL]: { - originalMessage?: never; - }; - [CONST.REPORT.ACTIONS.TYPE.UNAPPROVED]: { - originalMessage?: never; - }; - [CONST.REPORT.ACTIONS.TYPE.UNHOLD]: { - originalMessage?: never; - }; - [CONST.REPORT.ACTIONS.TYPE.UNSHARE]: { - originalMessage?: never; - }; - [CONST.REPORT.ACTIONS.TYPE.UPDATE_GROUP_CHAT_MEMBER_ROLE]: { - originalMessage?: never; - }; - [CONST.REPORT.ACTIONS.TYPE.REIMBURSEMENT_SETUP_REQUESTED]: { - originalMessage?: never; - }; -} & { - [T in ValueOf]: { - originalMessage: OriginalMessageChangeLog; - }; -} & { - [T in ValueOf]: { - originalMessage: OriginalMessageChangeLog; - }; -}; - type OriginalMessageMap = { [CONST.REPORT.ACTIONS.TYPE.ACTIONABLE_JOIN_REQUEST]: OriginalMessageJoinPolicyChangeLog; [CONST.REPORT.ACTIONS.TYPE.ACTIONABLE_MENTION_WHISPER]: OriginalMessageActionableMentionWhisper; @@ -460,7 +281,6 @@ type AssertOriginalMessageDefinedForAllActions = AssertTypesEqual< >; type OriginalMessage = OriginalMessageMap[T]; -type OriginalMessageTemporary = OriginalMessageMap1[T]; // Note: type-fest's ConditionalKeys does not work correctly with objects containing `never`: https://github.com/sindresorhus/type-fest/issues/878 type ReportActionNamesWithHTMLMessage = { @@ -477,15 +297,4 @@ type AssertAllActionsWithHTMLAreListed = AssertTypesEqual< export default OriginalMessage; export {REPORT_ACTIONS_WITH_HTML_MESSAGE}; -export type { - DecisionName, - OriginalMessageIOU, - ChronosOOOEvent, - PaymentMethodType, - OriginalMessageSource, - ReportActionNamesWithHTMLMessage, - Reaction, - Decision, - OriginalMessageChangeLog, - OriginalMessageTemporary, -}; +export type {DecisionName, OriginalMessageIOU, ChronosOOOEvent, PaymentMethodType, OriginalMessageSource, ReportActionNamesWithHTMLMessage, Reaction, Decision, OriginalMessageChangeLog}; From 85f876f72c96527a8c41b1000c805228e49562c8 Mon Sep 17 00:00:00 2001 From: nkdengineer Date: Tue, 4 Jun 2024 19:33:19 +0700 Subject: [PATCH 22/45] fix ts check --- src/pages/home/report/ReportActionItemMessage.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/pages/home/report/ReportActionItemMessage.tsx b/src/pages/home/report/ReportActionItemMessage.tsx index 1feaa2ddf1b5..9e4816afda9c 100644 --- a/src/pages/home/report/ReportActionItemMessage.tsx +++ b/src/pages/home/report/ReportActionItemMessage.tsx @@ -14,6 +14,7 @@ import ONYXKEYS from '@src/ONYXKEYS'; import type {ReportAction, Transaction} from '@src/types/onyx'; import TextCommentFragment from './comment/TextCommentFragment'; import ReportActionItemFragment from './ReportActionItemFragment'; +import { Message } from '@src/types/onyx/ReportAction'; type ReportActionItemMessageOnyxProps = { /** The transaction linked to the report action. */ @@ -42,9 +43,9 @@ function ReportActionItemMessage({action, transaction, displayAsGroup, reportID, const {translate} = useLocalize(); const actionMessage = action.previousMessage ?? action.message; - let fragments = []; + let fragments: Message[] = []; if (Array.isArray(actionMessage)) { - fragments = actionMessage.filter((item) => !!item); + fragments = actionMessage.filter((item): item is Message => !!item); } else { fragments = actionMessage ? [actionMessage] : []; } From dc26e46270a4e14c505a96af3f18b03f453b52b6 Mon Sep 17 00:00:00 2001 From: nkdengineer Date: Tue, 4 Jun 2024 19:34:42 +0700 Subject: [PATCH 23/45] fix lint --- src/pages/home/report/ReportActionItemMessage.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/home/report/ReportActionItemMessage.tsx b/src/pages/home/report/ReportActionItemMessage.tsx index 9e4816afda9c..dec9a4ee84e7 100644 --- a/src/pages/home/report/ReportActionItemMessage.tsx +++ b/src/pages/home/report/ReportActionItemMessage.tsx @@ -12,9 +12,9 @@ import * as ReportUtils from '@libs/ReportUtils'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import type {ReportAction, Transaction} from '@src/types/onyx'; +import type {Message} from '@src/types/onyx/ReportAction'; import TextCommentFragment from './comment/TextCommentFragment'; import ReportActionItemFragment from './ReportActionItemFragment'; -import { Message } from '@src/types/onyx/ReportAction'; type ReportActionItemMessageOnyxProps = { /** The transaction linked to the report action. */ From d489a956db36fc7673553307ce6818b88e3de1d2 Mon Sep 17 00:00:00 2001 From: nkdengineer Date: Tue, 4 Jun 2024 19:45:50 +0700 Subject: [PATCH 24/45] add JSDoc for deprecated field --- src/libs/ReportUtils.ts | 3 +-- .../home/report/ContextMenu/BaseReportActionContextMenu.tsx | 3 ++- src/types/onyx/ReportAction.ts | 1 + 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 96796dc47b1c..c7e75fc3cb77 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -22,7 +22,6 @@ import type {Route} from '@src/ROUTES'; import ROUTES from '@src/ROUTES'; import type { Beta, - OriginalMessageIOU, PersonalDetails, PersonalDetailsList, Policy, @@ -6323,7 +6322,7 @@ function hasSmartscanError(reportActions: ReportAction[]) { } const IOUReportID = ReportActionsUtils.getIOUReportIDFromReportActionPreview(action); const isReportPreviewError = ReportActionsUtils.isReportPreviewAction(action) && shouldShowRBRForMissingSmartscanFields(IOUReportID) && !isSettled(IOUReportID); - const transactionID = (action.originalMessage as OriginalMessageIOU)?.IOUTransactionID ?? '0'; + const transactionID = ReportActionsUtils.isMoneyRequestAction(action) ? ReportActionsUtils.getOriginalMessage(action)?.IOUTransactionID ?? '0' : '0'; const transaction = allTransactions?.[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`] ?? {}; const isSplitBillError = ReportActionsUtils.isSplitBillAction(action) && TransactionUtils.hasMissingSmartscanFields(transaction as Transaction); diff --git a/src/pages/home/report/ContextMenu/BaseReportActionContextMenu.tsx b/src/pages/home/report/ContextMenu/BaseReportActionContextMenu.tsx index 46ebdd751762..f2263c753c22 100755 --- a/src/pages/home/report/ContextMenu/BaseReportActionContextMenu.tsx +++ b/src/pages/home/report/ContextMenu/BaseReportActionContextMenu.tsx @@ -236,7 +236,8 @@ function BaseReportActionContextMenu({ {filteredContextMenuActions.map((contextAction, index) => { const closePopup = !isMini; const payload: ContextMenuActionPayload = { - reportAction: reportAction as ReportAction, + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + reportAction: reportAction!, reportID, draftMessage, selection, diff --git a/src/types/onyx/ReportAction.ts b/src/types/onyx/ReportAction.ts index c59db714cae7..0739c167d742 100644 --- a/src/types/onyx/ReportAction.ts +++ b/src/types/onyx/ReportAction.ts @@ -227,6 +227,7 @@ type ReportActionBase = OnyxCommon.OnyxValueWithOfflineFeedback<{ }>; type ReportAction = ReportActionBase & { + /** @deprecated Used in old report actions before migration. Replaced by using getOriginalMessage function. */ originalMessage?: OriginalMessage; /** report action message */ From 10f197233d16969e679f113b5055a026ca679f1a Mon Sep 17 00:00:00 2001 From: nkdengineer Date: Wed, 5 Jun 2024 15:28:14 +0700 Subject: [PATCH 25/45] fix logic --- src/libs/ReportActionsUtils.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libs/ReportActionsUtils.ts b/src/libs/ReportActionsUtils.ts index efa6792ce669..ff9e85059ca7 100644 --- a/src/libs/ReportActionsUtils.ts +++ b/src/libs/ReportActionsUtils.ts @@ -222,7 +222,7 @@ function isReimbursementQueuedAction(reportAction: OnyxEntry): rep return isActionOfType(reportAction, CONST.REPORT.ACTIONS.TYPE.REIMBURSEMENT_QUEUED); } -function isMemberChangeAction(reportAction: OnyxEntry) { +function isMemberChangeAction(reportAction: OnyxEntry): reportAction is ReportAction> { return isActionOfType( reportAction, CONST.REPORT.ACTIONS.TYPE.ROOM_CHANGE_LOG.INVITE_TO_ROOM, @@ -1059,7 +1059,7 @@ function getMemberChangeMessageElements(reportAction: OnyxEntry): const isInviteAction = isInviteMemberAction(reportAction); const isLeaveAction = isLeavePolicyAction(reportAction); - if (!isInviteAction && !isLeaveAction) { + if (!isMemberChangeAction(reportAction)) { return []; } From 622b7c8be886e1ee1dc3ae38d4736ab2e124f1a6 Mon Sep 17 00:00:00 2001 From: nkdengineer Date: Wed, 5 Jun 2024 15:39:30 +0700 Subject: [PATCH 26/45] fix lint --- src/libs/ReportActionsUtils.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/libs/ReportActionsUtils.ts b/src/libs/ReportActionsUtils.ts index ff9e85059ca7..45a60f984be9 100644 --- a/src/libs/ReportActionsUtils.ts +++ b/src/libs/ReportActionsUtils.ts @@ -222,7 +222,9 @@ function isReimbursementQueuedAction(reportAction: OnyxEntry): rep return isActionOfType(reportAction, CONST.REPORT.ACTIONS.TYPE.REIMBURSEMENT_QUEUED); } -function isMemberChangeAction(reportAction: OnyxEntry): reportAction is ReportAction> { +function isMemberChangeAction( + reportAction: OnyxEntry, +): reportAction is ReportAction> { return isActionOfType( reportAction, CONST.REPORT.ACTIONS.TYPE.ROOM_CHANGE_LOG.INVITE_TO_ROOM, From 602388e51405cd75010c582866b981b74b20cc32 Mon Sep 17 00:00:00 2001 From: nkdengineer Date: Wed, 5 Jun 2024 19:59:23 +0700 Subject: [PATCH 27/45] use isActionOfType --- src/libs/ReportActionsUtils.ts | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/src/libs/ReportActionsUtils.ts b/src/libs/ReportActionsUtils.ts index 45a60f984be9..22a71d28df63 100644 --- a/src/libs/ReportActionsUtils.ts +++ b/src/libs/ReportActionsUtils.ts @@ -96,7 +96,7 @@ function isDeletedAction(reportAction: OnyxEntry(reportAction: ReportActi return reportAction.originalMessage; } -function getMessage(reportAction: OnyxEntry>): OriginalMessage | Message | undefined { - if (!Array.isArray(reportAction?.message)) { - return reportAction?.message ?? reportAction?.originalMessage; - } - return reportAction.originalMessage ?? reportAction.message?.[0]; -} - /** * We are in the process of deprecating reportAction.originalMessage and will be setting the db version of "message" to reportAction.message in the future see: https://github.com/Expensify/App/issues/39797 * In the interim, we must check to see if we have an object or array for the reportAction.message, if we have an array we will use the originalMessage as this means we have not yet migrated. @@ -241,14 +234,12 @@ function isInviteMemberAction( return isActionOfType(reportAction, CONST.REPORT.ACTIONS.TYPE.ROOM_CHANGE_LOG.INVITE_TO_ROOM, CONST.REPORT.ACTIONS.TYPE.POLICY_CHANGE_LOG.INVITE_TO_ROOM); } -function isLeavePolicyAction( - reportAction: OnyxEntry, -): reportAction is ReportAction { +function isLeavePolicyAction(reportAction: OnyxEntry): reportAction is ReportAction { return isActionOfType(reportAction, CONST.REPORT.ACTIONS.TYPE.POLICY_CHANGE_LOG.LEAVE_POLICY); } function isReimbursementDeQueuedAction(reportAction: OnyxEntry): reportAction is ReportAction { - return reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.REIMBURSEMENT_DEQUEUED; + return isActionOfType(reportAction, CONST.REPORT.ACTIONS.TYPE.REIMBURSEMENT_DEQUEUED); } function isClosedAction(reportAction: OnyxEntry): reportAction is ReportAction { @@ -1415,7 +1406,6 @@ export { getReportActionMessage, getOriginalMessage, isActionOfType, - getMessage, isActionableTrackExpense, getAllReportActions, isLinkedTransactionHeld, From 5808acd9b1e99fdb98ab3945c0683d115c898f7e Mon Sep 17 00:00:00 2001 From: nkdengineer Date: Wed, 5 Jun 2024 22:16:46 +0700 Subject: [PATCH 28/45] clean code --- .../AttachmentCarousel/extractAttachments.ts | 2 +- src/libs/ReportActionsUtils.ts | 19 ++++++++++------ src/libs/ReportUtils.ts | 10 ++++----- src/libs/TaskUtils.ts | 4 ++-- src/libs/actions/IOU.ts | 22 +++++++++---------- src/libs/actions/Report.ts | 2 +- .../report/ReportActionItemMessageEdit.tsx | 2 +- 7 files changed, 33 insertions(+), 28 deletions(-) diff --git a/src/components/Attachments/AttachmentCarousel/extractAttachments.ts b/src/components/Attachments/AttachmentCarousel/extractAttachments.ts index 7dced21eae55..3c12fb31ae1e 100644 --- a/src/components/Attachments/AttachmentCarousel/extractAttachments.ts +++ b/src/components/Attachments/AttachmentCarousel/extractAttachments.ts @@ -93,7 +93,7 @@ function extractAttachments( const decision = ReportActionsUtils.getReportActionMessage(action)?.moderationDecision?.decision; const hasBeenFlagged = decision === CONST.MODERATION.MODERATOR_DECISION_PENDING_HIDE || decision === CONST.MODERATION.MODERATOR_DECISION_HIDDEN; - const html = (ReportActionsUtils.getReportActionMessage(action)?.html ?? '').replace('/>', `data-flagged="${hasBeenFlagged}" data-id="${action.reportActionID}"/>`); + const html = ReportActionsUtils.getReportActionHtml(action).replace('/>', `data-flagged="${hasBeenFlagged}" data-id="${action.reportActionID}"/>`); htmlParser.write(html); }); htmlParser.end(); diff --git a/src/libs/ReportActionsUtils.ts b/src/libs/ReportActionsUtils.ts index 22a71d28df63..9312b8828451 100644 --- a/src/libs/ReportActionsUtils.ts +++ b/src/libs/ReportActionsUtils.ts @@ -143,7 +143,7 @@ function isModifiedExpenseAction(reportAction: OnyxEntry): reportA return isActionOfType(reportAction, CONST.REPORT.ACTIONS.TYPE.MODIFIED_EXPENSE); } -function isPolicyChangelLogAction(reportAction: OnyxEntry): reportAction is ReportAction> { +function isPolicyChangeLogAction(reportAction: OnyxEntry): reportAction is ReportAction> { return isActionOfType(reportAction, ...Object.values(CONST.REPORT.ACTIONS.TYPE.POLICY_CHANGE_LOG)); } @@ -470,7 +470,7 @@ function getMostRecentIOURequestActionID(reportActions: ReportAction[] | null): * Returns array of links inside a given report action */ function extractLinksFromMessageHtml(reportAction: OnyxEntry): string[] { - const htmlContent = getReportActionMessage(reportAction)?.html; + const htmlContent = getReportActionHtml(reportAction); const regex = CONST.REGEX_LINK_IN_ANCHOR; @@ -688,7 +688,7 @@ function shouldReportActionBeVisibleAsLastAction(reportAction: OnyxEntry): Message { const messageElements: readonly MemberChangeMessageElement[] = getMemberChangeMessageElements(reportAction); const html = messageElements @@ -1311,9 +1316,9 @@ function isApprovedOrSubmittedReportAction(action: OnyxEntry | Emp */ function getReportActionMessageText(reportAction: OnyxEntry | EmptyObject): string { if (!Array.isArray(reportAction?.message)) { - return ''; + return getReportActionText(reportAction); } - return reportAction?.message?.reduce((acc, curr) => `${acc}${curr?.text}`, '') ?? ''; + return reportAction?.message?.reduce((acc, curr) => `${acc}${getTextFromHtml(curr?.html)}`, '') ?? ''; } function getDismissedViolationMessageText(originalMessage: ReportAction['originalMessage']): string { @@ -1416,7 +1421,7 @@ export { isRoomChangeLogAction, isChronosOOOListAction, isAddCommentAction, - isPolicyChangelLogAction, + isPolicyChangeLogAction, }; export type {LastVisibleMessage}; diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index e0e49cdbc471..e52d0f3cbadd 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -2733,7 +2733,7 @@ function canEditFieldOfMoneyRequest(reportAction: OnyxEntry, field */ function canEditReportAction(reportAction: OnyxEntry): boolean { const isCommentOrIOU = reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.ADD_COMMENT || reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.IOU; - const message = Array.isArray(reportAction?.message) ? reportAction?.message?.[0] : reportAction?.message; + const message = reportAction ? ReportActionsUtils.getReportActionMessage(reportAction) : undefined; return Boolean( reportAction?.actorAccountID === currentUserAccountID && @@ -2875,7 +2875,7 @@ function getReportPreviewMessage( isForListPreview = false, originalReportAction: OnyxEntry | EmptyObject = iouReportAction, ): string { - const reportActionMessage = ReportActionsUtils.getReportActionMessage(iouReportAction)?.html ?? ''; + const reportActionMessage = ReportActionsUtils.getReportActionHtml(iouReportAction); if (isEmptyObject(report) || !report?.reportID || isEmptyObject(iouReportAction)) { // The iouReport is not found locally after SignIn because the OpenApp API won't return iouReports if they're settled @@ -3113,7 +3113,7 @@ function getAdminRoomInvitedParticipants(parentReportAction: ReportAction | Empt if (!ReportActionsUtils.getOriginalMessage(parentReportAction)) { return parentReportActionMessage || Localize.translateLocal('parentReportAction.deletedMessage'); } - if (!ReportActionsUtils.isPolicyChangelLogAction(parentReportAction) || !ReportActionsUtils.isRoomChangeLogAction(parentReportAction)) { + if (!ReportActionsUtils.isPolicyChangeLogAction(parentReportAction) || !ReportActionsUtils.isRoomChangeLogAction(parentReportAction)) { return parentReportActionMessage || Localize.translateLocal('parentReportAction.deletedMessage'); } @@ -3677,7 +3677,7 @@ function buildOptimisticTaskCommentReportAction( // These parameters are not saved on the reportAction, but are used to display the task in the UI // Added when we fetch the reportActions on a report reportAction.reportAction.originalMessage = { - html: ReportActionsUtils.getReportActionMessage(reportAction.reportAction)?.html ?? '', + html: ReportActionsUtils.getReportActionHtml(reportAction.reportAction), taskReportID: ReportActionsUtils.getReportActionMessage(reportAction.reportAction)?.taskReportID, whisperedTo: [], }; @@ -6634,7 +6634,7 @@ function isAllowedToSubmitDraftExpenseReport(report: OnyxEntry): boolean */ function getIndicatedMissingPaymentMethod(userWallet: OnyxEntry, reportId: string, reportAction: ReportAction): MissingPaymentMethod | undefined { const isSubmitterOfUnsettledReport = isCurrentUserSubmitter(reportId) && !isSettled(reportId); - if (!isSubmitterOfUnsettledReport || !ReportActionsUtils.isActionOfType(reportAction, CONST.REPORT.ACTIONS.TYPE.REIMBURSEMENT_QUEUED)) { + if (!isSubmitterOfUnsettledReport || !ReportActionsUtils.isReimbursementQueuedAction(reportAction)) { return undefined; } const paymentType = ReportActionsUtils.getOriginalMessage(reportAction)?.paymentType; diff --git a/src/libs/TaskUtils.ts b/src/libs/TaskUtils.ts index 9ff2f09f0dd2..a7b18608239d 100644 --- a/src/libs/TaskUtils.ts +++ b/src/libs/TaskUtils.ts @@ -6,7 +6,7 @@ import type {Report} from '@src/types/onyx'; import type {Message} from '@src/types/onyx/ReportAction'; import type ReportAction from '@src/types/onyx/ReportAction'; import * as Localize from './Localize'; -import {getReportActionMessage, getReportActionText} from './ReportActionsUtils'; +import {getReportActionHtml, getReportActionText} from './ReportActionsUtils'; let allReports: OnyxCollection = {}; Onyx.connect({ @@ -31,7 +31,7 @@ function getTaskReportActionMessage(action: OnyxEntry): Pick { const parser = new ExpensiMark(); - const originalMessage = parser.htmlToMarkdown(ReportActionsUtils.getReportActionMessage(action)?.html ?? ''); + const originalMessage = parser.htmlToMarkdown(ReportActionsUtils.getReportActionHtml(action)); if ( ReportActionsUtils.isDeletedAction(action) || Boolean(action.message && draftMessage === originalMessage) || From a7e3f34acf8768b3836e6122547fd70081461f13 Mon Sep 17 00:00:00 2001 From: nkdengineer Date: Wed, 5 Jun 2024 22:27:47 +0700 Subject: [PATCH 29/45] replace text to html --- .../Notification/LocalNotification/BrowserNotifications.ts | 5 +++-- src/libs/ReportActionsUtils.ts | 7 ++++--- src/pages/home/report/ReportActionItemFragment.tsx | 7 ++++--- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/libs/Notification/LocalNotification/BrowserNotifications.ts b/src/libs/Notification/LocalNotification/BrowserNotifications.ts index 90f73217885d..652f9f510a47 100644 --- a/src/libs/Notification/LocalNotification/BrowserNotifications.ts +++ b/src/libs/Notification/LocalNotification/BrowserNotifications.ts @@ -4,6 +4,7 @@ import type {ImageSourcePropType} from 'react-native'; import EXPENSIFY_ICON_URL from '@assets/images/expensify-logo-round-clearspace.png'; import * as AppUpdate from '@libs/actions/AppUpdate'; import ModifiedExpenseMessage from '@libs/ModifiedExpenseMessage'; +import {getTextFromHtml} from '@libs/ReportActionsUtils'; import * as ReportUtils from '@libs/ReportUtils'; import type {Report, ReportAction} from '@src/types/onyx'; import focusApp from './focusApp'; @@ -103,9 +104,9 @@ export default { // Specifically target the comment part of the message let plainTextMessage = ''; if (Array.isArray(message)) { - plainTextMessage = message?.find((f) => f?.type === 'COMMENT')?.text ?? ''; + plainTextMessage = getTextFromHtml(message?.find((f) => f?.type === 'COMMENT')?.html); } else { - plainTextMessage = message?.type === 'COMMENT' ? message?.text ?? '' : ''; + plainTextMessage = message?.type === 'COMMENT' ? getTextFromHtml(message?.html) : ''; } if (isChatRoom) { diff --git a/src/libs/ReportActionsUtils.ts b/src/libs/ReportActionsUtils.ts index 9312b8828451..3831df5128b4 100644 --- a/src/libs/ReportActionsUtils.ts +++ b/src/libs/ReportActionsUtils.ts @@ -733,7 +733,7 @@ function getLastVisibleMessage(reportID: string, actionsToMerge: OnyxCollection< }; } - let messageText = message?.text ?? ''; + let messageText = getTextFromHtml(message?.html) ?? ''; if (messageText) { messageText = StringUtils.lineBreaksToSpaces(String(messageText)).substring(0, CONST.REPORT.LAST_MESSAGE_TEXT_MAX_LENGTH).trim(); } @@ -1192,9 +1192,9 @@ function isOldDotReportAction(action: ReportAction): boolean { */ function getMessageOfOldDotReportAction(reportAction: OnyxEntry): string { if (!Array.isArray(reportAction?.message)) { - return reportAction?.message?.text ?? ''; + return getReportActionText(reportAction); } - return reportAction?.message?.map((element) => element?.text).join('') ?? ''; + return reportAction?.message?.map((element) => getTextFromHtml(element?.html)).join('') ?? ''; } function getMemberChangeMessagePlainText(reportAction: OnyxEntry): string { @@ -1422,6 +1422,7 @@ export { isChronosOOOListAction, isAddCommentAction, isPolicyChangeLogAction, + getTextFromHtml, }; export type {LastVisibleMessage}; diff --git a/src/pages/home/report/ReportActionItemFragment.tsx b/src/pages/home/report/ReportActionItemFragment.tsx index 27227251b0b6..f00568a9a576 100644 --- a/src/pages/home/report/ReportActionItemFragment.tsx +++ b/src/pages/home/report/ReportActionItemFragment.tsx @@ -7,6 +7,7 @@ import useLocalize from '@hooks/useLocalize'; import useNetwork from '@hooks/useNetwork'; import useThemeStyles from '@hooks/useThemeStyles'; import convertToLTR from '@libs/convertToLTR'; +import {getTextFromHtml} from '@libs/ReportActionsUtils'; import * as ReportUtils from '@libs/ReportUtils'; import CONST from '@src/CONST'; import type * as OnyxCommon from '@src/types/onyx/OnyxCommon'; @@ -141,7 +142,7 @@ function ReportActionItemFragment({ numberOfLines={isSingleLine ? 1 : undefined} style={[styles.chatItemMessage, styles.colorMuted]} > - {isFragmentContainingDisplayName ? convertToLTR(fragment?.text ?? '') : fragment?.text} + {isFragmentContainingDisplayName ? convertToLTR(getTextFromHtml(fragment?.html)) : getTextFromHtml(fragment?.html)} ); } @@ -152,7 +153,7 @@ function ReportActionItemFragment({ numberOfLines={isSingleLine ? 1 : undefined} style={[styles.chatItemMessage]} > - {isFragmentContainingDisplayName ? convertToLTR(fragment?.text ?? '') : fragment?.text} + {isFragmentContainingDisplayName ? convertToLTR(getTextFromHtml(fragment?.html)) : getTextFromHtml(fragment?.html)} ); } @@ -167,7 +168,7 @@ function ReportActionItemFragment({ numberOfLines={isSingleLine ? 1 : undefined} style={[styles.chatItemMessageHeaderSender, isSingleLine ? styles.pre : styles.preWrap]} > - {fragment?.text} + {getTextFromHtml(fragment?.html)} ); From f70e9b72a618e1f871b894dfbd56bb6b208dd5a3 Mon Sep 17 00:00:00 2001 From: nkdengineer Date: Wed, 5 Jun 2024 22:31:44 +0700 Subject: [PATCH 30/45] replace text to html --- src/libs/actions/IOU.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 92437906c83c..3793faaf8706 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -4938,7 +4938,7 @@ function editRegularMoneyRequest( '', false, ); - updatedMoneyRequestReport.lastMessageText = lastMessage[0].text; + updatedMoneyRequestReport.lastMessageText = ReportActionsUtils.getTextFromHtml(lastMessage[0].html); updatedMoneyRequestReport.lastMessageHtml = lastMessage[0].html; // Update the last message of the chat report From 201f875d74fad49fa6b0252fe63fd3a3c60b559c Mon Sep 17 00:00:00 2001 From: nkdengineer Date: Wed, 5 Jun 2024 22:44:21 +0700 Subject: [PATCH 31/45] revert unnecessary change --- src/pages/home/report/ReportActionItemFragment.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/pages/home/report/ReportActionItemFragment.tsx b/src/pages/home/report/ReportActionItemFragment.tsx index f00568a9a576..236d502c82a4 100644 --- a/src/pages/home/report/ReportActionItemFragment.tsx +++ b/src/pages/home/report/ReportActionItemFragment.tsx @@ -142,7 +142,7 @@ function ReportActionItemFragment({ numberOfLines={isSingleLine ? 1 : undefined} style={[styles.chatItemMessage, styles.colorMuted]} > - {isFragmentContainingDisplayName ? convertToLTR(getTextFromHtml(fragment?.html)) : getTextFromHtml(fragment?.html)} + {isFragmentContainingDisplayName ? convertToLTR(fragment?.text ?? '') : fragment?.text} ); } @@ -153,7 +153,7 @@ function ReportActionItemFragment({ numberOfLines={isSingleLine ? 1 : undefined} style={[styles.chatItemMessage]} > - {isFragmentContainingDisplayName ? convertToLTR(getTextFromHtml(fragment?.html)) : getTextFromHtml(fragment?.html)} + {isFragmentContainingDisplayName ? convertToLTR(fragment?.text ?? '') : fragment?.text} ); } @@ -168,7 +168,7 @@ function ReportActionItemFragment({ numberOfLines={isSingleLine ? 1 : undefined} style={[styles.chatItemMessageHeaderSender, isSingleLine ? styles.pre : styles.preWrap]} > - {getTextFromHtml(fragment?.html)} + {fragment?.text} ); From 10631d512f7040f2cd3936a6aa1d4433267610cf Mon Sep 17 00:00:00 2001 From: nkdengineer Date: Wed, 5 Jun 2024 22:44:37 +0700 Subject: [PATCH 32/45] fix lint --- src/pages/home/report/ReportActionItemFragment.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/pages/home/report/ReportActionItemFragment.tsx b/src/pages/home/report/ReportActionItemFragment.tsx index 236d502c82a4..27227251b0b6 100644 --- a/src/pages/home/report/ReportActionItemFragment.tsx +++ b/src/pages/home/report/ReportActionItemFragment.tsx @@ -7,7 +7,6 @@ import useLocalize from '@hooks/useLocalize'; import useNetwork from '@hooks/useNetwork'; import useThemeStyles from '@hooks/useThemeStyles'; import convertToLTR from '@libs/convertToLTR'; -import {getTextFromHtml} from '@libs/ReportActionsUtils'; import * as ReportUtils from '@libs/ReportUtils'; import CONST from '@src/CONST'; import type * as OnyxCommon from '@src/types/onyx/OnyxCommon'; From a31f9a09ae5d81d013b170ea55db37c54dd5ce52 Mon Sep 17 00:00:00 2001 From: nkdengineer Date: Fri, 7 Jun 2024 13:16:14 +0700 Subject: [PATCH 33/45] fix ts check --- src/libs/actions/Policy/Member.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libs/actions/Policy/Member.ts b/src/libs/actions/Policy/Member.ts index ee2f02b68252..b566044ad2b2 100644 --- a/src/libs/actions/Policy/Member.ts +++ b/src/libs/actions/Policy/Member.ts @@ -14,12 +14,12 @@ import * as ErrorUtils from '@libs/ErrorUtils'; import Log from '@libs/Log'; import * as PersonalDetailsUtils from '@libs/PersonalDetailsUtils'; import * as PhoneNumber from '@libs/PhoneNumber'; +import * as ReportActionsUtils from '@libs/ReportActionsUtils'; import * as ReportUtils from '@libs/ReportUtils'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import type {InvitedEmailsToAccountIDs, PersonalDetailsList, Policy, PolicyEmployee, PolicyOwnershipChangeChecks, Report, ReportAction} from '@src/types/onyx'; import type {PendingAction} from '@src/types/onyx/OnyxCommon'; -import type {OriginalMessageJoinPolicyChangeLog} from '@src/types/onyx/OriginalMessage'; import type {Attributes, Rate} from '@src/types/onyx/Policy'; import type {EmptyObject} from '@src/types/utils/EmptyObject'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; @@ -724,7 +724,7 @@ function acceptJoinRequest(reportID: string, reportAction: OnyxEntry Date: Wed, 12 Jun 2024 11:28:47 +0700 Subject: [PATCH 34/45] fix ts check --- src/libs/ReportUtils.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 1f842825b1f0..8761ac8e2be6 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -2734,11 +2734,11 @@ function canEditReportAction(reportAction: OnyxEntry): boolean { } function canHoldUnholdReportAction(reportAction: OnyxEntry): {canHoldRequest: boolean; canUnholdRequest: boolean} { - if (reportAction?.actionName !== CONST.REPORT.ACTIONS.TYPE.IOU) { + if (!ReportActionsUtils.isMoneyRequestAction(reportAction)) { return {canHoldRequest: false, canUnholdRequest: false}; } - const moneyRequestReportID = reportAction?.originalMessage?.IOUReportID ?? 0; + const moneyRequestReportID = ReportActionsUtils.getOriginalMessage(reportAction)?.IOUReportID ?? 0; const moneyRequestReport = getReport(String(moneyRequestReportID)); if (!moneyRequestReportID || !moneyRequestReport) { @@ -2747,7 +2747,7 @@ function canHoldUnholdReportAction(reportAction: OnyxEntry): {canH const isRequestSettled = isSettled(moneyRequestReport?.reportID); const isApproved = isReportApproved(moneyRequestReport); - const transactionID = moneyRequestReport ? reportAction?.originalMessage?.IOUTransactionID : 0; + const transactionID = moneyRequestReport ? ReportActionsUtils.getOriginalMessage(reportAction)?.IOUTransactionID : 0; const transaction = allTransactions?.[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`] ?? ({} as Transaction); const parentReport = getReport(String(moneyRequestReport.parentReportID)); @@ -2775,17 +2775,17 @@ function canHoldUnholdReportAction(reportAction: OnyxEntry): {canH } const changeMoneyRequestHoldStatus = (reportAction: OnyxEntry): void => { - if (reportAction?.actionName !== CONST.REPORT.ACTIONS.TYPE.IOU) { + if (!ReportActionsUtils.isMoneyRequestAction(reportAction)) { return; } - const moneyRequestReportID = reportAction?.originalMessage?.IOUReportID ?? 0; + const moneyRequestReportID = ReportActionsUtils.getOriginalMessage(reportAction)?.IOUReportID ?? 0; const moneyRequestReport = getReport(String(moneyRequestReportID)); if (!moneyRequestReportID || !moneyRequestReport) { return; } - const transactionID = reportAction?.originalMessage?.IOUTransactionID ?? ''; + const transactionID = ReportActionsUtils.getOriginalMessage(reportAction)?.IOUTransactionID ?? ''; const transaction = allTransactions?.[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`] ?? ({} as Transaction); const isOnHold = TransactionUtils.isOnHold(transaction); const policy = allPolicies?.[`${ONYXKEYS.COLLECTION.POLICY}${moneyRequestReport.policyID}`] ?? null; From 294df4a6e9093aa253e18a97f79011f2b0bba5b2 Mon Sep 17 00:00:00 2001 From: nkdengineer Date: Wed, 12 Jun 2024 13:44:23 +0700 Subject: [PATCH 35/45] update type --- .../ReportActionItem/MoneyRequestView.tsx | 2 +- src/libs/ReportActionsUtils.ts | 29 +- src/libs/ReportUtils.ts | 21 +- src/libs/actions/IOU.ts | 31 +-- .../BaseReportActionContextMenu.tsx | 4 +- src/pages/home/report/ReportActionItem.tsx | 2 - src/pages/iou/HoldReasonPage.tsx | 4 +- .../request/step/IOURequestStepCategory.tsx | 3 +- .../step/IOURequestStepDescription.tsx | 3 +- .../iou/request/step/IOURequestStepTag.tsx | 7 +- src/types/onyx/OriginalMessage.ts | 255 +++++------------- src/types/onyx/ReportActionName.ts | 4 +- 12 files changed, 114 insertions(+), 251 deletions(-) diff --git a/src/components/ReportActionItem/MoneyRequestView.tsx b/src/components/ReportActionItem/MoneyRequestView.tsx index e46eaf1d615b..0733f62801f4 100644 --- a/src/components/ReportActionItem/MoneyRequestView.tsx +++ b/src/components/ReportActionItem/MoneyRequestView.tsx @@ -136,7 +136,7 @@ function MoneyRequestView({ const isCancelled = moneyRequestReport && moneyRequestReport.isCancelledIOU; // Used for non-restricted fields such as: description, category, tag, billable, etc. - const canEdit = ReportUtils.canEditMoneyRequest(parentReportAction); + const canEdit = ReportActionsUtils.isMoneyRequestAction(parentReportAction) && ReportUtils.canEditMoneyRequest(parentReportAction); const canEditTaxFields = canEdit && !isDistanceRequest; const canEditAmount = ReportUtils.canEditFieldOfMoneyRequest(parentReportAction, CONST.EDIT_REQUEST_FIELD.AMOUNT); diff --git a/src/libs/ReportActionsUtils.ts b/src/libs/ReportActionsUtils.ts index 97d85b4b9cab..acceea7bad8c 100644 --- a/src/libs/ReportActionsUtils.ts +++ b/src/libs/ReportActionsUtils.ts @@ -3,7 +3,7 @@ import _ from 'lodash'; import lodashFindLast from 'lodash/findLast'; import type {OnyxCollection, OnyxEntry, OnyxUpdate} from 'react-native-onyx'; import Onyx from 'react-native-onyx'; -import type {ValueOf} from 'type-fest'; +import type {SetFieldType, SetRequired, ValueOf} from 'type-fest'; import CONST from '@src/CONST'; import type {TranslationPaths} from '@src/languages/types'; import ONYXKEYS from '@src/ONYXKEYS'; @@ -135,8 +135,8 @@ function isReportPreviewAction(reportAction: OnyxEntry): reportAct return isActionOfType(reportAction, CONST.REPORT.ACTIONS.TYPE.REPORT_PREVIEW); } -function isReportActionSubmitted(reportAction: OnyxEntry): boolean { - return reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.SUBMITTED; +function isSubmittedAction(reportAction: OnyxEntry): reportAction is ReportAction { + return isActionOfType(reportAction, CONST.REPORT.ACTIONS.TYPE.SUBMITTED); } function isModifiedExpenseAction(reportAction: OnyxEntry): reportAction is ReportAction { @@ -155,6 +155,10 @@ function isAddCommentAction(reportAction: OnyxEntry): reportAction return isActionOfType(reportAction, CONST.REPORT.ACTIONS.TYPE.ADD_COMMENT); } +function isCreatedTaskReportAction(reportAction: OnyxEntry): reportAction is ReportAction { + return isActionOfType(reportAction, CONST.REPORT.ACTIONS.TYPE.ADD_COMMENT) && !!getOriginalMessage(reportAction)?.taskReportID; +} + function isActionOfType( action: OnyxEntry, ...actionNames: T @@ -543,13 +547,13 @@ function isConsecutiveActionMadeByPreviousActor(reportActions: ReportAction[] | return false; } - if (isReportActionSubmitted(currentAction)) { + if (isSubmittedAction(currentAction)) { const currentActionAdminAccountID = currentAction.adminAccountID; return currentActionAdminAccountID === previousAction.actorAccountID || currentActionAdminAccountID === previousAction.adminAccountID; } - if (isReportActionSubmitted(previousAction)) { + if (isSubmittedAction(previousAction)) { return typeof previousAction.adminAccountID === 'number' ? currentAction.actorAccountID === previousAction.adminAccountID : currentAction.actorAccountID === previousAction.actorAccountID; @@ -880,10 +884,11 @@ function getMostRecentReportActionLastModified(): string { /** * @returns The report preview action or `null` if one couldn't be found */ -function getReportPreviewAction(chatReportID: string, iouReportID: string): OnyxEntry { +function getReportPreviewAction(chatReportID: string, iouReportID: string): OnyxEntry> { return ( Object.values(allReportActions?.[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chatReportID}`] ?? {}).find( - (reportAction) => reportAction && isActionOfType(reportAction, CONST.REPORT.ACTIONS.TYPE.REPORT_PREVIEW) && getOriginalMessage(reportAction)?.linkedReportID === iouReportID, + (reportAction): reportAction is ReportAction => + reportAction && isActionOfType(reportAction, CONST.REPORT.ACTIONS.TYPE.REPORT_PREVIEW) && getOriginalMessage(reportAction)?.linkedReportID === iouReportID, ) ?? null ); } @@ -895,10 +900,6 @@ function getIOUReportIDFromReportActionPreview(reportAction: OnyxEntry): boolean { - return isActionOfType(reportAction, CONST.REPORT.ACTIONS.TYPE.ADD_COMMENT) && !!getOriginalMessage(reportAction)?.taskReportID; -} - /** * A helper method to identify if the message is deleted or not. */ @@ -913,15 +914,15 @@ function getNumberOfMoneyRequests(reportPreviewAction: OnyxEntry): return reportPreviewAction?.childMoneyRequestCount ?? 0; } -function isSplitBillAction(reportAction: OnyxEntry): boolean { +function isSplitBillAction(reportAction: OnyxEntry): reportAction is ReportAction { return isActionOfType(reportAction, CONST.REPORT.ACTIONS.TYPE.IOU) && getOriginalMessage(reportAction)?.type === CONST.IOU.REPORT_ACTION_TYPE.SPLIT; } -function isTrackExpenseAction(reportAction: OnyxEntry): boolean { +function isTrackExpenseAction(reportAction: OnyxEntry): reportAction is ReportAction { return isActionOfType(reportAction, CONST.REPORT.ACTIONS.TYPE.IOU) && getOriginalMessage(reportAction)?.type === CONST.IOU.REPORT_ACTION_TYPE.TRACK; } -function isPayAction(reportAction: OnyxEntry): boolean { +function isPayAction(reportAction: OnyxEntry): reportAction is ReportAction { return isActionOfType(reportAction, CONST.REPORT.ACTIONS.TYPE.IOU) && getOriginalMessage(reportAction)?.type === CONST.IOU.REPORT_ACTION_TYPE.PAY; } diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 8761ac8e2be6..197c159713cc 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -87,7 +87,7 @@ type SpendBreakdown = { type ParticipantDetails = [number, string, AvatarSource, AvatarSource]; type OptimisticAddCommentReportAction = Pick< - ReportAction, + ReportAction, | 'reportActionID' | 'actionName' | 'actorAccountID' @@ -2605,18 +2605,13 @@ function getTransactionCommentObject(transaction: OnyxEntry): Comme * This is used in conjunction with canEditRestrictedField to control editing of specific fields like amount, currency, created, receipt, and distance. * On its own, it only controls allowing/disallowing navigating to the editing pages or showing/hiding the 'Edit' icon on report actions */ -function canEditMoneyRequest(reportAction: OnyxEntry): boolean { +function canEditMoneyRequest(reportAction: ReportAction): boolean { const isDeleted = ReportActionsUtils.isDeletedAction(reportAction); if (isDeleted) { return false; } - // If the report action is not IOU type, return true early - if (!ReportActionsUtils.isMoneyRequestAction(reportAction)) { - return true; - } - const allowedReportActionType: Array> = [CONST.IOU.REPORT_ACTION_TYPE.TRACK, CONST.IOU.REPORT_ACTION_TYPE.CREATE]; const originalMessage = ReportActionsUtils.getOriginalMessage(reportAction); const actionType = originalMessage?.type; @@ -2669,7 +2664,7 @@ function canEditFieldOfMoneyRequest(reportAction: OnyxEntry, field CONST.EDIT_REQUEST_FIELD.DISTANCE, ]; - if (!canEditMoneyRequest(reportAction) || !ReportActionsUtils.isMoneyRequestAction(reportAction)) { + if (!ReportActionsUtils.isMoneyRequestAction(reportAction) || !canEditMoneyRequest(reportAction)) { return false; } @@ -2724,7 +2719,7 @@ function canEditReportAction(reportAction: OnyxEntry): boolean { return !!( reportAction?.actorAccountID === currentUserAccountID && isCommentOrIOU && - canEditMoneyRequest(reportAction) && // Returns true for non-IOU actions + (!ReportActionsUtils.isMoneyRequestAction(reportAction) || canEditMoneyRequest(reportAction)) && // Returns true for non-IOU actions !isReportMessageAttachment(message) && (isEmptyObject(reportAction.attachmentInfo) || !reportAction.isOptimisticAction) && !ReportActionsUtils.isDeletedAction(reportAction) && @@ -4293,7 +4288,13 @@ function buildOptimisticSubmittedReportAction(amount: number, currency: string, * @param [comment] - User comment for the IOU. * @param [transaction] - optimistic first transaction of preview */ -function buildOptimisticReportPreview(chatReport: OnyxEntry, iouReport: Report, comment = '', transaction: OnyxEntry = null, childReportID?: string): ReportAction { +function buildOptimisticReportPreview( + chatReport: OnyxEntry, + iouReport: Report, + comment = '', + transaction: OnyxEntry = null, + childReportID?: string, +): ReportAction { const hasReceipt = TransactionUtils.hasReceipt(transaction); const isReceiptBeingScanned = hasReceipt && TransactionUtils.isReceiptBeingScanned(transaction); const message = getReportPreviewMessage(iouReport); diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 032b45c50474..c1189db700f7 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -286,13 +286,14 @@ Onyx.connect({ /** * Find the report preview action from given chat report and iou report */ -function getReportPreviewAction(chatReportID: string, iouReportID: string): OnyxEntry { +function getReportPreviewAction(chatReportID: string, iouReportID: string): OnyxEntry> { const reportActions = allReportActions?.[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chatReportID}`] ?? {}; // Find the report preview action from the chat report return ( Object.values(reportActions).find( - (reportAction) => reportAction && ReportActionsUtils.isReportPreviewAction(reportAction) && ReportActionsUtils.getOriginalMessage(reportAction)?.linkedReportID === iouReportID, + (reportAction): reportAction is ReportAction => + reportAction && ReportActionsUtils.isReportPreviewAction(reportAction) && ReportActionsUtils.getOriginalMessage(reportAction)?.linkedReportID === iouReportID, ) ?? null ); } @@ -2004,13 +2005,7 @@ function getMoneyRequestInformation( let reportPreviewAction = shouldCreateNewMoneyRequestReport ? null : getReportPreviewAction(chatReport.reportID, iouReport.reportID); if (reportPreviewAction) { - reportPreviewAction = ReportUtils.updateReportPreview( - iouReport, - reportPreviewAction as ReportAction, - false, - comment, - optimisticTransaction, - ); + reportPreviewAction = ReportUtils.updateReportPreview(iouReport, reportPreviewAction, false, comment, optimisticTransaction); } else { reportPreviewAction = ReportUtils.buildOptimisticReportPreview(chatReport, iouReport, comment, optimisticTransaction); chatReport.lastVisibleActionCreated = reportPreviewAction.created; @@ -2233,18 +2228,12 @@ function getTrackExpenseInformation( linkedTrackedExpenseReportAction, ); - let reportPreviewAction: OnyxEntry = null; + let reportPreviewAction: OnyxEntry> = null; if (shouldUseMoneyReport && iouReport) { reportPreviewAction = shouldCreateNewMoneyRequestReport ? null : getReportPreviewAction(chatReport.reportID, iouReport.reportID); if (reportPreviewAction) { - reportPreviewAction = ReportUtils.updateReportPreview( - iouReport, - reportPreviewAction as ReportAction, - false, - comment, - optimisticTransaction, - ); + reportPreviewAction = ReportUtils.updateReportPreview(iouReport, reportPreviewAction, false, comment, optimisticTransaction); } else { reportPreviewAction = ReportUtils.buildOptimisticReportPreview(chatReport, iouReport, comment, optimisticTransaction); // Generated ReportPreview action is a parent report action of the iou report. @@ -4131,7 +4120,7 @@ function createSplitsAndOnyxData( let oneOnOneReportPreviewAction = getReportPreviewAction(oneOnOneChatReport.reportID, oneOnOneIOUReport.reportID); if (oneOnOneReportPreviewAction) { - oneOnOneReportPreviewAction = ReportUtils.updateReportPreview(oneOnOneIOUReport, oneOnOneReportPreviewAction as ReportAction); + oneOnOneReportPreviewAction = ReportUtils.updateReportPreview(oneOnOneIOUReport, oneOnOneReportPreviewAction); } else { oneOnOneReportPreviewAction = ReportUtils.buildOptimisticReportPreview(oneOnOneChatReport, oneOnOneIOUReport); } @@ -4849,7 +4838,7 @@ function completeSplitBill(chatReportID: string, reportAction: OnyxTypes.ReportA let oneOnOneReportPreviewAction = getReportPreviewAction(oneOnOneChatReport?.reportID ?? '', oneOnOneIOUReport?.reportID ?? ''); if (oneOnOneReportPreviewAction) { - oneOnOneReportPreviewAction = ReportUtils.updateReportPreview(oneOnOneIOUReport, oneOnOneReportPreviewAction as ReportAction); + oneOnOneReportPreviewAction = ReportUtils.updateReportPreview(oneOnOneIOUReport, oneOnOneReportPreviewAction); } else { oneOnOneReportPreviewAction = ReportUtils.buildOptimisticReportPreview(oneOnOneChatReport, oneOnOneIOUReport, '', oneOnOneTransaction); } @@ -5309,7 +5298,7 @@ function deleteMoneyRequest(transactionID: string, reportAction: OnyxTypes.Repor // STEP 4: Update the iouReport and reportPreview with new totals and messages if it wasn't deleted let updatedIOUReport: OnyxTypes.Report | null; const currency = TransactionUtils.getCurrency(transaction); - const updatedReportPreviewAction: OnyxTypes.ReportAction = {...reportPreviewAction}; + const updatedReportPreviewAction: OnyxTypes.ReportAction = {...reportPreviewAction}; updatedReportPreviewAction.pendingAction = shouldDeleteIOUReport ? CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE : CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE; if (iouReport && ReportUtils.isExpenseReport(iouReport)) { updatedIOUReport = {...iouReport}; @@ -5943,7 +5932,7 @@ function getPayMoneyRequestParams( let optimisticReportPreviewAction = null; const reportPreviewAction = getReportPreviewAction(chatReport.reportID, iouReport.reportID); if (reportPreviewAction) { - optimisticReportPreviewAction = ReportUtils.updateReportPreview(iouReport, reportPreviewAction as ReportAction, true); + optimisticReportPreviewAction = ReportUtils.updateReportPreview(iouReport, reportPreviewAction, true); } let currentNextStep = null; let optimisticNextStep = null; diff --git a/src/pages/home/report/ContextMenu/BaseReportActionContextMenu.tsx b/src/pages/home/report/ContextMenu/BaseReportActionContextMenu.tsx index f2263c753c22..a40c8df2918f 100755 --- a/src/pages/home/report/ContextMenu/BaseReportActionContextMenu.tsx +++ b/src/pages/home/report/ContextMenu/BaseReportActionContextMenu.tsx @@ -236,8 +236,8 @@ function BaseReportActionContextMenu({ {filteredContextMenuActions.map((contextAction, index) => { const closePopup = !isMini; const payload: ContextMenuActionPayload = { - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - reportAction: reportAction!, + // eslint-disable-next-line @typescript-eslint/non-nullable-type-assertion-style + reportAction: reportAction as ReportAction, reportID, draftMessage, selection, diff --git a/src/pages/home/report/ReportActionItem.tsx b/src/pages/home/report/ReportActionItem.tsx index af07a2167fbf..e9cc6b83baf2 100644 --- a/src/pages/home/report/ReportActionItem.tsx +++ b/src/pages/home/report/ReportActionItem.tsx @@ -488,8 +488,6 @@ function ReportActionItem({ onPress: () => Report.resolveActionableMentionWhisper(report.reportID, action, CONST.REPORT.ACTIONABLE_MENTION_WHISPER_RESOLUTION.NOTHING), }, ]; - - // eslint-disable-next-line react-hooks/exhaustive-deps }, [action, isActionableWhisper, report.reportID]); const renderThreadDivider = useMemo( diff --git a/src/pages/iou/HoldReasonPage.tsx b/src/pages/iou/HoldReasonPage.tsx index 18b290a81ea4..9c504388dafc 100644 --- a/src/pages/iou/HoldReasonPage.tsx +++ b/src/pages/iou/HoldReasonPage.tsx @@ -60,7 +60,7 @@ function HoldReasonPage({route}: HoldReasonPageProps) { // We have extra isWorkspaceRequest condition since, for 1:1 requests, canEditMoneyRequest will rightly return false // as we do not allow requestee to edit fields like description and amount. // But, we still want the requestee to be able to put the request on hold - if (!ReportUtils.canEditMoneyRequest(parentReportAction) && isWorkspaceRequest) { + if (ReportActionsUtils.isMoneyRequestAction(parentReportAction) && !ReportUtils.canEditMoneyRequest(parentReportAction) && isWorkspaceRequest) { return; } @@ -78,7 +78,7 @@ function HoldReasonPage({route}: HoldReasonPageProps) { // We have extra isWorkspaceRequest condition since, for 1:1 requests, canEditMoneyRequest will rightly return false // as we do not allow requestee to edit fields like description and amount. // But, we still want the requestee to be able to put the request on hold - if (!ReportUtils.canEditMoneyRequest(parentReportAction) && isWorkspaceRequest) { + if (ReportActionsUtils.isMoneyRequestAction(parentReportAction) && !ReportUtils.canEditMoneyRequest(parentReportAction) && isWorkspaceRequest) { const formErrors = {}; ErrorUtils.addErrorMessage(formErrors, 'reportModified', 'common.error.requestModified'); FormActions.setErrors(ONYXKEYS.FORMS.MONEY_REQUEST_HOLD_FORM, formErrors); diff --git a/src/pages/iou/request/step/IOURequestStepCategory.tsx b/src/pages/iou/request/step/IOURequestStepCategory.tsx index fd5c60537c38..4eabd76067a9 100644 --- a/src/pages/iou/request/step/IOURequestStepCategory.tsx +++ b/src/pages/iou/request/step/IOURequestStepCategory.tsx @@ -16,6 +16,7 @@ import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; import Navigation from '@libs/Navigation/Navigation'; import * as OptionsListUtils from '@libs/OptionsListUtils'; +import * as ReportActionsUtils from '@libs/ReportActionsUtils'; import * as ReportUtils from '@libs/ReportUtils'; import * as TransactionUtils from '@libs/TransactionUtils'; import variables from '@styles/variables'; @@ -100,7 +101,7 @@ function IOURequestStepCategory({ const isSplitBill = iouType === CONST.IOU.TYPE.SPLIT; const canEditSplitBill = isSplitBill && reportAction && session?.accountID === reportAction.actorAccountID && TransactionUtils.areRequiredFieldsEmpty(transaction); // eslint-disable-next-line rulesdir/no-negated-variables - const shouldShowNotFoundPage = isEditing && (isSplitBill ? !canEditSplitBill : !ReportUtils.canEditMoneyRequest(reportAction)); + const shouldShowNotFoundPage = isEditing && (isSplitBill ? !canEditSplitBill : !ReportActionsUtils.isMoneyRequestAction(reportAction) || !ReportUtils.canEditMoneyRequest(reportAction)); const fetchData = () => { if (policy && policyCategories) { diff --git a/src/pages/iou/request/step/IOURequestStepDescription.tsx b/src/pages/iou/request/step/IOURequestStepDescription.tsx index e8388a92e602..a2e6e616fb02 100644 --- a/src/pages/iou/request/step/IOURequestStepDescription.tsx +++ b/src/pages/iou/request/step/IOURequestStepDescription.tsx @@ -14,6 +14,7 @@ import useThemeStyles from '@hooks/useThemeStyles'; import * as ErrorUtils from '@libs/ErrorUtils'; import * as IOUUtils from '@libs/IOUUtils'; import Navigation from '@libs/Navigation/Navigation'; +import * as ReportActionsUtils from '@libs/ReportActionsUtils'; import * as ReportUtils from '@libs/ReportUtils'; import * as TransactionUtils from '@libs/TransactionUtils'; import updateMultilineInputRange from '@libs/updateMultilineInputRange'; @@ -143,7 +144,7 @@ function IOURequestStepDescription({ const isSplitBill = iouType === CONST.IOU.TYPE.SPLIT; const canEditSplitBill = isSplitBill && reportAction && session?.accountID === reportAction.actorAccountID && TransactionUtils.areRequiredFieldsEmpty(transaction); // eslint-disable-next-line rulesdir/no-negated-variables - const shouldShowNotFoundPage = isEditing && (isSplitBill ? !canEditSplitBill : !ReportUtils.canEditMoneyRequest(reportAction)); + const shouldShowNotFoundPage = isEditing && (isSplitBill ? !canEditSplitBill : !ReportActionsUtils.isMoneyRequestAction(reportAction) || !ReportUtils.canEditMoneyRequest(reportAction)); return ( PolicyUtils.getTagLists(policyTags), [policyTags]); const shouldShowTag = ReportUtils.isReportInGroupPolicy(report) && (transactionTag || OptionsListUtils.hasEnabledTags(policyTagLists)); // eslint-disable-next-line rulesdir/no-negated-variables - const shouldShowNotFoundPage = !shouldShowTag || (isEditing && (isSplitBill ? !canEditSplitBill : reportAction && !canEditMoneyRequest(reportAction))); + const shouldShowNotFoundPage = + !shouldShowTag || (isEditing && (isSplitBill ? !canEditSplitBill : !ReportActionsUtils.isMoneyRequestAction(reportAction) || !ReportUtils.canEditMoneyRequest(reportAction))); const navigateBack = () => { Navigation.goBack(backTo); diff --git a/src/types/onyx/OriginalMessage.ts b/src/types/onyx/OriginalMessage.ts index a2ebcf42961f..1f73fabe66c9 100644 --- a/src/types/onyx/OriginalMessage.ts +++ b/src/types/onyx/OriginalMessage.ts @@ -70,9 +70,7 @@ type OriginalMessageIOU = { whisperedTo?: number[]; }; -/** - * - */ +/** Names of moderation decisions */ type DecisionName = ValueOf< Pick< typeof CONST.MODERATION, @@ -322,9 +320,7 @@ type OriginalMessageModifiedExpense = { /** Model of `reimbursement queued` report action */ type OriginalMessageReimbursementQueued = { - /** - * - */ + /** How is the payment getting reimbursed */ paymentType: DeepValueOf; }; @@ -404,235 +400,120 @@ type OriginalMessageApproved = { }; /** The map type of original message */ -// eslint-disable-next-line jsdoc/require-jsdoc type OriginalMessageMap = { - /** - * - */ + /** */ [CONST.REPORT.ACTIONS.TYPE.ACTIONABLE_JOIN_REQUEST]: OriginalMessageJoinPolicyChangeLog; - /** - * - */ + /** */ [CONST.REPORT.ACTIONS.TYPE.ACTIONABLE_MENTION_WHISPER]: OriginalMessageActionableMentionWhisper; - /** - * - */ + /** */ [CONST.REPORT.ACTIONS.TYPE.ACTIONABLE_REPORT_MENTION_WHISPER]: OriginalMessageActionableReportMentionWhisper; - /** - * - */ + /** */ [CONST.REPORT.ACTIONS.TYPE.ACTIONABLE_TRACK_EXPENSE_WHISPER]: OriginalMessageActionableTrackedExpenseWhisper; - /** - * - */ + /** */ [CONST.REPORT.ACTIONS.TYPE.ADD_COMMENT]: OriginalMessageAddComment; - /** - * - */ + /** */ [CONST.REPORT.ACTIONS.TYPE.APPROVED]: OriginalMessageApproved; - /** - * - */ + /** */ [CONST.REPORT.ACTIONS.TYPE.CHANGE_FIELD]: never; - /** - * - */ + /** */ [CONST.REPORT.ACTIONS.TYPE.CHANGE_POLICY]: never; - /** - * - */ + /** */ [CONST.REPORT.ACTIONS.TYPE.CHANGE_TYPE]: never; - /** - * - */ + /** */ [CONST.REPORT.ACTIONS.TYPE.CHRONOS_OOO_LIST]: OriginalMessageChronosOOOList; - /** - * - */ + /** */ [CONST.REPORT.ACTIONS.TYPE.CLOSED]: OriginalMessageClosed; - /** - * - */ + /** */ [CONST.REPORT.ACTIONS.TYPE.CREATED]: never; - /** - * - */ + /** */ [CONST.REPORT.ACTIONS.TYPE.DELEGATE_SUBMIT]: never; - /** - * - */ + /** */ [CONST.REPORT.ACTIONS.TYPE.DELETED_ACCOUNT]: never; - /** - * - */ + /** */ [CONST.REPORT.ACTIONS.TYPE.DISMISSED_VIOLATION]: OriginalMessageDismissedViolation; - /** - * - */ + /** */ [CONST.REPORT.ACTIONS.TYPE.DONATION]: never; - /** - * - */ + /** */ [CONST.REPORT.ACTIONS.TYPE.EXPORTED_TO_CSV]: never; - /** - * - */ + /** */ [CONST.REPORT.ACTIONS.TYPE.EXPORTED_TO_INTEGRATION]: never; - /** - * - */ + /** */ [CONST.REPORT.ACTIONS.TYPE.EXPORTED_TO_QUICK_BOOKS]: never; - /** - * - */ + /** */ [CONST.REPORT.ACTIONS.TYPE.FORWARDED]: never; - /** - * - */ + /** */ [CONST.REPORT.ACTIONS.TYPE.HOLD]: never; - /** - * - */ + /** */ [CONST.REPORT.ACTIONS.TYPE.HOLD_COMMENT]: never; - /** - * - */ + /** */ [CONST.REPORT.ACTIONS.TYPE.INTEGRATIONS_MESSAGE]: never; - /** - * - */ + /** */ [CONST.REPORT.ACTIONS.TYPE.IOU]: OriginalMessageIOU; - /** - * - */ + /** */ [CONST.REPORT.ACTIONS.TYPE.MANAGER_ATTACH_RECEIPT]: never; - /** - * - */ + /** */ [CONST.REPORT.ACTIONS.TYPE.MANAGER_DETACH_RECEIPT]: never; - /** - * - */ + /** */ [CONST.REPORT.ACTIONS.TYPE.MARK_REIMBURSED_FROM_INTEGRATION]: never; - /** - * - */ + /** */ [CONST.REPORT.ACTIONS.TYPE.MARKED_REIMBURSED]: never; - /** - * - */ + /** */ [CONST.REPORT.ACTIONS.TYPE.MERGED_WITH_CASH_TRANSACTION]: never; - /** - * - */ + /** */ [CONST.REPORT.ACTIONS.TYPE.MODIFIED_EXPENSE]: OriginalMessageModifiedExpense; - /** - * - */ + /** */ [CONST.REPORT.ACTIONS.TYPE.MOVED]: OriginalMessageMoved; - /** - * - */ + /** */ [CONST.REPORT.ACTIONS.TYPE.OUTDATED_BANK_ACCOUNT]: never; - /** - * - */ + /** */ [CONST.REPORT.ACTIONS.TYPE.REIMBURSEMENT_ACH_BOUNCE]: never; - /** - * - */ + /** */ [CONST.REPORT.ACTIONS.TYPE.REIMBURSEMENT_ACH_CANCELLED]: never; - /** - * - */ + /** */ [CONST.REPORT.ACTIONS.TYPE.REIMBURSEMENT_ACCOUNT_CHANGED]: never; - /** - * - */ + /** */ [CONST.REPORT.ACTIONS.TYPE.REIMBURSEMENT_DEQUEUED]: OriginalMessageReimbursementDequeued; - /** - * - */ + /** */ [CONST.REPORT.ACTIONS.TYPE.REIMBURSEMENT_DELAYED]: never; - /** - * - */ + /** */ [CONST.REPORT.ACTIONS.TYPE.REIMBURSEMENT_QUEUED]: OriginalMessageReimbursementQueued; - /** - * - */ + /** */ [CONST.REPORT.ACTIONS.TYPE.REIMBURSEMENT_REQUESTED]: never; - /** - * - */ + /** */ [CONST.REPORT.ACTIONS.TYPE.REIMBURSEMENT_SETUP]: never; - /** - * - */ + /** */ [CONST.REPORT.ACTIONS.TYPE.RENAMED]: OriginalMessageRenamed; - /** - * - */ + /** */ [CONST.REPORT.ACTIONS.TYPE.REPORT_PREVIEW]: OriginalMessageReportPreview; - /** - * - */ + /** */ [CONST.REPORT.ACTIONS.TYPE.SELECTED_FOR_RANDOM_AUDIT]: never; - /** - * - */ + /** */ [CONST.REPORT.ACTIONS.TYPE.SHARE]: never; - /** - * - */ + /** */ [CONST.REPORT.ACTIONS.TYPE.STRIPE_PAID]: never; - /** - * - */ + /** */ [CONST.REPORT.ACTIONS.TYPE.SUBMITTED]: OriginalMessageSubmitted; - /** - * - */ + /** */ [CONST.REPORT.ACTIONS.TYPE.TASK_CANCELLED]: never; - /** - * - */ + /** */ [CONST.REPORT.ACTIONS.TYPE.TASK_COMPLETED]: never; - /** - * - */ + /** */ [CONST.REPORT.ACTIONS.TYPE.TASK_EDITED]: never; - /** - * - */ + /** */ [CONST.REPORT.ACTIONS.TYPE.TASK_REOPENED]: never; - /** - * - */ + /** */ [CONST.REPORT.ACTIONS.TYPE.TAKE_CONTROL]: never; - /** - * - */ + /** */ [CONST.REPORT.ACTIONS.TYPE.UNAPPROVED]: never; - /** - * - */ + /** */ [CONST.REPORT.ACTIONS.TYPE.UNHOLD]: never; - /** - * - */ + /** */ [CONST.REPORT.ACTIONS.TYPE.UNSHARE]: never; - /** - * - */ + /** */ [CONST.REPORT.ACTIONS.TYPE.UPDATE_GROUP_CHAT_MEMBER_ROLE]: never; - /** - * - */ + /** */ [CONST.REPORT.ACTIONS.TYPE.REIMBURSEMENT_SETUP_REQUESTED]: never; - /** - * - */ + /** */ [CONST.REPORT.ACTIONS.TYPE.TRIPPREVIEW]: OriginalMessageTripRoomPreview; } & { [T in ValueOf]: OriginalMessageChangeLog; @@ -640,24 +521,19 @@ type OriginalMessageMap = { [T in ValueOf]: OriginalMessageChangeLog; }; -/** - * - */ +/** */ // eslint-disable-next-line @typescript-eslint/no-unused-vars type AssertOriginalMessageDefinedForAllActions = AssertTypesEqual< ReportActionName, keyof OriginalMessageMap, `Error: Types don't match, OriginalMessageMap type is missing: ${Exclude}` >; -/** - * - */ + +/** */ type OriginalMessage = OriginalMessageMap[T]; // Note: type-fest's ConditionalKeys does not work correctly with objects containing `never`: https://github.com/sindresorhus/type-fest/issues/878 -/** - * - */ +/** */ type ReportActionNamesWithHTMLMessage = { [TKey in keyof OriginalMessageMap]-?: OriginalMessageMap[TKey] extends { /** @@ -672,9 +548,7 @@ type ReportActionNamesWithHTMLMessage = { }[keyof OriginalMessageMap]; const REPORT_ACTIONS_WITH_HTML_MESSAGE = [CONST.REPORT.ACTIONS.TYPE.ADD_COMMENT, CONST.REPORT.ACTIONS.TYPE.RENAMED] as const; -/** - * - */ +/** */ // eslint-disable-next-line @typescript-eslint/no-unused-vars type AssertAllActionsWithHTMLAreListed = AssertTypesEqual< ReportActionNamesWithHTMLMessage, @@ -683,7 +557,6 @@ type AssertAllActionsWithHTMLAreListed = AssertTypesEqual< >; export default OriginalMessage; -export {REPORT_ACTIONS_WITH_HTML_MESSAGE}; export type { DecisionName, OriginalMessageIOU, diff --git a/src/types/onyx/ReportActionName.ts b/src/types/onyx/ReportActionName.ts index a9cfe4ecbe2c..b5a16c88242a 100644 --- a/src/types/onyx/ReportActionName.ts +++ b/src/types/onyx/ReportActionName.ts @@ -1,9 +1,7 @@ import type CONST from '@src/CONST'; import type DeepValueOf from '@src/types/utils/DeepValueOf'; -/** - * - */ +/** The name (or type) of a reportAction */ type ReportActionName = DeepValueOf; export default ReportActionName; From 372e00d6065b9376f49e3451ce13e8488e01e1da Mon Sep 17 00:00:00 2001 From: nkdengineer Date: Wed, 12 Jun 2024 13:52:53 +0700 Subject: [PATCH 36/45] fix lint --- src/libs/ReportActionsUtils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/ReportActionsUtils.ts b/src/libs/ReportActionsUtils.ts index acceea7bad8c..71b3646d68ba 100644 --- a/src/libs/ReportActionsUtils.ts +++ b/src/libs/ReportActionsUtils.ts @@ -3,7 +3,7 @@ import _ from 'lodash'; import lodashFindLast from 'lodash/findLast'; import type {OnyxCollection, OnyxEntry, OnyxUpdate} from 'react-native-onyx'; import Onyx from 'react-native-onyx'; -import type {SetFieldType, SetRequired, ValueOf} from 'type-fest'; +import type {ValueOf} from 'type-fest'; import CONST from '@src/CONST'; import type {TranslationPaths} from '@src/languages/types'; import ONYXKEYS from '@src/ONYXKEYS'; From 85ca4dc2cfc49738ca196e32eebafdf609340668 Mon Sep 17 00:00:00 2001 From: nkdengineer Date: Thu, 13 Jun 2024 18:37:26 +0700 Subject: [PATCH 37/45] fix lint --- src/libs/ReportActionsUtils.ts | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/libs/ReportActionsUtils.ts b/src/libs/ReportActionsUtils.ts index 811587c5f412..cbdef78903aa 100644 --- a/src/libs/ReportActionsUtils.ts +++ b/src/libs/ReportActionsUtils.ts @@ -890,11 +890,9 @@ function getMostRecentReportActionLastModified(): string { * @returns The report preview action or `null` if one couldn't be found */ function getReportPreviewAction(chatReportID: string, iouReportID: string): OnyxEntry> { - return ( - Object.values(allReportActions?.[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chatReportID}`] ?? {}).find( - (reportAction): reportAction is ReportAction => - reportAction && isActionOfType(reportAction, CONST.REPORT.ACTIONS.TYPE.REPORT_PREVIEW) && getOriginalMessage(reportAction)?.linkedReportID === iouReportID, - ) + return Object.values(allReportActions?.[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chatReportID}`] ?? {}).find( + (reportAction): reportAction is ReportAction => + reportAction && isActionOfType(reportAction, CONST.REPORT.ACTIONS.TYPE.REPORT_PREVIEW) && getOriginalMessage(reportAction)?.linkedReportID === iouReportID, ); } From a1908d882fac36b54df488336da5b14ada2fa614 Mon Sep 17 00:00:00 2001 From: nkdengineer Date: Fri, 14 Jun 2024 11:58:31 +0700 Subject: [PATCH 38/45] fix lint --- src/pages/home/report/ReportActionItem.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/pages/home/report/ReportActionItem.tsx b/src/pages/home/report/ReportActionItem.tsx index e707271a94a0..e4c166099860 100644 --- a/src/pages/home/report/ReportActionItem.tsx +++ b/src/pages/home/report/ReportActionItem.tsx @@ -1081,7 +1081,8 @@ export default withOnyx({ }, }, linkedTransactionRouteError: { - key: ({action}) => `${ONYXKEYS.COLLECTION.TRANSACTION}${ReportActionsUtils.isMoneyRequestAction(action) ? ReportActionsUtils.getOriginalMessage(action)?.IOUTransactionID ?? -1 : -1}`, + key: ({action}) => + `${ONYXKEYS.COLLECTION.TRANSACTION}${ReportActionsUtils.isMoneyRequestAction(action) ? ReportActionsUtils.getOriginalMessage(action)?.IOUTransactionID ?? -1 : -1}`, selector: (transaction: OnyxEntry) => transaction?.errorFields?.route ?? null, }, modal: { From fa896a04606c58844b67b39b00c5a88614f98d6d Mon Sep 17 00:00:00 2001 From: isogit123 <34800355+isogit123@users.noreply.github.com> Date: Wed, 19 Jun 2024 12:11:43 +0000 Subject: [PATCH 39/45] Use correct hover background for MenuItem --- src/components/MenuItem.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/MenuItem.tsx b/src/components/MenuItem.tsx index c1fe4270d4e1..3660ea792b21 100644 --- a/src/components/MenuItem.tsx +++ b/src/components/MenuItem.tsx @@ -514,6 +514,7 @@ function MenuItem( ...(Array.isArray(wrapperStyle) ? wrapperStyle : [wrapperStyle]), !focused && (isHovered || pressed) && hoverAndPressStyle, shouldGreyOutWhenDisabled && disabled && styles.buttonOpacityDisabled, + isHovered && !pressed && styles.hoveredComponentBG ] as StyleProp } disabledStyle={shouldUseDefaultCursorWhenDisabled && [styles.cursorDefault]} From 9fa006e00de9e60fb6d1f516ba15828b55ad1576 Mon Sep 17 00:00:00 2001 From: isogit123 <34800355+isogit123@users.noreply.github.com> Date: Wed, 19 Jun 2024 12:38:33 +0000 Subject: [PATCH 40/45] Empty commit to rerun checks From 2f94fdebea56617960ec12b833683a700d95b73b Mon Sep 17 00:00:00 2001 From: James Dean Date: Wed, 19 Jun 2024 13:01:08 -0700 Subject: [PATCH 41/45] Update en.ts --- src/languages/en.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/languages/en.ts b/src/languages/en.ts index 498635cdb449..43589265ed2f 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -2085,7 +2085,7 @@ export default { [`${CONST.QUICKBOOKS_REIMBURSABLE_ACCOUNT_TYPE.VENDOR_BILL}Description`]: "We'll create an itemized vendor bill for each Expensify report with the date of the last expense, and add it to the account below. If this period is closed, we'll post to the 1st of the next open period.", - [`${CONST.QUICKBOOKS_NON_REIMBURSABLE_EXPORT_ACCOUNT_TYPE.DEBIT_CARD}AccountDescription`]: 'Debit card transactions will export to the bank account below.”', + [`${CONST.QUICKBOOKS_NON_REIMBURSABLE_EXPORT_ACCOUNT_TYPE.DEBIT_CARD}AccountDescription`]: 'Debit card transactions will export to the bank account below.', [`${CONST.QUICKBOOKS_NON_REIMBURSABLE_EXPORT_ACCOUNT_TYPE.CREDIT_CARD}AccountDescription`]: 'Credit card transactions will export to the bank account below.', [`${CONST.QUICKBOOKS_REIMBURSABLE_ACCOUNT_TYPE.VENDOR_BILL}AccountDescription`]: 'Choose a vendor to apply to all credit card transactions.', From c2b0c8a19fec3f9cb15db06b2a74420d30ce3050 Mon Sep 17 00:00:00 2001 From: James Dean Date: Wed, 19 Jun 2024 13:02:36 -0700 Subject: [PATCH 42/45] Update es.ts --- src/languages/es.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/languages/es.ts b/src/languages/es.ts index 3969e255ec28..9bdd64426631 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -2114,7 +2114,7 @@ export default { 'Crearemos una factura de proveedor desglosada para cada informe de Expensify con la fecha del último gasto, y la añadiremos a la cuenta a continuación. Si este periodo está cerrado, lo contabilizaremos en el día 1 del siguiente periodo abierto.', [`${CONST.QUICKBOOKS_NON_REIMBURSABLE_EXPORT_ACCOUNT_TYPE.DEBIT_CARD}AccountDescription`]: - 'Las transacciones con tarjeta de débito se exportarán a la cuenta bancaria que aparece a continuación.”', + 'Las transacciones con tarjeta de débito se exportarán a la cuenta bancaria que aparece a continuación.', [`${CONST.QUICKBOOKS_NON_REIMBURSABLE_EXPORT_ACCOUNT_TYPE.CREDIT_CARD}AccountDescription`]: 'Las transacciones con tarjeta de crédito se exportarán a la cuenta bancaria que aparece a continuación.', [`${CONST.QUICKBOOKS_REIMBURSABLE_ACCOUNT_TYPE.VENDOR_BILL}AccountDescription`]: 'Selecciona el proveedor que se aplicará a todas las transacciones con tarjeta de crédito.', From 6b5466e79eebc24418d7edbe4e7e266d47bc1cbf Mon Sep 17 00:00:00 2001 From: nkdengineer Date: Thu, 20 Jun 2024 10:22:26 +0700 Subject: [PATCH 43/45] remove unused type --- src/pages/home/report/ReportActionItem.tsx | 2 +- src/types/onyx/OriginalMessage.ts | 29 ++-------------------- src/types/onyx/ReportAction.ts | 12 +++------ 3 files changed, 6 insertions(+), 37 deletions(-) diff --git a/src/pages/home/report/ReportActionItem.tsx b/src/pages/home/report/ReportActionItem.tsx index a4b9ed3ed4e4..6348bc99949e 100644 --- a/src/pages/home/report/ReportActionItem.tsx +++ b/src/pages/home/report/ReportActionItem.tsx @@ -782,7 +782,7 @@ function ReportActionItem({ } if (action.actionName === CONST.REPORT.ACTIONS.TYPE.CREATED) { - const transactionID = (parentReportActionForTransactionThread as OnyxTypes.OriginalMessageIOU)?.originalMessage.IOUTransactionID; + const transactionID = ReportActionsUtils.isMoneyRequestAction(parentReportActionForTransactionThread) ? ReportActionsUtils.getOriginalMessage(parentReportActionForTransactionThread)?.IOUTransactionID : '-1'; return ( = OriginalMessageMap[T]; -// Note: type-fest's ConditionalKeys does not work correctly with objects containing `never`: https://github.com/sindresorhus/type-fest/issues/878 -/** */ -type ReportActionNamesWithHTMLMessage = { - [TKey in keyof OriginalMessageMap]-?: OriginalMessageMap[TKey] extends { - /** - * - */ - html: string; - } - ? OriginalMessageMap[TKey] extends never - ? never - : TKey - : never; -}[keyof OriginalMessageMap]; -const REPORT_ACTIONS_WITH_HTML_MESSAGE = [CONST.REPORT.ACTIONS.TYPE.ADD_COMMENT, CONST.REPORT.ACTIONS.TYPE.RENAMED] as const; - -/** */ -// eslint-disable-next-line @typescript-eslint/no-unused-vars -type AssertAllActionsWithHTMLAreListed = AssertTypesEqual< - ReportActionNamesWithHTMLMessage, - TupleToUnion, - `Error: Types don't match, REPORT_ACTIONS_WITH_HTML_MESSAGE is missing: ${Exclude}` ->; - export default OriginalMessage; export type { DecisionName, @@ -563,7 +539,6 @@ export type { ChronosOOOEvent, PaymentMethodType, OriginalMessageSource, - ReportActionNamesWithHTMLMessage, Reaction, Decision, OriginalMessageChangeLog, diff --git a/src/types/onyx/ReportAction.ts b/src/types/onyx/ReportAction.ts index ce498588086e..8c8386b239a5 100644 --- a/src/types/onyx/ReportAction.ts +++ b/src/types/onyx/ReportAction.ts @@ -7,7 +7,7 @@ import type CollectionDataSet from '@src/types/utils/CollectionDataSet'; import type {EmptyObject} from '@src/types/utils/EmptyObject'; import type * as OnyxCommon from './OnyxCommon'; import type OriginalMessage from './OriginalMessage'; -import type {Decision, ReportActionNamesWithHTMLMessage} from './OriginalMessage'; +import type {Decision} from './OriginalMessage'; import type {NotificationPreference} from './Report'; import type ReportActionName from './ReportActionName'; import type {Receipt} from './Transaction'; @@ -277,13 +277,7 @@ type ReportAction = ReportActionB previousMessage?: (OriginalMessage & Message) | Array; }; -/** - * - */ -type ReportActionWithHTMLMessage = ReportAction; -/** - * - */ +/** */ type ReportActionChangeLog = ReportAction>>; /** Record of report actions, indexed by report action ID */ @@ -293,4 +287,4 @@ type ReportActions = Record; type ReportActionsCollectionDataSet = CollectionDataSet; export default ReportAction; -export type {ReportActions, Message, LinkMetadata, OriginalMessage, ReportActionsCollectionDataSet, ReportActionWithHTMLMessage, ReportActionChangeLog}; +export type {ReportActions, Message, LinkMetadata, OriginalMessage, ReportActionsCollectionDataSet, ReportActionChangeLog}; From 839df17c93fae912e3ea91c7db519cd8f22858b6 Mon Sep 17 00:00:00 2001 From: nkdengineer Date: Thu, 20 Jun 2024 11:19:37 +0700 Subject: [PATCH 44/45] fix lint --- src/components/ReportActionItem/TripRoomPreview.tsx | 2 +- src/pages/home/report/ReportActionItem.tsx | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/components/ReportActionItem/TripRoomPreview.tsx b/src/components/ReportActionItem/TripRoomPreview.tsx index 2243773c407b..53c887f320ef 100644 --- a/src/components/ReportActionItem/TripRoomPreview.tsx +++ b/src/components/ReportActionItem/TripRoomPreview.tsx @@ -18,6 +18,7 @@ import * as CurrencyUtils from '@libs/CurrencyUtils'; import DateUtils from '@libs/DateUtils'; import * as DeviceCapabilities from '@libs/DeviceCapabilities'; import Navigation from '@libs/Navigation/Navigation'; +import {getReportActionText} from '@libs/ReportActionsUtils'; import * as ReportUtils from '@libs/ReportUtils'; import * as TripReservationUtils from '@libs/TripReservationUtils'; import type {ContextMenuAnchor} from '@pages/home/report/ContextMenu/ReportActionContextMenu'; @@ -28,7 +29,6 @@ import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import type {ReportAction} from '@src/types/onyx'; import type {Reservation} from '@src/types/onyx/Transaction'; -import { getReportActionText } from '@libs/ReportActionsUtils'; type TripRoomPreviewProps = { /** All the data of the action */ diff --git a/src/pages/home/report/ReportActionItem.tsx b/src/pages/home/report/ReportActionItem.tsx index 6348bc99949e..b5d77465d1f9 100644 --- a/src/pages/home/report/ReportActionItem.tsx +++ b/src/pages/home/report/ReportActionItem.tsx @@ -782,7 +782,9 @@ function ReportActionItem({ } if (action.actionName === CONST.REPORT.ACTIONS.TYPE.CREATED) { - const transactionID = ReportActionsUtils.isMoneyRequestAction(parentReportActionForTransactionThread) ? ReportActionsUtils.getOriginalMessage(parentReportActionForTransactionThread)?.IOUTransactionID : '-1'; + const transactionID = ReportActionsUtils.isMoneyRequestAction(parentReportActionForTransactionThread) + ? ReportActionsUtils.getOriginalMessage(parentReportActionForTransactionThread)?.IOUTransactionID + : '-1'; return ( Date: Fri, 21 Jun 2024 08:53:31 +0300 Subject: [PATCH 45/45] Add trailing , Co-authored-by: Roji Philip --- src/components/MenuItem.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/MenuItem.tsx b/src/components/MenuItem.tsx index 3660ea792b21..fa58b5cd5f5f 100644 --- a/src/components/MenuItem.tsx +++ b/src/components/MenuItem.tsx @@ -514,7 +514,7 @@ function MenuItem( ...(Array.isArray(wrapperStyle) ? wrapperStyle : [wrapperStyle]), !focused && (isHovered || pressed) && hoverAndPressStyle, shouldGreyOutWhenDisabled && disabled && styles.buttonOpacityDisabled, - isHovered && !pressed && styles.hoveredComponentBG + isHovered && !pressed && styles.hoveredComponentBG, ] as StyleProp } disabledStyle={shouldUseDefaultCursorWhenDisabled && [styles.cursorDefault]}