From 8291b9823924841114747a9f963400ee51be32d5 Mon Sep 17 00:00:00 2001 From: DylanDylann Date: Mon, 23 Jun 2025 15:12:45 +0700 Subject: [PATCH 01/27] allow remove demo transaction --- src/libs/ReportSecondaryActionUtils.ts | 5 +++++ src/libs/TransactionUtils/index.ts | 5 +++++ src/pages/ReportDetailsPage.tsx | 4 +++- src/types/onyx/Transaction.ts | 3 +++ 4 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/libs/ReportSecondaryActionUtils.ts b/src/libs/ReportSecondaryActionUtils.ts index bd91d7a5739f..1e244b6658ba 100644 --- a/src/libs/ReportSecondaryActionUtils.ts +++ b/src/libs/ReportSecondaryActionUtils.ts @@ -48,6 +48,7 @@ import { getOriginalTransactionWithSplitInfo, hasReceipt as hasReceiptTransactionUtils, isCardTransaction as isCardTransactionUtils, + isDemoTransaction, isDuplicate, isOnHold as isOnHoldTransactionUtils, isPending, @@ -413,6 +414,10 @@ function isDeleteAction(report: Report, reportTransactions: Transaction[], repor const isReportOpenOrProcessing = isOpenReportUtils(report) || isProcessingReportUtils(report); const isSingleTransaction = reportTransactions.length === 1; + if (reportTransactions.every((t) => isDemoTransaction(t))) { + return true; + } + if (isUnreported) { return isOwner; } diff --git a/src/libs/TransactionUtils/index.ts b/src/libs/TransactionUtils/index.ts index 090971f1be60..6b16db11ea00 100644 --- a/src/libs/TransactionUtils/index.ts +++ b/src/libs/TransactionUtils/index.ts @@ -323,6 +323,10 @@ function hasReceiptSource(transaction: OnyxInputOrEntry): boolean { return !!transaction?.receipt?.source; } +function isDemoTransaction(transaction: OnyxInputOrEntry): boolean { + return transaction?.comment?.isDemoTransaction ?? false; +} + function isMerchantMissing(transaction: OnyxEntry) { if (transaction?.modifiedMerchant && transaction.modifiedMerchant !== '') { return transaction.modifiedMerchant === CONST.TRANSACTION.PARTIAL_TRANSACTION_MERCHANT; @@ -1733,6 +1737,7 @@ export { getTransactionPendingAction, isTransactionPendingDelete, createUnreportedExpenseSections, + isDemoTransaction, }; export type {TransactionChanges}; diff --git a/src/pages/ReportDetailsPage.tsx b/src/pages/ReportDetailsPage.tsx index 6f02b73a378b..68b0954cbe53 100644 --- a/src/pages/ReportDetailsPage.tsx +++ b/src/pages/ReportDetailsPage.tsx @@ -92,6 +92,7 @@ import { shouldUseFullTitleToDisplay, } from '@libs/ReportUtils'; import StringUtils from '@libs/StringUtils'; +import {isDemoTransaction} from '@libs/TransactionUtils'; import {deleteMoneyRequest, deleteTrackExpense, getNavigationUrlAfterTrackExpenseDelete, getNavigationUrlOnMoneyRequestDelete} from '@userActions/IOU'; import { clearAvatarErrors, @@ -279,7 +280,8 @@ function ReportDetailsPage({policies, report, route, reportMetadata}: ReportDeta const canDeleteRequest = isActionOwner && (canDeleteTransaction(moneyRequestReport, isMoneyRequestReportArchived) || isSelfDMTrackExpenseReport) && !isDeletedParentAction; const iouTransactionID = isMoneyRequestAction(requestParentReportAction) ? getOriginalMessage(requestParentReportAction)?.IOUTransactionID : ''; const isCardTransactionCanBeDeleted = canDeleteCardTransactionByLiabilityType(iouTransactionID); - const shouldShowDeleteButton = shouldShowTaskDeleteButton || (canDeleteRequest && isCardTransactionCanBeDeleted); + const [transaction] = useOnyx(`${ONYXKEYS.COLLECTION.TRANSACTION}${iouTransactionID}`, {canBeMissing: true}); + const shouldShowDeleteButton = shouldShowTaskDeleteButton || (canDeleteRequest && isCardTransactionCanBeDeleted) || isDemoTransaction(transaction); useEffect(() => { if (canDeleteRequest) { return; diff --git a/src/types/onyx/Transaction.ts b/src/types/onyx/Transaction.ts index 6898997336c0..0ca2909fcd4a 100644 --- a/src/types/onyx/Transaction.ts +++ b/src/types/onyx/Transaction.ts @@ -69,6 +69,9 @@ type Comment = { /** Whether the transaction comment is loading */ isLoading?: boolean; + /** Whether the transaction comment is a demo transaction */ + isDemoTransaction?: boolean; + /** Type of the transaction */ type?: ValueOf; From 4915983a6f03f42b3a248f0962b64230a7026a34 Mon Sep 17 00:00:00 2001 From: DylanDylann Date: Thu, 26 Jun 2025 13:12:56 +0700 Subject: [PATCH 02/27] new update --- src/libs/ReportUtils.ts | 7 ++++++- .../report/ContextMenu/BaseReportActionContextMenu.tsx | 8 ++++++++ src/pages/home/report/ContextMenu/ContextMenuActions.tsx | 9 +++++++-- 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 7b474d7e222e..ba1c0f2395e6 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -239,6 +239,7 @@ import { hasViolation, hasWarningTypeViolation, isCardTransaction as isCardTransactionTransactionUtils, + isDemoTransaction, isDistanceRequest, isExpensifyCardTransaction, isFetchingWaypointsFromServer, @@ -2503,11 +2504,15 @@ function canDeleteCardTransactionByLiabilityType(iouTransactionID?: string): boo * Can only delete if the author is this user and the action is an ADD_COMMENT action or an IOU action in an unsettled report, or if the user is a * policy admin */ -function canDeleteReportAction(reportAction: OnyxInputOrEntry, reportID: string | undefined): boolean { +function canDeleteReportAction(reportAction: OnyxInputOrEntry, reportID: string | undefined, transactions?: Transaction[]): boolean { const report = getReportOrDraftReport(reportID); const isActionOwner = reportAction?.actorAccountID === currentUserAccountID; const policy = allPolicies?.[`${ONYXKEYS.COLLECTION.POLICY}${report?.policyID}`] ?? null; + if (transactions?.every((t) => isDemoTransaction(t))) { + return true; + } + if (isMoneyRequestAction(reportAction)) { const iouTransactionID = getOriginalMessage(reportAction)?.IOUTransactionID; const isCardTransactionCanBeDeleted = canDeleteCardTransactionByLiabilityType(iouTransactionID); diff --git a/src/pages/home/report/ContextMenu/BaseReportActionContextMenu.tsx b/src/pages/home/report/ContextMenu/BaseReportActionContextMenu.tsx index c902f0b44069..bce959c9e774 100755 --- a/src/pages/home/report/ContextMenu/BaseReportActionContextMenu.tsx +++ b/src/pages/home/report/ContextMenu/BaseReportActionContextMenu.tsx @@ -160,6 +160,13 @@ function BaseReportActionContextMenu({ return reportActions[reportActionID]; }, [reportActions, reportActionID]); + const [linkedTransactions] = useOnyx(ONYXKEYS.COLLECTION.TRANSACTION, { + selector: (transactions) => { + return Object.values(transactions ?? {}).filter((t) => t?.reportID === reportAction?.childReportID); + }, + canBeMissing: true, + }); + const sourceID = getSourceIDFromReportAction(reportAction); const [download] = useOnyx(`${ONYXKEYS.COLLECTION.DOWNLOAD}${sourceID}`, {canBeMissing: true}); @@ -226,6 +233,7 @@ function BaseReportActionContextMenu({ moneyRequestAction, areHoldRequirementsMet, account, + transactions: linkedTransactions ?? [], }), ); diff --git a/src/pages/home/report/ContextMenu/ContextMenuActions.tsx b/src/pages/home/report/ContextMenu/ContextMenuActions.tsx index a650a484536d..2e570236d08c 100644 --- a/src/pages/home/report/ContextMenu/ContextMenuActions.tsx +++ b/src/pages/home/report/ContextMenu/ContextMenuActions.tsx @@ -171,6 +171,7 @@ type ShouldShow = (args: { moneyRequestAction: ReportAction | undefined; areHoldRequirementsMet: boolean; account: OnyxEntry; + transactions: Transaction[]; }) => boolean; type ContextMenuActionPayload = { @@ -819,11 +820,15 @@ const ContextMenuActions: ContextMenuAction[] = [ isAnonymousAction: false, textTranslateKey: 'reportActionContextMenu.deleteAction', icon: Expensicons.Trashcan, - shouldShow: ({type, reportAction, isArchivedRoom, isChronosReport, reportID, moneyRequestAction}) => + shouldShow: ({type, reportAction, isArchivedRoom, isChronosReport, reportID, moneyRequestAction, transactions}) => // Until deleting parent threads is supported in FE, we will prevent the user from deleting a thread parent !!reportID && type === CONST.CONTEXT_MENU_TYPES.REPORT_ACTION && - canDeleteReportAction(moneyRequestAction ?? reportAction, isMoneyRequestAction(moneyRequestAction) ? getOriginalMessage(moneyRequestAction)?.IOUReportID : reportID) && + canDeleteReportAction( + moneyRequestAction ?? reportAction, + isMoneyRequestAction(moneyRequestAction) ? getOriginalMessage(moneyRequestAction)?.IOUReportID : reportID, + transactions, + ) && !isArchivedRoom && !isChronosReport && !isMessageDeleted(reportAction), From 3ac15e6f39d53813e69e388687bbd66703f0ecc1 Mon Sep 17 00:00:00 2001 From: DylanDylann Date: Thu, 26 Jun 2025 13:33:39 +0700 Subject: [PATCH 03/27] fix UTs --- Mobile-Expensify | 2 +- src/libs/ReportSecondaryActionUtils.ts | 2 +- .../home/report/ContextMenu/BaseReportActionContextMenu.tsx | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Mobile-Expensify b/Mobile-Expensify index a56575e0a6dc..b953673f6612 160000 --- a/Mobile-Expensify +++ b/Mobile-Expensify @@ -1 +1 @@ -Subproject commit a56575e0a6dc18ef7adf7bd56ad8f2f6b81867ae +Subproject commit b953673f6612b8579693c8b58c07bee620d4f83e diff --git a/src/libs/ReportSecondaryActionUtils.ts b/src/libs/ReportSecondaryActionUtils.ts index 0c243d25a41f..a86785c35d41 100644 --- a/src/libs/ReportSecondaryActionUtils.ts +++ b/src/libs/ReportSecondaryActionUtils.ts @@ -413,7 +413,7 @@ function isDeleteAction(report: Report, reportTransactions: Transaction[], repor const isReportOpenOrProcessing = isOpenReportUtils(report) || isProcessingReportUtils(report); const isSingleTransaction = reportTransactions.length === 1; - if (reportTransactions.every((t) => isDemoTransaction(t))) { + if (reportTransactions.length > 0 && reportTransactions.every((t) => isDemoTransaction(t))) { return true; } diff --git a/src/pages/home/report/ContextMenu/BaseReportActionContextMenu.tsx b/src/pages/home/report/ContextMenu/BaseReportActionContextMenu.tsx index bce959c9e774..8c4a029e9fad 100755 --- a/src/pages/home/report/ContextMenu/BaseReportActionContextMenu.tsx +++ b/src/pages/home/report/ContextMenu/BaseReportActionContextMenu.tsx @@ -162,7 +162,7 @@ function BaseReportActionContextMenu({ const [linkedTransactions] = useOnyx(ONYXKEYS.COLLECTION.TRANSACTION, { selector: (transactions) => { - return Object.values(transactions ?? {}).filter((t) => t?.reportID === reportAction?.childReportID); + return Object.values(transactions ?? {}).filter((t) => t?.reportID && t?.reportID === reportAction?.childReportID); }, canBeMissing: true, }); From 26d13cea97ff2e295b38ec92ce9b8c6195864890 Mon Sep 17 00:00:00 2001 From: DylanDylann Date: Thu, 26 Jun 2025 13:42:32 +0700 Subject: [PATCH 04/27] fix lint --- .../report/ContextMenu/BaseReportActionContextMenu.tsx | 2 +- .../home/report/ContextMenu/ContextMenuActions.tsx | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/pages/home/report/ContextMenu/BaseReportActionContextMenu.tsx b/src/pages/home/report/ContextMenu/BaseReportActionContextMenu.tsx index 8c4a029e9fad..4e7ea8e3c688 100755 --- a/src/pages/home/report/ContextMenu/BaseReportActionContextMenu.tsx +++ b/src/pages/home/report/ContextMenu/BaseReportActionContextMenu.tsx @@ -233,7 +233,7 @@ function BaseReportActionContextMenu({ moneyRequestAction, areHoldRequirementsMet, account, - transactions: linkedTransactions ?? [], + transactions: linkedTransactions?.filter((linkedTransaction): linkedTransaction is NonNullable => linkedTransaction !== undefined) ?? [], }), ); diff --git a/src/pages/home/report/ContextMenu/ContextMenuActions.tsx b/src/pages/home/report/ContextMenu/ContextMenuActions.tsx index 2e570236d08c..3805e6397193 100644 --- a/src/pages/home/report/ContextMenu/ContextMenuActions.tsx +++ b/src/pages/home/report/ContextMenu/ContextMenuActions.tsx @@ -1,5 +1,5 @@ import {Str} from 'expensify-common'; -import type {MutableRefObject} from 'react'; +import type {RefObject} from 'react'; import React from 'react'; // eslint-disable-next-line no-restricted-imports import type {GestureResponderEvent, Text, View} from 'react-native'; @@ -159,7 +159,7 @@ type ShouldShow = (args: { reportAction: OnyxEntry; isArchivedRoom: boolean; betas: OnyxEntry; - menuTarget: MutableRefObject | undefined; + menuTarget: RefObject | undefined; isChronosReport: boolean; reportID?: string; isPinnedChat: boolean; @@ -185,12 +185,12 @@ type ContextMenuActionPayload = { transitionActionSheetState: (params: {type: string; payload?: Record}) => void; openContextMenu: () => void; interceptAnonymousUser: (callback: () => void, isAnonymousAction?: boolean) => void; - anchor?: MutableRefObject; + anchor?: RefObject; checkIfContextMenuActive?: () => void; - openOverflowMenu: (event: GestureResponderEvent | MouseEvent, anchorRef: MutableRefObject) => void; + openOverflowMenu: (event: GestureResponderEvent | MouseEvent, anchorRef: RefObject) => void; event?: GestureResponderEvent | MouseEvent | KeyboardEvent; setIsEmojiPickerActive?: (state: boolean) => void; - anchorRef?: MutableRefObject; + anchorRef?: RefObject; moneyRequestAction: ReportAction | undefined; card?: Card; }; From 61fe4f8a8aba7b6d744ec57216926937baf624d5 Mon Sep 17 00:00:00 2001 From: DylanDylann Date: Thu, 26 Jun 2025 13:54:48 +0700 Subject: [PATCH 05/27] lint fix --- src/libs/DebugUtils.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libs/DebugUtils.ts b/src/libs/DebugUtils.ts index 138a6dce2d7f..50ecc33f97ac 100644 --- a/src/libs/DebugUtils.ts +++ b/src/libs/DebugUtils.ts @@ -1110,6 +1110,7 @@ function validateTransactionDraftProperty(key: keyof Transaction, value: string) splits: 'array', dismissedViolations: 'object', splitExpenses: 'array', + isDemoTransaction: 'boolean', }); case 'accountant': return validateObject>(value, { From 3b09e510c5d10ad7bd43aad02555319e73456104 Mon Sep 17 00:00:00 2001 From: DylanDylann Date: Thu, 26 Jun 2025 14:00:29 +0700 Subject: [PATCH 06/27] lint fix --- src/libs/DebugUtils.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libs/DebugUtils.ts b/src/libs/DebugUtils.ts index 50ecc33f97ac..ff55c5302fdf 100644 --- a/src/libs/DebugUtils.ts +++ b/src/libs/DebugUtils.ts @@ -1072,6 +1072,7 @@ function validateTransactionDraftProperty(key: keyof Transaction, value: string) inserted: CONST.RED_BRICK_ROAD_PENDING_ACTION, accountant: CONST.RED_BRICK_ROAD_PENDING_ACTION, splitExpenses: CONST.RED_BRICK_ROAD_PENDING_ACTION, + isDemoTransaction: CONST.RED_BRICK_ROAD_PENDING_ACTION, }, 'string', ); From f2e6363c07a8fd2a0e81a0a3dec46bc5a6ef212e Mon Sep 17 00:00:00 2001 From: DylanDylann Date: Mon, 30 Jun 2025 11:03:13 +0700 Subject: [PATCH 07/27] fix UTs --- src/pages/ReportDetailsPage.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/pages/ReportDetailsPage.tsx b/src/pages/ReportDetailsPage.tsx index 9f228daa3cb0..955d56e1fa70 100644 --- a/src/pages/ReportDetailsPage.tsx +++ b/src/pages/ReportDetailsPage.tsx @@ -118,6 +118,7 @@ import {isEmptyObject} from '@src/types/utils/EmptyObject'; import type IconAsset from '@src/types/utils/IconAsset'; import type {WithReportOrNotFoundProps} from './home/report/withReportOrNotFound'; import withReportOrNotFound from './home/report/withReportOrNotFound'; +import getNonEmptyStringOnyxID from '@libs/getNonEmptyStringOnyxID'; type ReportDetailsPageMenuItem = { key: DeepValueOf; @@ -278,7 +279,7 @@ function ReportDetailsPage({policy, report, route, reportMetadata}: ReportDetail const canDeleteRequest = isActionOwner && (canDeleteTransaction(moneyRequestReport, isMoneyRequestReportArchived) || isSelfDMTrackExpenseReport) && !isDeletedParentAction; const iouTransactionID = isMoneyRequestAction(requestParentReportAction) ? getOriginalMessage(requestParentReportAction)?.IOUTransactionID : ''; const isCardTransactionCanBeDeleted = canDeleteCardTransactionByLiabilityType(iouTransactionID); - const [transaction] = useOnyx(`${ONYXKEYS.COLLECTION.TRANSACTION}${iouTransactionID}`, {canBeMissing: true}); + const [transaction] = useOnyx(`${ONYXKEYS.COLLECTION.TRANSACTION}${getNonEmptyStringOnyxID(iouTransactionID)}`, {canBeMissing: true}); const shouldShowDeleteButton = shouldShowTaskDeleteButton || (canDeleteRequest && isCardTransactionCanBeDeleted) || isDemoTransaction(transaction); useEffect(() => { if (canDeleteRequest) { From a8bfe26356c6a86f66f049fbeea1c1facd278b40 Mon Sep 17 00:00:00 2001 From: DylanDylann Date: Mon, 30 Jun 2025 11:12:48 +0700 Subject: [PATCH 08/27] add UTs --- src/pages/ReportDetailsPage.tsx | 2 +- tests/unit/ReportSecondaryActionUtilsTest.ts | 26 ++++++++++++ tests/unit/ReportUtilsTest.ts | 44 ++++++++++++++++++++ 3 files changed, 71 insertions(+), 1 deletion(-) diff --git a/src/pages/ReportDetailsPage.tsx b/src/pages/ReportDetailsPage.tsx index 955d56e1fa70..b880bfc1d535 100644 --- a/src/pages/ReportDetailsPage.tsx +++ b/src/pages/ReportDetailsPage.tsx @@ -32,6 +32,7 @@ import usePermissions from '@hooks/usePermissions'; import useReportIsArchived from '@hooks/useReportIsArchived'; import useThemeStyles from '@hooks/useThemeStyles'; import getBase62ReportID from '@libs/getBase62ReportID'; +import getNonEmptyStringOnyxID from '@libs/getNonEmptyStringOnyxID'; import Navigation from '@libs/Navigation/Navigation'; import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types'; import type {ReportDetailsNavigatorParamList} from '@libs/Navigation/types'; @@ -118,7 +119,6 @@ import {isEmptyObject} from '@src/types/utils/EmptyObject'; import type IconAsset from '@src/types/utils/IconAsset'; import type {WithReportOrNotFoundProps} from './home/report/withReportOrNotFound'; import withReportOrNotFound from './home/report/withReportOrNotFound'; -import getNonEmptyStringOnyxID from '@libs/getNonEmptyStringOnyxID'; type ReportDetailsPageMenuItem = { key: DeepValueOf; diff --git a/tests/unit/ReportSecondaryActionUtilsTest.ts b/tests/unit/ReportSecondaryActionUtilsTest.ts index b72138dce75b..381b87037c20 100644 --- a/tests/unit/ReportSecondaryActionUtilsTest.ts +++ b/tests/unit/ReportSecondaryActionUtilsTest.ts @@ -780,6 +780,32 @@ describe('getSecondaryAction', () => { const result = getSecondaryReportActions({report, chatReport, reportTransactions: [transaction], violations: {}, policy}); expect(result.includes(CONST.REPORT.SECONDARY_ACTIONS.DELETE)).toBe(false); }); + + it('include DELETE option for demo transaction', async () => { + const report = { + reportID: REPORT_ID, + type: CONST.REPORT.TYPE.EXPENSE, + ownerAccountID: EMPLOYEE_ACCOUNT_ID, + statusNum: CONST.REPORT.STATUS_NUM.SUBMITTED, + stateNum: CONST.REPORT.STATE_NUM.SUBMITTED, + } as unknown as Report; + + const TRANSACTION_ID = 'TRANSACTION_ID'; + + const transaction = { + transactionID: TRANSACTION_ID, + reportID: REPORT_ID, + comment: { + isDemoTransaction: true, + }, + } as unknown as Transaction; + + const policy = {} as unknown as Policy; + await Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT}${REPORT_ID}`, report); + + const result = getSecondaryReportActions({report, chatReport, reportTransactions: [transaction], violations: {}, policy}); + expect(result.includes(CONST.REPORT.SECONDARY_ACTIONS.DELETE)).toBe(true); + }); }); describe('getSecondaryExportReportActions', () => { diff --git a/tests/unit/ReportUtilsTest.ts b/tests/unit/ReportUtilsTest.ts index bd9940a82f88..c7de6f0f39af 100644 --- a/tests/unit/ReportUtilsTest.ts +++ b/tests/unit/ReportUtilsTest.ts @@ -2638,6 +2638,50 @@ describe('ReportUtils', () => { expect(canDeleteReportAction(moneyRequestAction, currentReportId)).toBe(false); }); }); + + it('should return true for demo transaction', () => { + const transaction = { + ...createRandomTransaction(1), + comment: { + isDemoTransaction: true, + }, + }; + + const report = LHNTestUtils.getFakeReport(); + const parentReportAction: ReportAction = { + ...LHNTestUtils.getFakeReportAction(), + message: [ + { + type: 'COMMENT', + html: 'hey', + text: 'hey', + isEdited: false, + whisperedTo: [], + isDeletedParentAction: false, + moderationDecision: { + decision: CONST.MODERATION.MODERATOR_DECISION_PENDING_REMOVE, + }, + }, + ], + childReportID: report.reportID, + }; + const moneyRequestAction = { + ...parentReportAction, + actorAccountID: currentUserAccountID, + actionName: CONST.REPORT.ACTIONS.TYPE.IOU, + originalMessage: { + IOUReportID: '1', + IOUTransactionID: '1', + amount: 100, + participantAccountID: 1, + currency: CONST.CURRENCY.USD, + type: CONST.IOU.REPORT_ACTION_TYPE.PAY, + paymentType: CONST.IOU.PAYMENT_TYPE.EXPENSIFY, + }, + }; + + expect(canDeleteReportAction(moneyRequestAction, '1', [transaction])).toBe(true); + }); }); describe('getPolicyExpenseChat', () => { From 4f08b0e885a19dce7d656b87134c288843c51a5a Mon Sep 17 00:00:00 2001 From: DylanDylann Date: Thu, 3 Jul 2025 18:16:31 +0700 Subject: [PATCH 09/27] add optimistic data --- src/libs/TransactionUtils/index.ts | 7 ++++++- src/libs/actions/IOU.ts | 1 + 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/libs/TransactionUtils/index.ts b/src/libs/TransactionUtils/index.ts index 51e0d11a8d5f..c4321d272d7e 100644 --- a/src/libs/TransactionUtils/index.ts +++ b/src/libs/TransactionUtils/index.ts @@ -82,6 +82,7 @@ type BuildOptimisticTransactionParams = { existingTransaction?: OnyxEntry; policy?: OnyxEntry; transactionParams: TransactionParams; + isDemoTransaction?: boolean; }; let allTransactions: OnyxCollection = {}; @@ -234,7 +235,7 @@ function isPendingCardOrScanningTransaction(transaction: OnyxEntry) * it's transactionID match what was already generated. */ function buildOptimisticTransaction(params: BuildOptimisticTransactionParams): Transaction { - const {originalTransactionID = '', existingTransactionID, existingTransaction, policy, transactionParams} = params; + const {originalTransactionID = '', existingTransactionID, existingTransaction, policy, transactionParams, isDemoTransaction} = params; const { amount, currency, @@ -261,7 +262,11 @@ function buildOptimisticTransaction(params: BuildOptimisticTransactionParams): T // Because JS can only handle 53-bit numbers, transactionIDs are strings in the front-end (just like reportActionID) const transactionID = existingTransactionID ?? rand64(); + const commentJSON: Comment = {comment, attendees}; + if (isDemoTransaction) { + commentJSON.isDemoTransaction = true; + } if (source) { commentJSON.source = source; } diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 1842a2755c1e..c84064f9b30a 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -3367,6 +3367,7 @@ function getMoneyRequestInformation(moneyRequestInformation: MoneyRequestInforma billable, pendingFields: isDistanceRequest ? {waypoints: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD} : undefined, }, + isDemoTransaction: isSelectedManagerMcTest(participant.login) || transactionParams.receipt?.isTestDriveReceipt, }); const optimisticPolicyRecentlyUsedCategories = buildOptimisticPolicyRecentlyUsedCategories(iouReport.policyID, category); From eef1756e14337a60d68ab676a38f76132023c5b1 Mon Sep 17 00:00:00 2001 From: DylanDylann Date: Thu, 3 Jul 2025 18:16:40 +0700 Subject: [PATCH 10/27] add optimistic data --- src/libs/TransactionUtils/index.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libs/TransactionUtils/index.ts b/src/libs/TransactionUtils/index.ts index c4321d272d7e..7d04305d8fce 100644 --- a/src/libs/TransactionUtils/index.ts +++ b/src/libs/TransactionUtils/index.ts @@ -262,7 +262,6 @@ function buildOptimisticTransaction(params: BuildOptimisticTransactionParams): T // Because JS can only handle 53-bit numbers, transactionIDs are strings in the front-end (just like reportActionID) const transactionID = existingTransactionID ?? rand64(); - const commentJSON: Comment = {comment, attendees}; if (isDemoTransaction) { commentJSON.isDemoTransaction = true; From 47fdae76b7bf49670e0cc814909356e268d5b0e6 Mon Sep 17 00:00:00 2001 From: DylanDylann Date: Thu, 3 Jul 2025 19:25:06 +0700 Subject: [PATCH 11/27] merge main --- Mobile-Expensify | 2 +- src/libs/ReportUtils.ts | 4 ++-- src/pages/ReportDetailsPage.tsx | 4 +--- .../report/ContextMenu/BaseReportActionContextMenu.tsx | 8 -------- src/pages/home/report/ContextMenu/ContextMenuActions.tsx | 4 +--- tests/unit/ReportUtilsTest.ts | 2 +- 6 files changed, 6 insertions(+), 18 deletions(-) diff --git a/Mobile-Expensify b/Mobile-Expensify index 6ec14b1852c8..57d9657d93bd 160000 --- a/Mobile-Expensify +++ b/Mobile-Expensify @@ -1 +1 @@ -Subproject commit 6ec14b1852c835d8826459d4724a9f982837bdcd +Subproject commit 57d9657d93bd5e104d5c6215bab163fd4340b8ad diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index e2e12b1a6828..17e83d4f2406 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -2495,12 +2495,12 @@ function canDeleteCardTransactionByLiabilityType(transaction: OnyxEntry, reportID: string | undefined, transactions?: Transaction[], iouTransaction?: OnyxEntry): boolean { +function canDeleteReportAction(reportAction: OnyxInputOrEntry, reportID: string | undefined, iouTransaction?: OnyxEntry): boolean { const report = getReportOrDraftReport(reportID); const isActionOwner = reportAction?.actorAccountID === currentUserAccountID; const policy = allPolicies?.[`${ONYXKEYS.COLLECTION.POLICY}${report?.policyID}`] ?? null; - if (transactions?.every((t) => isDemoTransaction(t))) { + if (isDemoTransaction(iouTransaction)) { return true; } diff --git a/src/pages/ReportDetailsPage.tsx b/src/pages/ReportDetailsPage.tsx index 3cdf31fcccc4..4b25b393baf4 100644 --- a/src/pages/ReportDetailsPage.tsx +++ b/src/pages/ReportDetailsPage.tsx @@ -276,12 +276,10 @@ function ReportDetailsPage({policy, report, route, reportMetadata}: ReportDetail !isClosedReport(report) && isTaskModifiable && isTaskActionable; - const canDeleteRequest = isActionOwner && (canDeleteTransaction(moneyRequestReport, isMoneyRequestReportArchived) || isSelfDMTrackExpenseReport) && !isDeletedParentAction; - const iouTransactionID = isMoneyRequestAction(requestParentReportAction) ? getOriginalMessage(requestParentReportAction)?.IOUTransactionID : undefined; const [iouTransaction] = useOnyx(`${ONYXKEYS.COLLECTION.TRANSACTION}${iouTransactionID}`, {canBeMissing: true}); - const isCardTransactionCanBeDeleted = canDeleteCardTransactionByLiabilityType(iouTransactionID); + const isCardTransactionCanBeDeleted = canDeleteCardTransactionByLiabilityType(iouTransaction); const shouldShowDeleteButton = shouldShowTaskDeleteButton || (canDeleteRequest && isCardTransactionCanBeDeleted) || isDemoTransaction(iouTransaction); useEffect(() => { diff --git a/src/pages/home/report/ContextMenu/BaseReportActionContextMenu.tsx b/src/pages/home/report/ContextMenu/BaseReportActionContextMenu.tsx index b1421bf4b2fd..84c4dadd272f 100755 --- a/src/pages/home/report/ContextMenu/BaseReportActionContextMenu.tsx +++ b/src/pages/home/report/ContextMenu/BaseReportActionContextMenu.tsx @@ -159,13 +159,6 @@ function BaseReportActionContextMenu({ return reportActions[reportActionID]; }, [reportActions, reportActionID]); - const [linkedTransactions] = useOnyx(ONYXKEYS.COLLECTION.TRANSACTION, { - selector: (transactions) => { - return Object.values(transactions ?? {}).filter((t) => t?.reportID && t?.reportID === reportAction?.childReportID); - }, - canBeMissing: true, - }); - const sourceID = getSourceIDFromReportAction(reportAction); const [download] = useOnyx(`${ONYXKEYS.COLLECTION.DOWNLOAD}${sourceID}`, {canBeMissing: true}); @@ -233,7 +226,6 @@ function BaseReportActionContextMenu({ moneyRequestAction, areHoldRequirementsMet, account, - transactions: linkedTransactions?.filter((linkedTransaction): linkedTransaction is NonNullable => linkedTransaction !== undefined) ?? [], iouTransaction, }), ); diff --git a/src/pages/home/report/ContextMenu/ContextMenuActions.tsx b/src/pages/home/report/ContextMenu/ContextMenuActions.tsx index 48902754612b..f155d81497df 100644 --- a/src/pages/home/report/ContextMenu/ContextMenuActions.tsx +++ b/src/pages/home/report/ContextMenu/ContextMenuActions.tsx @@ -171,7 +171,6 @@ type ShouldShow = (args: { moneyRequestAction: ReportAction | undefined; areHoldRequirementsMet: boolean; account: OnyxEntry; - transactions: Transaction[]; iouTransaction: OnyxEntry; }) => boolean; @@ -821,14 +820,13 @@ const ContextMenuActions: ContextMenuAction[] = [ isAnonymousAction: false, textTranslateKey: 'reportActionContextMenu.deleteAction', icon: Expensicons.Trashcan, - shouldShow: ({type, reportAction, isArchivedRoom, isChronosReport, reportID, moneyRequestAction, transactions, iouTransaction}) => + shouldShow: ({type, reportAction, isArchivedRoom, isChronosReport, reportID, moneyRequestAction, iouTransaction}) => // Until deleting parent threads is supported in FE, we will prevent the user from deleting a thread parent !!reportID && type === CONST.CONTEXT_MENU_TYPES.REPORT_ACTION && canDeleteReportAction( moneyRequestAction ?? reportAction, isMoneyRequestAction(moneyRequestAction) ? getOriginalMessage(moneyRequestAction)?.IOUReportID : reportID, - transactions, iouTransaction, ) && !isArchivedRoom && diff --git a/tests/unit/ReportUtilsTest.ts b/tests/unit/ReportUtilsTest.ts index 4dd754c6e6d6..a90cf75ff6f9 100644 --- a/tests/unit/ReportUtilsTest.ts +++ b/tests/unit/ReportUtilsTest.ts @@ -2695,7 +2695,7 @@ describe('ReportUtils', () => { }, }; - expect(canDeleteReportAction(moneyRequestAction, '1', [transaction])).toBe(true); + expect(canDeleteReportAction(moneyRequestAction, '1', transaction)).toBe(true); }); }); From c8cbac005cd1f6995a37e919874c57ae3d64b839 Mon Sep 17 00:00:00 2001 From: DylanDylann Date: Thu, 3 Jul 2025 19:32:29 +0700 Subject: [PATCH 12/27] lint fix --- src/libs/ReportSecondaryActionUtils.ts | 4 ++-- src/libs/TransactionUtils/index.ts | 4 ++-- src/pages/ReportDetailsPage.tsx | 5 ++--- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/libs/ReportSecondaryActionUtils.ts b/src/libs/ReportSecondaryActionUtils.ts index 03c54a85689f..d675e82c2c97 100644 --- a/src/libs/ReportSecondaryActionUtils.ts +++ b/src/libs/ReportSecondaryActionUtils.ts @@ -47,7 +47,7 @@ import { getOriginalTransactionWithSplitInfo, hasReceipt as hasReceiptTransactionUtils, isCardTransaction as isCardTransactionUtils, - isDemoTransaction, + isDemoTransactionFunc, isDuplicate, isOnHold as isOnHoldTransactionUtils, isPending, @@ -419,7 +419,7 @@ function isDeleteAction(report: Report, reportTransactions: Transaction[], repor const isReportOpenOrProcessing = isOpenReportUtils(report) || isProcessingReportUtils(report); const isSingleTransaction = reportTransactions.length === 1; - if (reportTransactions.length > 0 && reportTransactions.every((t) => isDemoTransaction(t))) { + if (reportTransactions.length > 0 && reportTransactions.every((t) => isDemoTransactionFunc(t))) { return true; } diff --git a/src/libs/TransactionUtils/index.ts b/src/libs/TransactionUtils/index.ts index 1da12e1f5c07..b9d15edf7c27 100644 --- a/src/libs/TransactionUtils/index.ts +++ b/src/libs/TransactionUtils/index.ts @@ -328,7 +328,7 @@ function hasReceiptSource(transaction: OnyxInputOrEntry): boolean { return !!transaction?.receipt?.source; } -function isDemoTransaction(transaction: OnyxInputOrEntry): boolean { +function isDemoTransactionFunc(transaction: OnyxInputOrEntry): boolean { return transaction?.comment?.isDemoTransaction ?? false; } @@ -1748,7 +1748,7 @@ export { getTransactionPendingAction, isTransactionPendingDelete, createUnreportedExpenseSections, - isDemoTransaction, + isDemoTransactionFunc, }; export type {TransactionChanges}; diff --git a/src/pages/ReportDetailsPage.tsx b/src/pages/ReportDetailsPage.tsx index 4b25b393baf4..03be8e0e1629 100644 --- a/src/pages/ReportDetailsPage.tsx +++ b/src/pages/ReportDetailsPage.tsx @@ -32,7 +32,6 @@ import usePermissions from '@hooks/usePermissions'; import useReportIsArchived from '@hooks/useReportIsArchived'; import useThemeStyles from '@hooks/useThemeStyles'; import getBase62ReportID from '@libs/getBase62ReportID'; -import getNonEmptyStringOnyxID from '@libs/getNonEmptyStringOnyxID'; import Navigation from '@libs/Navigation/Navigation'; import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types'; import type {ReportDetailsNavigatorParamList} from '@libs/Navigation/types'; @@ -93,7 +92,7 @@ import { shouldUseFullTitleToDisplay, } from '@libs/ReportUtils'; import StringUtils from '@libs/StringUtils'; -import {isDemoTransaction} from '@libs/TransactionUtils'; +import {isDemoTransactionFunc} from '@libs/TransactionUtils'; import {deleteMoneyRequest, deleteTrackExpense, getNavigationUrlAfterTrackExpenseDelete, getNavigationUrlOnMoneyRequestDelete} from '@userActions/IOU'; import { clearAvatarErrors, @@ -280,7 +279,7 @@ function ReportDetailsPage({policy, report, route, reportMetadata}: ReportDetail const iouTransactionID = isMoneyRequestAction(requestParentReportAction) ? getOriginalMessage(requestParentReportAction)?.IOUTransactionID : undefined; const [iouTransaction] = useOnyx(`${ONYXKEYS.COLLECTION.TRANSACTION}${iouTransactionID}`, {canBeMissing: true}); const isCardTransactionCanBeDeleted = canDeleteCardTransactionByLiabilityType(iouTransaction); - const shouldShowDeleteButton = shouldShowTaskDeleteButton || (canDeleteRequest && isCardTransactionCanBeDeleted) || isDemoTransaction(iouTransaction); + const shouldShowDeleteButton = shouldShowTaskDeleteButton || (canDeleteRequest && isCardTransactionCanBeDeleted) || isDemoTransactionFunc(iouTransaction); useEffect(() => { if (canDeleteRequest) { From 3650fb2f588ebd4d5518a5395c0f6ab4278fd42d Mon Sep 17 00:00:00 2001 From: DylanDylann Date: Thu, 3 Jul 2025 19:33:28 +0700 Subject: [PATCH 13/27] lint fix --- src/libs/ReportUtils.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 17e83d4f2406..b7dcdf402819 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -241,7 +241,7 @@ import { hasViolation, hasWarningTypeViolation, isCardTransaction as isCardTransactionTransactionUtils, - isDemoTransaction, + isDemoTransactionFunc, isDistanceRequest, isExpensifyCardTransaction, isFetchingWaypointsFromServer, @@ -2500,7 +2500,7 @@ function canDeleteReportAction(reportAction: OnyxInputOrEntry, rep const isActionOwner = reportAction?.actorAccountID === currentUserAccountID; const policy = allPolicies?.[`${ONYXKEYS.COLLECTION.POLICY}${report?.policyID}`] ?? null; - if (isDemoTransaction(iouTransaction)) { + if (isDemoTransactionFunc(iouTransaction)) { return true; } From 8a1ec58acf601e5534af4e5069b60bc71f9285cb Mon Sep 17 00:00:00 2001 From: DylanDylann Date: Fri, 4 Jul 2025 10:46:50 +0700 Subject: [PATCH 14/27] update comment --- src/libs/ReportSecondaryActionUtils.ts | 4 ++-- src/libs/ReportUtils.ts | 8 ++++---- src/libs/TransactionUtils/index.ts | 10 +++++----- src/pages/ReportDetailsPage.tsx | 4 ++-- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/libs/ReportSecondaryActionUtils.ts b/src/libs/ReportSecondaryActionUtils.ts index d675e82c2c97..03c54a85689f 100644 --- a/src/libs/ReportSecondaryActionUtils.ts +++ b/src/libs/ReportSecondaryActionUtils.ts @@ -47,7 +47,7 @@ import { getOriginalTransactionWithSplitInfo, hasReceipt as hasReceiptTransactionUtils, isCardTransaction as isCardTransactionUtils, - isDemoTransactionFunc, + isDemoTransaction, isDuplicate, isOnHold as isOnHoldTransactionUtils, isPending, @@ -419,7 +419,7 @@ function isDeleteAction(report: Report, reportTransactions: Transaction[], repor const isReportOpenOrProcessing = isOpenReportUtils(report) || isProcessingReportUtils(report); const isSingleTransaction = reportTransactions.length === 1; - if (reportTransactions.length > 0 && reportTransactions.every((t) => isDemoTransactionFunc(t))) { + if (reportTransactions.length > 0 && reportTransactions.every((t) => isDemoTransaction(t))) { return true; } diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index b7dcdf402819..fb315d08f58f 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -241,7 +241,7 @@ import { hasViolation, hasWarningTypeViolation, isCardTransaction as isCardTransactionTransactionUtils, - isDemoTransactionFunc, + isDemoTransaction, isDistanceRequest, isExpensifyCardTransaction, isFetchingWaypointsFromServer, @@ -2495,17 +2495,17 @@ function canDeleteCardTransactionByLiabilityType(transaction: OnyxEntry, reportID: string | undefined, iouTransaction?: OnyxEntry): boolean { +function canDeleteReportAction(reportAction: OnyxInputOrEntry, reportID: string | undefined, transaction: OnyxEntry | undefined): boolean { const report = getReportOrDraftReport(reportID); const isActionOwner = reportAction?.actorAccountID === currentUserAccountID; const policy = allPolicies?.[`${ONYXKEYS.COLLECTION.POLICY}${report?.policyID}`] ?? null; - if (isDemoTransactionFunc(iouTransaction)) { + if (isDemoTransaction(transaction)) { return true; } if (isMoneyRequestAction(reportAction)) { - const isCardTransactionCanBeDeleted = canDeleteCardTransactionByLiabilityType(iouTransaction); + const isCardTransactionCanBeDeleted = canDeleteCardTransactionByLiabilityType(transaction); // For now, users cannot delete split actions const isSplitAction = getOriginalMessage(reportAction)?.type === CONST.IOU.REPORT_ACTION_TYPE.SPLIT; diff --git a/src/libs/TransactionUtils/index.ts b/src/libs/TransactionUtils/index.ts index b9d15edf7c27..054220778846 100644 --- a/src/libs/TransactionUtils/index.ts +++ b/src/libs/TransactionUtils/index.ts @@ -82,7 +82,7 @@ type BuildOptimisticTransactionParams = { existingTransaction?: OnyxEntry; policy?: OnyxEntry; transactionParams: TransactionParams; - isDemoTransaction?: boolean; + isDemoTransactionParam?: boolean; }; let allTransactions: OnyxCollection = {}; @@ -235,7 +235,7 @@ function isPendingCardOrScanningTransaction(transaction: OnyxEntry) * it's transactionID match what was already generated. */ function buildOptimisticTransaction(params: BuildOptimisticTransactionParams): Transaction { - const {originalTransactionID = '', existingTransactionID, existingTransaction, policy, transactionParams, isDemoTransaction} = params; + const {originalTransactionID = '', existingTransactionID, existingTransaction, policy, transactionParams, isDemoTransactionParam} = params; const { amount, currency, @@ -263,7 +263,7 @@ function buildOptimisticTransaction(params: BuildOptimisticTransactionParams): T const transactionID = existingTransactionID ?? rand64(); const commentJSON: Comment = {comment, attendees}; - if (isDemoTransaction) { + if (isDemoTransactionParam) { commentJSON.isDemoTransaction = true; } if (source) { @@ -328,7 +328,7 @@ function hasReceiptSource(transaction: OnyxInputOrEntry): boolean { return !!transaction?.receipt?.source; } -function isDemoTransactionFunc(transaction: OnyxInputOrEntry): boolean { +function isDemoTransaction(transaction: OnyxInputOrEntry): boolean { return transaction?.comment?.isDemoTransaction ?? false; } @@ -1748,7 +1748,7 @@ export { getTransactionPendingAction, isTransactionPendingDelete, createUnreportedExpenseSections, - isDemoTransactionFunc, + isDemoTransaction, }; export type {TransactionChanges}; diff --git a/src/pages/ReportDetailsPage.tsx b/src/pages/ReportDetailsPage.tsx index 03be8e0e1629..e67fee46438c 100644 --- a/src/pages/ReportDetailsPage.tsx +++ b/src/pages/ReportDetailsPage.tsx @@ -92,7 +92,7 @@ import { shouldUseFullTitleToDisplay, } from '@libs/ReportUtils'; import StringUtils from '@libs/StringUtils'; -import {isDemoTransactionFunc} from '@libs/TransactionUtils'; +import {isDemoTransaction} from '@libs/TransactionUtils'; import {deleteMoneyRequest, deleteTrackExpense, getNavigationUrlAfterTrackExpenseDelete, getNavigationUrlOnMoneyRequestDelete} from '@userActions/IOU'; import { clearAvatarErrors, @@ -279,7 +279,7 @@ function ReportDetailsPage({policy, report, route, reportMetadata}: ReportDetail const iouTransactionID = isMoneyRequestAction(requestParentReportAction) ? getOriginalMessage(requestParentReportAction)?.IOUTransactionID : undefined; const [iouTransaction] = useOnyx(`${ONYXKEYS.COLLECTION.TRANSACTION}${iouTransactionID}`, {canBeMissing: true}); const isCardTransactionCanBeDeleted = canDeleteCardTransactionByLiabilityType(iouTransaction); - const shouldShowDeleteButton = shouldShowTaskDeleteButton || (canDeleteRequest && isCardTransactionCanBeDeleted) || isDemoTransactionFunc(iouTransaction); + const shouldShowDeleteButton = shouldShowTaskDeleteButton || (canDeleteRequest && isCardTransactionCanBeDeleted) || isDemoTransaction(iouTransaction); useEffect(() => { if (canDeleteRequest) { From d75b2130a6d54ecc089aee4b08980c06a9b2e660 Mon Sep 17 00:00:00 2001 From: DylanDylann Date: Fri, 4 Jul 2025 11:09:47 +0700 Subject: [PATCH 15/27] type fix --- 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 a3f08cef0d78..aee5471b54b9 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -3379,7 +3379,7 @@ function getMoneyRequestInformation(moneyRequestInformation: MoneyRequestInforma billable, pendingFields: isDistanceRequest ? {waypoints: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD} : undefined, }, - isDemoTransaction: isSelectedManagerMcTest(participant.login) || transactionParams.receipt?.isTestDriveReceipt, + isDemoTransactionParam: isSelectedManagerMcTest(participant.login) || transactionParams.receipt?.isTestDriveReceipt, }); const optimisticPolicyRecentlyUsedCategories = buildOptimisticPolicyRecentlyUsedCategories(iouReport.policyID, category); From 0bc1904513bc1a143c307616f8c5b1face8522b6 Mon Sep 17 00:00:00 2001 From: DylanDylann Date: Fri, 4 Jul 2025 12:30:01 +0700 Subject: [PATCH 16/27] update test --- tests/perf-test/ReportUtils.perf-test.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/perf-test/ReportUtils.perf-test.ts b/tests/perf-test/ReportUtils.perf-test.ts index 06a020678faf..f5b7a9b2e344 100644 --- a/tests/perf-test/ReportUtils.perf-test.ts +++ b/tests/perf-test/ReportUtils.perf-test.ts @@ -89,10 +89,11 @@ describe('ReportUtils', () => { test('[ReportUtils] canDeleteReportAction on 1k reports and policies', async () => { const reportID = '1'; + const transaction = createRandomTransaction(1); const reportAction = {...createRandomReportAction(1), actionName: CONST.REPORT.ACTIONS.TYPE.ADD_COMMENT} as unknown as ReportAction; await waitForBatchedUpdates(); - await measureFunction(() => canDeleteReportAction(reportAction, reportID)); + await measureFunction(() => canDeleteReportAction(reportAction, reportID, transaction)); }); test('[ReportUtils] getReportRecipientAccountID on 1k participants', async () => { From 161e7c866275eca031a62e2b738af7c367be7735 Mon Sep 17 00:00:00 2001 From: DylanDylann Date: Sat, 5 Jul 2025 00:37:28 +0700 Subject: [PATCH 17/27] chore: update comment --- src/pages/ReportDetailsPage.tsx | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/pages/ReportDetailsPage.tsx b/src/pages/ReportDetailsPage.tsx index e67fee46438c..77b5f5eb1ccf 100644 --- a/src/pages/ReportDetailsPage.tsx +++ b/src/pages/ReportDetailsPage.tsx @@ -243,17 +243,21 @@ function ReportDetailsPage({policy, report, route, reportMetadata}: ReportDetail }); const isPrivateNotesFetchTriggered = reportMetadata?.isLoadingPrivateNotes !== undefined; - + const iouAction = reportActions.find((action) => action.actionName === CONST.REPORT.ACTIONS.TYPE.IOU && !!getOriginalMessage(action)?.IOUTransactionID); + const [childTransaction] = useOnyx(`${ONYXKEYS.COLLECTION.TRANSACTION}${getOriginalMessage(iouAction)?.IOUTransactionID}`, {canBeMissing: true}); const requestParentReportAction = useMemo(() => { // 2. MoneyReport case if (caseID === CASES.MONEY_REPORT) { + if (isDemoTransaction(childTransaction)) { + return iouAction; + } if (!reportActions || !transactionThreadReport?.parentReportActionID) { return undefined; } return reportActions.find((action) => action.reportActionID === transactionThreadReport.parentReportActionID); } return parentReportAction; - }, [caseID, parentReportAction, reportActions, transactionThreadReport?.parentReportActionID]); + }, [caseID, childTransaction, iouAction, parentReportAction, reportActions, transactionThreadReport?.parentReportActionID]); const isActionOwner = typeof requestParentReportAction?.actorAccountID === 'number' && typeof session?.accountID === 'number' && requestParentReportAction.actorAccountID === session?.accountID; From e66b241ad1a5099e3f21ba91bb43f2d17937b15a Mon Sep 17 00:00:00 2001 From: DylanDylann Date: Sat, 5 Jul 2025 14:15:06 +0700 Subject: [PATCH 18/27] remove redundant --- src/pages/ReportDetailsPage.tsx | 5 +++-- .../ContextMenu/BaseReportActionContextMenu.tsx | 11 +++++++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/pages/ReportDetailsPage.tsx b/src/pages/ReportDetailsPage.tsx index 77b5f5eb1ccf..f22ff230c152 100644 --- a/src/pages/ReportDetailsPage.tsx +++ b/src/pages/ReportDetailsPage.tsx @@ -242,9 +242,10 @@ function ReportDetailsPage({policy, report, route, reportMetadata}: ReportDetail return !pendingMember || pendingMember.pendingAction !== CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE ? accountID : []; }); + const iouAction = reportActions.find((action) => isMoneyRequestAction(action) && !!getOriginalMessage(action)?.IOUTransactionID); + const requestIOUTransactionID = isMoneyRequestAction(iouAction) ? getOriginalMessage(iouAction)?.IOUTransactionID : undefined; + const [childTransaction] = useOnyx(`${ONYXKEYS.COLLECTION.TRANSACTION}${requestIOUTransactionID}`, {canBeMissing: true}); const isPrivateNotesFetchTriggered = reportMetadata?.isLoadingPrivateNotes !== undefined; - const iouAction = reportActions.find((action) => action.actionName === CONST.REPORT.ACTIONS.TYPE.IOU && !!getOriginalMessage(action)?.IOUTransactionID); - const [childTransaction] = useOnyx(`${ONYXKEYS.COLLECTION.TRANSACTION}${getOriginalMessage(iouAction)?.IOUTransactionID}`, {canBeMissing: true}); const requestParentReportAction = useMemo(() => { // 2. MoneyReport case if (caseID === CASES.MONEY_REPORT) { diff --git a/src/pages/home/report/ContextMenu/BaseReportActionContextMenu.tsx b/src/pages/home/report/ContextMenu/BaseReportActionContextMenu.tsx index 84c4dadd272f..f7db749753c7 100755 --- a/src/pages/home/report/ContextMenu/BaseReportActionContextMenu.tsx +++ b/src/pages/home/report/ContextMenu/BaseReportActionContextMenu.tsx @@ -21,7 +21,7 @@ import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useRestoreInputFocus from '@hooks/useRestoreInputFocus'; import useStyleUtils from '@hooks/useStyleUtils'; import {getExpensifyCardFromReportAction} from '@libs/CardMessageUtils'; -import {getLinkedTransactionID, getOneTransactionThreadReportID, getOriginalMessage, getReportAction} from '@libs/ReportActionsUtils'; +import {getLinkedTransactionID, getOneTransactionThreadReportID, getOriginalMessage, getReportAction, isMoneyRequestAction} from '@libs/ReportActionsUtils'; import { chatIncludesChronosWithID, getSourceIDFromReportAction, @@ -32,6 +32,7 @@ import { isTrackExpenseReport as ReportUtilsIsTrackExpenseReport, } from '@libs/ReportUtils'; import shouldEnableContextMenuEnterShortcut from '@libs/shouldEnableContextMenuEnterShortcut'; +import {isDemoTransaction} from '@libs/TransactionUtils'; import {isAnonymousUser, signOutAndRedirectToSignIn} from '@userActions/Session'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; @@ -178,7 +179,13 @@ function BaseReportActionContextMenu({ const isMoneyRequestReport = useMemo(() => ReportUtilsIsMoneyRequestReport(childReport), [childReport]); const isInvoiceReport = useMemo(() => ReportUtilsIsInvoiceReport(childReport), [childReport]); + const iouAction = paginatedReportActions.find((action) => isMoneyRequestAction(action) && !!getOriginalMessage(action)?.IOUTransactionID); + const requestIOUTransactionID = isMoneyRequestAction(iouAction) ? getOriginalMessage(iouAction)?.IOUTransactionID : undefined; + const [childTransaction] = useOnyx(`${ONYXKEYS.COLLECTION.TRANSACTION}${requestIOUTransactionID}`, {canBeMissing: true}); const requestParentReportAction = useMemo(() => { + if (isDemoTransaction(childTransaction)) { + return iouAction; + } if (isMoneyRequestReport || isInvoiceReport) { if (!paginatedReportActions || !transactionThreadReport?.parentReportActionID) { return undefined; @@ -186,7 +193,7 @@ function BaseReportActionContextMenu({ return paginatedReportActions.find((action) => action.reportActionID === transactionThreadReport.parentReportActionID); } return parentReportAction; - }, [parentReportAction, isMoneyRequestReport, isInvoiceReport, paginatedReportActions, transactionThreadReport?.parentReportActionID]); + }, [parentReportAction, isMoneyRequestReport, isInvoiceReport, paginatedReportActions, transactionThreadReport?.parentReportActionID, childTransaction, iouAction]); const moneyRequestAction = transactionThreadReportID ? requestParentReportAction : parentReportAction; const isChildReportArchived = useReportIsArchived(childReport?.reportID); From a7d0c4706e9a8080b37d9a8804e6047c319301c1 Mon Sep 17 00:00:00 2001 From: DylanDylann Date: Mon, 7 Jul 2025 14:35:00 +0700 Subject: [PATCH 19/27] don't strike out the svg component --- src/components/OfflineWithFeedback.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/OfflineWithFeedback.tsx b/src/components/OfflineWithFeedback.tsx index 04a0c12cd9c1..6a433a52dbcd 100644 --- a/src/components/OfflineWithFeedback.tsx +++ b/src/components/OfflineWithFeedback.tsx @@ -14,6 +14,7 @@ import type ChildrenProps from '@src/types/utils/ChildrenProps'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; import CustomStylesForChildrenProvider from './CustomStylesForChildrenProvider'; import ErrorMessageRow from './ErrorMessageRow'; +import ImageSVG from './ImageSVG'; /** * This component should be used when we are using the offline pattern B (offline with feedback). @@ -108,7 +109,7 @@ function OfflineWithFeedback({ const applyStrikeThrough = useCallback( (childrenProp: React.ReactNode): React.ReactNode => { const strikeThroughChildren = mapChildrenFlat(childrenProp, (child) => { - if (!React.isValidElement(child)) { + if (!React.isValidElement(child) || child.type === ImageSVG) { return child; } From 5ce602658d45eb154e24d54ec15410ce66ae5918 Mon Sep 17 00:00:00 2001 From: DylanDylann Date: Mon, 7 Jul 2025 15:07:31 +0700 Subject: [PATCH 20/27] update optimistic data --- src/libs/actions/IOU.ts | 1 + src/pages/ReportDetailsPage.tsx | 8 +------- .../report/ContextMenu/BaseReportActionContextMenu.tsx | 8 +------- 3 files changed, 3 insertions(+), 14 deletions(-) diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index aee5471b54b9..3dbcbd64ed73 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -1598,6 +1598,7 @@ function buildOnyxDataForMoneyRequest(moneyRequestParams: BuildOnyxDataForMoneyR iouReportID: iou.report.reportID, transactionID: transaction.transactionID, }); + optimisticIOUReportAction.reportActionID = iou.action.reportActionID; optimisticData.push( { diff --git a/src/pages/ReportDetailsPage.tsx b/src/pages/ReportDetailsPage.tsx index f22ff230c152..1c8b87564261 100644 --- a/src/pages/ReportDetailsPage.tsx +++ b/src/pages/ReportDetailsPage.tsx @@ -242,23 +242,17 @@ function ReportDetailsPage({policy, report, route, reportMetadata}: ReportDetail return !pendingMember || pendingMember.pendingAction !== CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE ? accountID : []; }); - const iouAction = reportActions.find((action) => isMoneyRequestAction(action) && !!getOriginalMessage(action)?.IOUTransactionID); - const requestIOUTransactionID = isMoneyRequestAction(iouAction) ? getOriginalMessage(iouAction)?.IOUTransactionID : undefined; - const [childTransaction] = useOnyx(`${ONYXKEYS.COLLECTION.TRANSACTION}${requestIOUTransactionID}`, {canBeMissing: true}); const isPrivateNotesFetchTriggered = reportMetadata?.isLoadingPrivateNotes !== undefined; const requestParentReportAction = useMemo(() => { // 2. MoneyReport case if (caseID === CASES.MONEY_REPORT) { - if (isDemoTransaction(childTransaction)) { - return iouAction; - } if (!reportActions || !transactionThreadReport?.parentReportActionID) { return undefined; } return reportActions.find((action) => action.reportActionID === transactionThreadReport.parentReportActionID); } return parentReportAction; - }, [caseID, childTransaction, iouAction, parentReportAction, reportActions, transactionThreadReport?.parentReportActionID]); + }, [caseID, parentReportAction, reportActions, transactionThreadReport?.parentReportActionID]); const isActionOwner = typeof requestParentReportAction?.actorAccountID === 'number' && typeof session?.accountID === 'number' && requestParentReportAction.actorAccountID === session?.accountID; diff --git a/src/pages/home/report/ContextMenu/BaseReportActionContextMenu.tsx b/src/pages/home/report/ContextMenu/BaseReportActionContextMenu.tsx index f7db749753c7..94ea94751032 100755 --- a/src/pages/home/report/ContextMenu/BaseReportActionContextMenu.tsx +++ b/src/pages/home/report/ContextMenu/BaseReportActionContextMenu.tsx @@ -179,13 +179,7 @@ function BaseReportActionContextMenu({ const isMoneyRequestReport = useMemo(() => ReportUtilsIsMoneyRequestReport(childReport), [childReport]); const isInvoiceReport = useMemo(() => ReportUtilsIsInvoiceReport(childReport), [childReport]); - const iouAction = paginatedReportActions.find((action) => isMoneyRequestAction(action) && !!getOriginalMessage(action)?.IOUTransactionID); - const requestIOUTransactionID = isMoneyRequestAction(iouAction) ? getOriginalMessage(iouAction)?.IOUTransactionID : undefined; - const [childTransaction] = useOnyx(`${ONYXKEYS.COLLECTION.TRANSACTION}${requestIOUTransactionID}`, {canBeMissing: true}); const requestParentReportAction = useMemo(() => { - if (isDemoTransaction(childTransaction)) { - return iouAction; - } if (isMoneyRequestReport || isInvoiceReport) { if (!paginatedReportActions || !transactionThreadReport?.parentReportActionID) { return undefined; @@ -193,7 +187,7 @@ function BaseReportActionContextMenu({ return paginatedReportActions.find((action) => action.reportActionID === transactionThreadReport.parentReportActionID); } return parentReportAction; - }, [parentReportAction, isMoneyRequestReport, isInvoiceReport, paginatedReportActions, transactionThreadReport?.parentReportActionID, childTransaction, iouAction]); + }, [parentReportAction, isMoneyRequestReport, isInvoiceReport, paginatedReportActions, transactionThreadReport?.parentReportActionID]); const moneyRequestAction = transactionThreadReportID ? requestParentReportAction : parentReportAction; const isChildReportArchived = useReportIsArchived(childReport?.reportID); From dc03f68c96317984784a3b58b53c150250806dce Mon Sep 17 00:00:00 2001 From: DylanDylann Date: Mon, 7 Jul 2025 15:26:52 +0700 Subject: [PATCH 21/27] add opt data --- src/libs/actions/IOU.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 3dbcbd64ed73..e3aa3ef2a0a8 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -1338,6 +1338,9 @@ function buildOnyxDataForTestDriveIOU(testDriveIOUParams: BuildOnyxDataForTestDr iouReportID: testDriveIOUParams.iouOptimisticParams.report.reportID, transactionID: testDriveIOUParams.transaction.transactionID, }); + if (testDriveIOUParams.testDriveCommentReportActionID) { + optimisticIOUReportAction.reportActionID = testDriveIOUParams.testDriveCommentReportActionID; + } const text = Localize.translateLocal('testDrive.employeeInviteMessage', {name: personalDetailsList?.[userAccountID]?.firstName ?? ''}); const textComment = buildOptimisticAddCommentReportAction(text, undefined, userAccountID, undefined, undefined, undefined, testDriveIOUParams.testDriveCommentReportActionID); From da375b104e7ac95d67972c37658d8aef35604889 Mon Sep 17 00:00:00 2001 From: DylanDylann Date: Mon, 7 Jul 2025 15:29:20 +0700 Subject: [PATCH 22/27] remove import --- .../home/report/ContextMenu/BaseReportActionContextMenu.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/pages/home/report/ContextMenu/BaseReportActionContextMenu.tsx b/src/pages/home/report/ContextMenu/BaseReportActionContextMenu.tsx index 94ea94751032..84c4dadd272f 100755 --- a/src/pages/home/report/ContextMenu/BaseReportActionContextMenu.tsx +++ b/src/pages/home/report/ContextMenu/BaseReportActionContextMenu.tsx @@ -21,7 +21,7 @@ import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useRestoreInputFocus from '@hooks/useRestoreInputFocus'; import useStyleUtils from '@hooks/useStyleUtils'; import {getExpensifyCardFromReportAction} from '@libs/CardMessageUtils'; -import {getLinkedTransactionID, getOneTransactionThreadReportID, getOriginalMessage, getReportAction, isMoneyRequestAction} from '@libs/ReportActionsUtils'; +import {getLinkedTransactionID, getOneTransactionThreadReportID, getOriginalMessage, getReportAction} from '@libs/ReportActionsUtils'; import { chatIncludesChronosWithID, getSourceIDFromReportAction, @@ -32,7 +32,6 @@ import { isTrackExpenseReport as ReportUtilsIsTrackExpenseReport, } from '@libs/ReportUtils'; import shouldEnableContextMenuEnterShortcut from '@libs/shouldEnableContextMenuEnterShortcut'; -import {isDemoTransaction} from '@libs/TransactionUtils'; import {isAnonymousUser, signOutAndRedirectToSignIn} from '@userActions/Session'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; From 058a2641e1d1525cc792f1f9976e6a4fec4c397a Mon Sep 17 00:00:00 2001 From: DylanDylann Date: Mon, 7 Jul 2025 17:00:19 +0700 Subject: [PATCH 23/27] Update opt data --- src/libs/actions/IOU.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index e3aa3ef2a0a8..9c53ad85a356 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -1338,8 +1338,8 @@ function buildOnyxDataForTestDriveIOU(testDriveIOUParams: BuildOnyxDataForTestDr iouReportID: testDriveIOUParams.iouOptimisticParams.report.reportID, transactionID: testDriveIOUParams.transaction.transactionID, }); - if (testDriveIOUParams.testDriveCommentReportActionID) { - optimisticIOUReportAction.reportActionID = testDriveIOUParams.testDriveCommentReportActionID; + if (testDriveIOUParams.iouOptimisticParams.action.reportActionID) { + optimisticIOUReportAction.reportActionID = testDriveIOUParams.iouOptimisticParams.action.reportActionID; } const text = Localize.translateLocal('testDrive.employeeInviteMessage', {name: personalDetailsList?.[userAccountID]?.firstName ?? ''}); From f060c5b2379b39305391183d471010be0956f60a Mon Sep 17 00:00:00 2001 From: DylanDylann Date: Mon, 7 Jul 2025 21:10:52 +0700 Subject: [PATCH 24/27] resolve cmt --- src/libs/ReportUtils.ts | 4 +++- src/libs/actions/IOU.ts | 6 ++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index fb315d08f58f..02eba8a9265b 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -374,6 +374,7 @@ type BuildOptimisticIOUReportActionParams = { created?: string; linkedExpenseReportAction?: OnyxEntry; isPersonalTrackingExpense?: boolean; + reportActionID?: string; }; type OptimisticIOUReportAction = Pick< @@ -6236,6 +6237,7 @@ function buildOptimisticIOUReportAction(params: BuildOptimisticIOUReportActionPa created = DateUtils.getDBTime(), linkedExpenseReportAction, isPersonalTrackingExpense = false, + reportActionID, } = params; const IOUReportID = isPersonalTrackingExpense ? undefined : iouReportID || generateReportID(); @@ -6295,7 +6297,7 @@ function buildOptimisticIOUReportAction(params: BuildOptimisticIOUReportActionPa automatic: false, isAttachmentOnly: false, originalMessage, - reportActionID: rand64(), + reportActionID: reportActionID ?? rand64(), shouldShow: true, created, pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 9c53ad85a356..1f9ada44940f 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -1337,10 +1337,8 @@ function buildOnyxDataForTestDriveIOU(testDriveIOUParams: BuildOnyxDataForTestDr paymentType: CONST.IOU.PAYMENT_TYPE.ELSEWHERE, iouReportID: testDriveIOUParams.iouOptimisticParams.report.reportID, transactionID: testDriveIOUParams.transaction.transactionID, + reportActionID: testDriveIOUParams.iouOptimisticParams.action.reportActionID, }); - if (testDriveIOUParams.iouOptimisticParams.action.reportActionID) { - optimisticIOUReportAction.reportActionID = testDriveIOUParams.iouOptimisticParams.action.reportActionID; - } const text = Localize.translateLocal('testDrive.employeeInviteMessage', {name: personalDetailsList?.[userAccountID]?.firstName ?? ''}); const textComment = buildOptimisticAddCommentReportAction(text, undefined, userAccountID, undefined, undefined, undefined, testDriveIOUParams.testDriveCommentReportActionID); @@ -1600,8 +1598,8 @@ function buildOnyxDataForMoneyRequest(moneyRequestParams: BuildOnyxDataForMoneyR paymentType: isScanRequest && !isTestReceipt ? undefined : CONST.IOU.PAYMENT_TYPE.ELSEWHERE, iouReportID: iou.report.reportID, transactionID: transaction.transactionID, + reportActionID: iou.action.reportActionID, }); - optimisticIOUReportAction.reportActionID = iou.action.reportActionID; optimisticData.push( { From acaeff2ef94c84b66f6a545a188b1f540bc78c2f Mon Sep 17 00:00:00 2001 From: DylanDylann Date: Fri, 11 Jul 2025 01:20:21 +0800 Subject: [PATCH 25/27] merge main --- src/components/OfflineWithFeedback.tsx | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/components/OfflineWithFeedback.tsx b/src/components/OfflineWithFeedback.tsx index 641b66c1e740..6a433a52dbcd 100644 --- a/src/components/OfflineWithFeedback.tsx +++ b/src/components/OfflineWithFeedback.tsx @@ -109,8 +109,7 @@ function OfflineWithFeedback({ const applyStrikeThrough = useCallback( (childrenProp: React.ReactNode): React.ReactNode => { const strikeThroughChildren = mapChildrenFlat(childrenProp, (child) => { - console.log('applyStrikeThrough', child); - if (!React.isValidElement(child)) { + if (!React.isValidElement(child) || child.type === ImageSVG) { return child; } @@ -120,14 +119,10 @@ function OfflineWithFeedback({ style: StyleUtils.combineStyles(childProps.style ?? [], styles.offlineFeedback.deleted, styles.userSelectNone), }; - console.log('props', props); - if (childProps.children) { props.children = applyStrikeThrough(childProps.children); } - console.log('cloneElement'); - return React.cloneElement(child, props); }); From d996a2ddae1e544b5b7a2a8316fd08da2f6d995a Mon Sep 17 00:00:00 2001 From: DylanDylann Date: Sun, 13 Jul 2025 17:09:10 +0800 Subject: [PATCH 26/27] chore --- tests/unit/ReportSecondaryActionUtilsTest.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit/ReportSecondaryActionUtilsTest.ts b/tests/unit/ReportSecondaryActionUtilsTest.ts index fa58a36c48be..c59112af2e28 100644 --- a/tests/unit/ReportSecondaryActionUtilsTest.ts +++ b/tests/unit/ReportSecondaryActionUtilsTest.ts @@ -1098,7 +1098,7 @@ describe('getSecondaryAction', () => { await Onyx.merge(`${ONYXKEYS.COLLECTION.POLICY}${POLICY_ID}`, policy); const result = getSecondaryReportActions({report, chatReport, reportTransactions: [transaction], violations: {}, policy}); - expect(result.includes(CONST.REPORT.SECONDARY_ACTIONS.DELETE)).toBe(false); + expect(result.includes(CONST.REPORT.SECONDARY_ACTIONS.DELETE)).toBe(true); }); it('include EXPORT_TO_ACCOUNTING option for settled expense report', async () => { From d57586b70278ec8baea78c0d36b55867c9b327e0 Mon Sep 17 00:00:00 2001 From: DylanDylann Date: Sun, 13 Jul 2025 17:09:25 +0800 Subject: [PATCH 27/27] chore --- Mobile-Expensify | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mobile-Expensify b/Mobile-Expensify index 64c234b647d6..297576dcb900 160000 --- a/Mobile-Expensify +++ b/Mobile-Expensify @@ -1 +1 @@ -Subproject commit 64c234b647d673e0588595d19b2442db91104ca2 +Subproject commit 297576dcb90053f18473b3228dfe1be1270fb879