diff --git a/Mobile-Expensify b/Mobile-Expensify
index 70de73073e5d..e1f7b4f3e00c 160000
--- a/Mobile-Expensify
+++ b/Mobile-Expensify
@@ -1 +1 @@
-Subproject commit 70de73073e5d23f7d27b4bb15fb499ae32ae1ed4
+Subproject commit e1f7b4f3e00c6d0158e6ae8f86d0c98782f2e3ff
diff --git a/android/app/build.gradle b/android/app/build.gradle
index 29b64a9b0c7f..e9e1bba6ab95 100644
--- a/android/app/build.gradle
+++ b/android/app/build.gradle
@@ -114,8 +114,8 @@ android {
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
multiDexEnabled rootProject.ext.multiDexEnabled
- versionCode 1009027807
- versionName "9.2.78-7"
+ versionCode 1009027808
+ versionName "9.2.78-8"
// Supported language variants must be declared here to avoid from being removed during the compilation.
// This also helps us to not include unnecessary language variants in the APK.
resConfigs "en", "es"
diff --git a/ios/NewExpensify/Info.plist b/ios/NewExpensify/Info.plist
index d97e3ac76a12..1e5abed0466e 100644
--- a/ios/NewExpensify/Info.plist
+++ b/ios/NewExpensify/Info.plist
@@ -44,7 +44,7 @@
CFBundleVersion
- 9.2.78.7
+ 9.2.78.8
FullStory
OrgId
diff --git a/ios/NotificationServiceExtension/Info.plist b/ios/NotificationServiceExtension/Info.plist
index 341b583e50c6..f12b846204b4 100644
--- a/ios/NotificationServiceExtension/Info.plist
+++ b/ios/NotificationServiceExtension/Info.plist
@@ -13,7 +13,7 @@
CFBundleShortVersionString
9.2.78
CFBundleVersion
- 9.2.78.7
+ 9.2.78.8
NSExtension
NSExtensionPointIdentifier
diff --git a/ios/ShareViewController/Info.plist b/ios/ShareViewController/Info.plist
index 35441022a6f9..53c3134814c6 100644
--- a/ios/ShareViewController/Info.plist
+++ b/ios/ShareViewController/Info.plist
@@ -13,7 +13,7 @@
CFBundleShortVersionString
9.2.78
CFBundleVersion
- 9.2.78.7
+ 9.2.78.8
NSExtension
NSExtensionAttributes
diff --git a/package-lock.json b/package-lock.json
index 78be1ab41cee..f0753176398b 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "new.expensify",
- "version": "9.2.78-7",
+ "version": "9.2.78-8",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "new.expensify",
- "version": "9.2.78-7",
+ "version": "9.2.78-8",
"hasInstallScript": true,
"license": "MIT",
"dependencies": {
diff --git a/package.json b/package.json
index fd0f5dcaffb5..c5e42f3ed2e8 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "new.expensify",
- "version": "9.2.78-7",
+ "version": "9.2.78-8",
"author": "Expensify, Inc.",
"homepage": "https://new.expensify.com",
"description": "New Expensify is the next generation of Expensify: a reimagination of payments based atop a foundation of chat.",
diff --git a/src/components/Search/index.tsx b/src/components/Search/index.tsx
index 71aa7ca1b498..b2a24922efe1 100644
--- a/src/components/Search/index.tsx
+++ b/src/components/Search/index.tsx
@@ -106,6 +106,7 @@ function mapTransactionItemToSelectedEntry(
item.keyForList,
{
isSelected: true,
+ canDelete: item.canDelete,
canReject: canRejectRequest,
canHold: canHoldRequest,
isHeld: isOnHold(item),
@@ -198,6 +199,7 @@ function prepareTransactionsList(
...selectedTransactions,
[item.keyForList]: {
isSelected: true,
+ canDelete: item.canDelete,
canReject: canRejectRequest,
canHold: canHoldRequest,
isHeld: isOnHold(item),
@@ -541,6 +543,7 @@ function Search({
),
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
isSelected: areAllMatchingItemsSelected || selectedTransactions[transactionItem.transactionID]?.isSelected || isExpenseReportType,
+ canDelete: transactionItem.canDelete,
canReject: canRejectRequest,
reportID: transactionItem.reportID,
policyID: transactionItem.report?.policyID,
@@ -592,6 +595,7 @@ function Search({
),
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
isSelected: areAllMatchingItemsSelected || selectedTransactions[transactionItem.transactionID].isSelected,
+ canDelete: transactionItem.canDelete,
canReject: canRejectRequest,
reportID: transactionItem.reportID,
policyID: transactionItem.report?.policyID,
diff --git a/src/components/Search/types.ts b/src/components/Search/types.ts
index 8f5beab5e9c6..77beb3a9a150 100644
--- a/src/components/Search/types.ts
+++ b/src/components/Search/types.ts
@@ -11,6 +11,9 @@ type SelectedTransactionInfo = {
/** Whether the transaction is selected */
isSelected: boolean;
+ /** If the transaction can be deleted */
+ canDelete: boolean;
+
/** If the transaction can be rejected */
canReject: boolean;
diff --git a/src/libs/SearchUIUtils.ts b/src/libs/SearchUIUtils.ts
index caf32aa867c2..e00127fdb1ef 100644
--- a/src/libs/SearchUIUtils.ts
+++ b/src/libs/SearchUIUtils.ts
@@ -2658,6 +2658,7 @@ function getTransactionFromTransactionListItem(item: TransactionListItemType): O
isTaxAmountColumnWide,
violations,
hash,
+ canDelete,
accountID,
policyID,
...transaction
diff --git a/src/pages/Search/SearchPage.tsx b/src/pages/Search/SearchPage.tsx
index 19709ee3f08d..8a60573f64ac 100644
--- a/src/pages/Search/SearchPage.tsx
+++ b/src/pages/Search/SearchPage.tsx
@@ -59,10 +59,8 @@ import {navigateToParticipantPage} from '@libs/IOUUtils';
import Navigation from '@libs/Navigation/Navigation';
import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types';
import type {SearchFullscreenNavigatorParamList} from '@libs/Navigation/types';
-import {getActiveAdminWorkspaces, hasDynamicExternalWorkflow, hasOnlyPersonalPolicies as hasOnlyPersonalPoliciesUtil, hasVBBA, isPaidGroupPolicy} from '@libs/PolicyUtils';
-import {getOriginalMessage, isMoneyRequestAction} from '@libs/ReportActionsUtils';
+import {getActiveAdminWorkspaces, hasDynamicExternalWorkflow, hasOnlyPersonalPolicies as hasOnlyPersonalPoliciesUtil, isPaidGroupPolicy} from '@libs/PolicyUtils';
import {
- canDeleteMoneyRequestReport,
generateReportID,
getPolicyExpenseChat,
getReportOrDraftReport,
@@ -671,24 +669,7 @@ function SearchPage({route}: SearchPageProps) {
});
}
- const shouldShowDeleteOption =
- !isOffline &&
- selectedTransactionsKeys.every((id) => {
- const transaction = currentSearchResults?.data?.[`${ONYXKEYS.COLLECTION.TRANSACTION}${id}`];
- if (!transaction) {
- return false;
- }
- const parentReportID = transaction.reportID;
- const parentReport = currentSearchResults?.data?.[`${ONYXKEYS.COLLECTION.REPORT}${parentReportID}`];
- if (!parentReport) {
- return false;
- }
- const reportActions = currentSearchResults?.data?.[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${parentReportID}`];
- const parentReportAction = Object.values(reportActions ?? {}).find(
- (action) => (isMoneyRequestAction(action) ? getOriginalMessage(action)?.IOUTransactionID : undefined) === transaction.transactionID,
- );
- return canDeleteMoneyRequestReport(parentReport, [transaction], parentReportAction ? [parentReportAction] : []);
- });
+ const shouldShowDeleteOption = !isOffline && selectedTransactionsKeys.every((id) => selectedTransactions[id].canDelete);
if (shouldShowDeleteOption) {
options.push({
@@ -735,16 +716,15 @@ function SearchPage({route}: SearchPageProps) {
status,
hash,
selectedTransactions,
- expensifyIcons,
translate,
areAllMatchingItemsSelected,
isOffline,
selectedReports,
- queryJSON,
+ selectedTransactionReportIDs,
lastPaymentMethods,
selectedReportIDs,
allTransactions,
- selectedTransactionReportIDs,
+ queryJSON,
selectedPolicyIDs,
policies,
integrationsExportTemplates,
@@ -754,14 +734,14 @@ function SearchPage({route}: SearchPageProps) {
dismissedRejectUseExplanation,
bulkPayButtonOptions,
onBulkPaySelected,
- areAllTransactionsFromSubmitter,
- dismissedHoldUseExplanation,
allReports,
- currentSearchResults?.data,
theme.icon,
styles.colorMuted,
styles.fontWeightNormal,
styles.textWrap,
+ expensifyIcons,
+ dismissedHoldUseExplanation,
+ areAllTransactionsFromSubmitter,
]);
const handleDeleteExpenses = () => {
diff --git a/src/types/onyx/SearchResults.ts b/src/types/onyx/SearchResults.ts
index 8b90d653cbbb..08b66a5086af 100644
--- a/src/types/onyx/SearchResults.ts
+++ b/src/types/onyx/SearchResults.ts
@@ -86,6 +86,9 @@ type SearchTransaction = {
/** The transaction amount */
amount: number;
+ /** If the transaction can be deleted */
+ canDelete: boolean;
+
/** The edited transaction amount */
modifiedAmount: number;
diff --git a/tests/unit/MoneyRequestReportUtilsTest.ts b/tests/unit/MoneyRequestReportUtilsTest.ts
index 9cae1e021d32..7bfdb2105183 100644
--- a/tests/unit/MoneyRequestReportUtilsTest.ts
+++ b/tests/unit/MoneyRequestReportUtilsTest.ts
@@ -55,6 +55,7 @@ const transactionItemBaseMock: TransactionListItemType = {
policy: policyBaseMock,
reportAction: reportActionBaseMock,
holdReportAction: undefined,
+ canDelete: true,
cardID: undefined,
cardName: undefined,
category: '',
diff --git a/tests/unit/Search/SearchUIUtilsTest.ts b/tests/unit/Search/SearchUIUtilsTest.ts
index fc6bb19fe607..1354ba19f2bb 100644
--- a/tests/unit/Search/SearchUIUtilsTest.ts
+++ b/tests/unit/Search/SearchUIUtilsTest.ts
@@ -386,6 +386,7 @@ const searchResults: OnyxTypes.SearchResults = {
[`report_${reportID5}`]: report5,
[`transactions_${transactionID}`]: {
amount: -5000,
+ canDelete: true,
cardID: undefined,
cardName: undefined,
category: '',
@@ -415,6 +416,7 @@ const searchResults: OnyxTypes.SearchResults = {
},
[`transactions_${transactionID2}`]: {
amount: -5000,
+ canDelete: true,
cardID: undefined,
cardName: undefined,
category: '',
@@ -445,6 +447,7 @@ const searchResults: OnyxTypes.SearchResults = {
...allViolations,
[`transactions_${transactionID3}`]: {
amount: 1200,
+ canDelete: true,
cardID: undefined,
cardName: undefined,
category: '',
@@ -474,6 +477,7 @@ const searchResults: OnyxTypes.SearchResults = {
},
[`transactions_${transactionID4}`]: {
amount: 3200,
+ canDelete: true,
cardID: undefined,
cardName: undefined,
category: '',
@@ -759,6 +763,7 @@ const transactionsListItems = [
policy,
reportAction: reportAction1,
holdReportAction: undefined,
+ canDelete: true,
cardID: undefined,
cardName: undefined,
category: '',
@@ -810,6 +815,7 @@ const transactionsListItems = [
policy,
reportAction: reportAction2,
holdReportAction: undefined,
+ canDelete: true,
cardID: undefined,
cardName: undefined,
category: '',
@@ -871,6 +877,7 @@ const transactionsListItems = [
policy,
reportAction: reportAction3,
holdReportAction: undefined,
+ canDelete: true,
cardID: undefined,
cardName: undefined,
category: '',
@@ -927,6 +934,7 @@ const transactionsListItems = [
policy,
reportAction: reportAction4,
holdReportAction: undefined,
+ canDelete: true,
cardID: undefined,
cardName: undefined,
category: '',
@@ -1020,6 +1028,7 @@ const transactionReportGroupListItems = [
reportAction: reportAction1,
holdReportAction: undefined,
amount: -5000,
+ canDelete: true,
cardID: undefined,
cardName: undefined,
category: '',
@@ -1114,6 +1123,7 @@ const transactionReportGroupListItems = [
reportAction: reportAction2,
holdReportAction: undefined,
amount: -5000,
+ canDelete: true,
cardID: undefined,
cardName: undefined,
category: '',
@@ -1215,7 +1225,122 @@ const transactionReportGroupListItems = [
displayName: 'Approver',
login: 'approver@policy.com',
},
- transactions: [transactionsListItems.at(2), transactionsListItems.at(3)],
+ transactions: [
+ {
+ amount: 1200,
+ action: 'view',
+ allActions: ['view'],
+ report: report3,
+ policy,
+ reportAction: reportAction3,
+ holdReportAction: undefined,
+ canDelete: true,
+ cardID: undefined,
+ cardName: undefined,
+ category: '',
+ comment: {comment: ''},
+ created: '2025-03-05',
+ currency: 'VND',
+ hasEReceipt: false,
+ merchant: '(none)',
+ modifiedAmount: 0,
+ modifiedCreated: '',
+ modifiedCurrency: '',
+ modifiedMerchant: '',
+ parentTransactionID: '',
+ reportID: '99999',
+ tag: '',
+ transactionID: '3',
+ from: {
+ accountID: 18439984,
+ avatar: 'https://d2k5nsl2zxldvw.cloudfront.net/images/avatars/avatar_3.png',
+ displayName: 'Admin',
+ login: 'admin@policy.com',
+ },
+ to: {
+ accountID: 1111111,
+ avatar: 'https://d2k5nsl2zxldvw.cloudfront.net/images/avatars/avatar_3.png',
+ displayName: 'Approver',
+ login: 'approver@policy.com',
+ },
+ formattedFrom: 'Admin',
+ formattedTo: 'Approver',
+ formattedTotal: 1200,
+ formattedMerchant: '',
+ date: '2025-03-05',
+ shouldShowMerchant: true,
+ shouldShowYear: true,
+ keyForList: '3',
+ isAmountColumnWide: false,
+ isTaxAmountColumnWide: false,
+ receipt: undefined,
+ taxAmount: undefined,
+ mccGroup: undefined,
+ modifiedMCCGroup: undefined,
+ pendingAction: undefined,
+ errors: undefined,
+ violations: [],
+ groupAmount: -5000,
+ groupCurrency: 'USD',
+ },
+ {
+ amount: 3200,
+ action: 'view',
+ allActions: ['view'],
+ report: report3,
+ policy,
+ reportAction: reportAction4,
+ holdReportAction: undefined,
+ canDelete: true,
+ cardID: undefined,
+ cardName: undefined,
+ category: '',
+ comment: {comment: ''},
+ created: '2025-03-05',
+ currency: 'VND',
+ hasEReceipt: false,
+ merchant: '(none)',
+ modifiedAmount: 0,
+ modifiedCreated: '',
+ modifiedCurrency: '',
+ modifiedMerchant: '',
+ parentTransactionID: '',
+ reportID: '99999',
+ tag: '',
+ transactionID: '4',
+ from: {
+ accountID: 18439984,
+ avatar: 'https://d2k5nsl2zxldvw.cloudfront.net/images/avatars/avatar_3.png',
+ displayName: 'Admin',
+ login: 'admin@policy.com',
+ },
+ to: {
+ accountID: 1111111,
+ avatar: 'https://d2k5nsl2zxldvw.cloudfront.net/images/avatars/avatar_3.png',
+ displayName: 'Approver',
+ login: 'approver@policy.com',
+ },
+ formattedFrom: 'Admin',
+ formattedTo: 'Approver',
+ formattedTotal: 3200,
+ formattedMerchant: '',
+ date: '2025-03-05',
+ shouldShowMerchant: true,
+ shouldShowYear: true,
+ keyForList: '4',
+ isAmountColumnWide: false,
+ isTaxAmountColumnWide: false,
+ receipt: undefined,
+ taxAmount: undefined,
+ mccGroup: undefined,
+ modifiedMCCGroup: undefined,
+ pendingAction: undefined,
+ errors: undefined,
+ violations: [],
+ groupAmount: -5000,
+ groupCurrency: 'USD',
+ },
+ ],
},
{
groupedBy: 'expense-report',
@@ -1696,7 +1821,7 @@ describe('SearchUIUtils', () => {
expect(distanceTransaction).toBeDefined();
expect(distanceTransaction?.iouRequestType).toBe(CONST.IOU.REQUEST_TYPE.DISTANCE);
- const expectedPropertyCount = 45;
+ const expectedPropertyCount = 46;
expect(Object.keys(distanceTransaction ?? {}).length).toBe(expectedPropertyCount);
});
@@ -1729,7 +1854,7 @@ describe('SearchUIUtils', () => {
expect(distanceTransaction).toBeDefined();
expect(distanceTransaction?.iouRequestType).toBe(CONST.IOU.REQUEST_TYPE.DISTANCE);
- const expectedPropertyCount = 45;
+ const expectedPropertyCount = 46;
expect(Object.keys(distanceTransaction ?? {}).length).toBe(expectedPropertyCount);
});
@@ -2321,6 +2446,7 @@ describe('SearchUIUtils', () => {
// eslint-disable-next-line @typescript-eslint/naming-convention
transactions_1805965960759424086: {
amount: 0,
+ canDelete: false,
category: 'Employee Meals Remote (Fringe Benefit)',
comment: {
comment: '',
@@ -2443,6 +2569,7 @@ describe('SearchUIUtils', () => {
// eslint-disable-next-line @typescript-eslint/naming-convention
transactions_1805965960759424086: {
amount: 0,
+ canDelete: false,
cardID: undefined,
cardName: undefined,
category: 'Employee Meals Remote (Fringe Benefit)',
diff --git a/tests/unit/Search/handleActionButtonPressTest.ts b/tests/unit/Search/handleActionButtonPressTest.ts
index 5bb137e4228e..4deb193a807c 100644
--- a/tests/unit/Search/handleActionButtonPressTest.ts
+++ b/tests/unit/Search/handleActionButtonPressTest.ts
@@ -92,6 +92,7 @@ const mockReportItemWithHold = {
action: 'view',
allActions: ['view'],
amount: -1200,
+ canDelete: true,
category: '',
comment: {
comment: '',
@@ -180,6 +181,7 @@ const mockReportItemWithHold = {
action: 'view',
allActions: ['view'],
amount: -12300,
+ canDelete: true,
category: '',
comment: {
comment: '',
diff --git a/tests/unit/TransactionGroupListItemTest.tsx b/tests/unit/TransactionGroupListItemTest.tsx
index 05cc0ab57376..6e360fdafeb7 100644
--- a/tests/unit/TransactionGroupListItemTest.tsx
+++ b/tests/unit/TransactionGroupListItemTest.tsx
@@ -26,6 +26,7 @@ jest.mock('@libs/SearchUIUtils', () => ({
const mockTransaction: TransactionListItemType = {
accountID: 1,
amount: 0,
+ canDelete: true,
category: '',
groupAmount: 1284,
groupCurrency: 'USD',