Skip to content

Commit 6f9802f

Browse files
committed
Bulk Edit. Merge snapshot data to fix missing data after hard refresh
1 parent 148a503 commit 6f9802f

4 files changed

Lines changed: 56 additions & 9 deletions

File tree

src/hooks/useSearchBulkActions.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -892,7 +892,8 @@ function useSearchBulkActions({queryJSON, deleteTransactionsOnSearch}: UseSearch
892892
const selectedTransactionsList = Object.values(selectedTransactions)
893893
.map((transaction) => transaction.transaction)
894894
.filter((transaction): transaction is Transaction => !!transaction);
895-
const canEditMultiple = canEditMultipleTransactions(selectedTransactionsList, allReportActions, allReports, policies, isExpenseReportSearch) && isBetaEnabled(CONST.BETAS.BULK_EDIT);
895+
const canEditMultiple =
896+
canEditMultipleTransactions(selectedTransactionsList, allReportActions, allReports, policies, isExpenseReportSearch, searchResults?.data) && isBetaEnabled(CONST.BETAS.BULK_EDIT);
896897

897898
if (canEditMultiple) {
898899
options.push({

src/libs/ReportUtils.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ import type {
5656
ReportMetadata,
5757
ReportNameValuePairs,
5858
ReportViolationName,
59+
SearchResults,
5960
Task,
6061
Transaction,
6162
TransactionViolation,
@@ -4876,6 +4877,7 @@ function canEditMultipleTransactions(
48764877
reports: OnyxCollection<Report>,
48774878
policies: OnyxCollection<Policy>,
48784879
areReportsSelected = false,
4880+
searchSnapshotData?: SearchResults['data'],
48794881
): boolean {
48804882
if (areReportsSelected) {
48814883
return false;
@@ -4896,7 +4898,9 @@ function canEditMultipleTransactions(
48964898
return false;
48974899
}
48984900

4899-
const reportAction = getIOUActionForTransactionID(Object.values(reportActions?.[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${transaction.reportID}`] ?? {}), transaction.transactionID);
4901+
const reportActionsKey = `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${transaction.reportID}` as const;
4902+
const actionsForReport = {...(searchSnapshotData?.[reportActionsKey] ?? {}), ...(reportActions?.[reportActionsKey] ?? {})};
4903+
const reportAction = getIOUActionForTransactionID(Object.values(actionsForReport), transaction.transactionID);
49004904
const report = reports?.[`${ONYXKEYS.COLLECTION.REPORT}${transaction.reportID}`];
49014905
const policy = policies?.[`${ONYXKEYS.COLLECTION.POLICY}${report?.policyID}`];
49024906

src/libs/Violations/ViolationsUtils.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -377,12 +377,12 @@ const ViolationsUtils = {
377377
}
378378

379379
// Remove 'missingCategory' violation if category is valid according to policy
380-
if (hasMissingCategoryViolation && (isCategoryInPolicy || isSelfDM)) {
380+
if (hasMissingCategoryViolation && (isCategoryInPolicy || isSelfDM || isInvoiceTransaction)) {
381381
newTransactionViolations = reject(newTransactionViolations, {name: 'missingCategory'});
382382
}
383383

384384
// Add 'missingCategory' violation if category is required and not set
385-
if (!hasMissingCategoryViolation && policyRequiresCategories && !categoryKey && !isSelfDM) {
385+
if (!hasMissingCategoryViolation && policyRequiresCategories && !categoryKey && !isSelfDM && !isInvoiceTransaction) {
386386
newTransactionViolations.push({name: 'missingCategory', type: CONST.VIOLATION_TYPES.VIOLATION, showInReview: true});
387387
}
388388
}

src/pages/Search/SearchEditMultiple/SearchEditMultiplePage.tsx

Lines changed: 47 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import React, {useEffect} from 'react';
22
import {View} from 'react-native';
3+
import type {OnyxCollection} from 'react-native-onyx';
34
import type {ValueOf} from 'type-fest';
45
import Button from '@components/Button';
56
import HeaderWithBackButton from '@components/HeaderWithBackButton';
@@ -24,13 +25,50 @@ import CONST from '@src/CONST';
2425
import ONYXKEYS from '@src/ONYXKEYS';
2526
import ROUTES from '@src/ROUTES';
2627
import type {Route} from '@src/ROUTES';
28+
import type {ReportActions, SearchResults, Transaction} from '@src/types/onyx';
2729
import type {TransactionChanges} from '@src/types/onyx/Transaction';
2830
import {getTransactionEditContext} from './SearchEditMultipleUtils';
2931

32+
/**
33+
* After a hard refresh, invoice transaction and report action data may only exist in the search snapshot,
34+
* not in the main Onyx collections. These helpers fill gaps from the snapshot so bulk edit can work.
35+
*/
36+
function withSnapshotTransactions(onyxTransactions: OnyxCollection<Transaction> | undefined, snapshotData: SearchResults['data'] | undefined): OnyxCollection<Transaction> | undefined {
37+
if (!snapshotData) {
38+
return onyxTransactions;
39+
}
40+
const merged = {...onyxTransactions};
41+
for (const key of Object.keys(snapshotData)) {
42+
if (!key.startsWith(ONYXKEYS.COLLECTION.TRANSACTION)) {
43+
continue;
44+
}
45+
const typedKey = key as `${typeof ONYXKEYS.COLLECTION.TRANSACTION}${string}`;
46+
if (!merged[typedKey]) {
47+
merged[typedKey] = snapshotData[typedKey] ?? null;
48+
}
49+
}
50+
return merged;
51+
}
52+
53+
function withSnapshotReportActions(onyxReportActions: OnyxCollection<ReportActions> | undefined, snapshotData: SearchResults['data'] | undefined): OnyxCollection<ReportActions> | undefined {
54+
if (!snapshotData) {
55+
return onyxReportActions;
56+
}
57+
const merged = {...onyxReportActions};
58+
for (const key of Object.keys(snapshotData)) {
59+
if (!key.startsWith(ONYXKEYS.COLLECTION.REPORT_ACTIONS)) {
60+
continue;
61+
}
62+
const typedKey = key as `${typeof ONYXKEYS.COLLECTION.REPORT_ACTIONS}${string}`;
63+
merged[typedKey] = {...(snapshotData[typedKey] ?? {}), ...(merged[typedKey] ?? {})};
64+
}
65+
return merged;
66+
}
67+
3068
function SearchEditMultiplePage() {
3169
const {translate} = useLocalize();
3270
const styles = useThemeStyles();
33-
const {currentSearchHash} = useSearchStateContext();
71+
const {currentSearchHash, currentSearchResults} = useSearchStateContext();
3472
const {clearSelectedTransactions} = useSearchActionsContext();
3573
const [policies] = useOnyx(ONYXKEYS.COLLECTION.POLICY);
3674
const [activePolicyID] = useOnyx(ONYXKEYS.NVP_ACTIVE_POLICY_ID);
@@ -39,10 +77,14 @@ function SearchEditMultiplePage() {
3977
const [allReports] = useOnyx(ONYXKEYS.COLLECTION.REPORT);
4078
const [allReportActions] = useOnyx(ONYXKEYS.COLLECTION.REPORT_ACTIONS);
4179

80+
const snapshotData = currentSearchResults?.data;
81+
const mergedTransactions = withSnapshotTransactions(allTransactions, snapshotData);
82+
const mergedReportActions = withSnapshotReportActions(allReportActions, snapshotData);
83+
4284
const selectedTransactionIDs = draftTransaction?.selectedTransactionIDs ?? [];
4385

4486
const selectedTransactionContexts = selectedTransactionIDs.flatMap((transactionID) => {
45-
const context = getTransactionEditContext(transactionID, allTransactions, allReports, allReportActions, policies);
87+
const context = getTransactionEditContext(transactionID, mergedTransactions, allReports, mergedReportActions, policies);
4688
return context ? [context] : [];
4789
});
4890

@@ -85,7 +127,7 @@ function SearchEditMultiplePage() {
85127
return !isIOUReport(report) && !isInvoiceReport(report) && transactionPolicy?.disabledFields?.reimbursable === false && !isManagedCardTransaction(transaction);
86128
});
87129

88-
const policyID = getSearchBulkEditPolicyID(selectedTransactionIDs, activePolicyID, allTransactions, allReports);
130+
const policyID = getSearchBulkEditPolicyID(selectedTransactionIDs, activePolicyID, mergedTransactions, allReports);
89131

90132
const policy = policyID ? policies?.[`${ONYXKEYS.COLLECTION.POLICY}${policyID}`] : undefined;
91133
const [policyCategories] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}${policyID}`);
@@ -152,8 +194,8 @@ function SearchEditMultiplePage() {
152194
changes,
153195
policy,
154196
reports: allReports,
155-
transactions: allTransactions,
156-
reportActions: allReportActions,
197+
transactions: mergedTransactions,
198+
reportActions: mergedReportActions,
157199
policyCategories,
158200
hash: currentSearchHash,
159201
allPolicies: policies,

0 commit comments

Comments
 (0)