-
Notifications
You must be signed in to change notification settings - Fork 3.9k
Reapply "Reapply "Feat: bulk edit multiple"" #84756
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
marcaaron
merged 59 commits into
Expensify:main
from
callstack-internal:feauture/bulk-edit-expenses-3
Mar 30, 2026
Merged
Changes from all commits
Commits
Show all changes
59 commits
Select commit
Hold shift + click to select a range
33cf846
Reapply "Reapply "Feat: bulk edit multiple""
pasyukevich 72bba39
Fix conditions for unreported expenses and fix common dependent tag l…
pasyukevich e132c76
Merge branch 'main' into feauture/bulk-edit-expenses-3
pasyukevich 6fd9a0b
Update SearchEditMultiplePage to include isInvoiceReport check in tra…
pasyukevich 4413a6e
Add isAnyInvoice check to determine IOU type in SearchEditMultipleAmo…
pasyukevich e0418e5
Enhance tax handling in updateMultipleMoneyRequests by adding tax amo…
pasyukevich c1aab27
Add support for negative amounts in self-DM track expenses in SearchE…
pasyukevich fdc4e3c
Fix selected tax rate appears as a separate rate
pasyukevich 19cce59
Fix cross policy bulk edit category shows rate not valid, refactor u…
pasyukevich 109395e
Refactor tax tracking logic in SearchEditMultiplePage to consider all…
pasyukevich 3b636bf
Enhance updateMultipleMoneyRequests to skip optimistic violation upda…
pasyukevich 3e5d947
Fix tag field and tag page header show different name
pasyukevich ab429bd
Merge branch 'main' into feauture/bulk-edit-expenses-3
pasyukevich 46d1bf5
Update tax rate title handling
pasyukevich 9499888
Add reportID to optimistic report action in updateMultipleMoneyRequests
pasyukevich 041dc2a
Merge branch 'main' into feauture/bulk-edit-expenses-3
pasyukevich 2c0a4a2
Fix failing tests
pasyukevich 4b0f5b8
Merge branch 'main' into feauture/bulk-edit-expenses-3
pasyukevich 5b46373
Enhance transaction validation by adding check for non-IOU reports be…
pasyukevich 9d447c1
Add tests for transaction category validation in IOU actions
pasyukevich 346d8dc
Merge branch 'main' into feauture/bulk-edit-expenses-3
pasyukevich 09c894a
fix tests
pasyukevich 71047b4
Add BULK_EDIT beta flag
pasyukevich 4c91de7
Merge branch 'main' into feauture/bulk-edit-expenses-3
pasyukevich 71c0018
fix lint
pasyukevich d74cab0
fix tests
pasyukevich c56a5ce
Refactor transaction policy handling in updateMultipleMoneyRequests f…
pasyukevich b8f0ffc
Merge branch 'main' into feauture/bulk-edit-expenses-3
pasyukevich 91955b5
fix typecheck
pasyukevich f7b7b52
Remove Onyx connection that can be skipped
pasyukevich f2feaa3
Fix tax amount calculation to use effective transaction amount in upd…
pasyukevich 7c91567
Refactor updateMultipleMoneyRequests to improve optimistic violation …
pasyukevich 15755d5
Enhance updateMultipleMoneyRequests to handle unreported expenses by …
pasyukevich bcedd5a
Fix system message dismisses after dismissing the error
pasyukevich 3d02e0f
Merge branch 'main' into feauture/bulk-edit-expenses-3
pasyukevich b6a42e4
fix infinite loading and missing MoneyRequestView with buildOptimisti…
LukasMod 148a503
Merge pull request #42 from callstack-internal/feauture/bulk-edit-exp…
LukasMod 171e289
Merge branch 'main' of github.com:callstack-internal/Expensify-App in…
LukasMod 2a29f58
Use allPolicyTags from onyx hook instead Onyx.connect
LukasMod e5e37c5
pass allPolicyCategories
LukasMod 4e667a4
add validation unit test for unreported expenses
LukasMod a84855d
fix issue with bulk edit split and unreported expenses
LukasMod 7c1d8e5
Merge snapshot data to fix missing data after hard refresh
LukasMod a8d0fa7
fix test 11 and 16 after hard refresh scenario
LukasMod 23f617b
Merge branch 'main' of github.com:callstack-internal/Expensify-App in…
LukasMod 0c6aadc
Merge branch 'main' of github.com:callstack-internal/Expensify-App in…
LukasMod aa0b93a
fix import
LukasMod b31a98c
Merge branch 'main' of github.com:callstack-internal/Expensify-App in…
LukasMod cc436ba
resolve ts issues after merging main
LukasMod b861e46
fix ts issue
LukasMod cd8e631
Merge branch 'main' of github.com:callstack-internal/Expensify-App in…
LukasMod 4680b7a
Merge branch 'main' of github.com:callstack-internal/Expensify-App in…
LukasMod 668686c
Use transactionPolicy instead of shared bulk-edit policy
LukasMod 5f8e120
fix: use per-transaction policy instead of shared bulk-edit policy in…
LukasMod bfa7971
fix: add backfilledCreatedActionID to resolve issue with multiple CRE…
LukasMod be005b2
fix: use snapshot data context with mergedReports
LukasMod 734d78d
fix: use snapshot-merged reports in bulk-edit pickers and extract use…
LukasMod b1ebe1b
fix useOnyx import
LukasMod 8645978
Merge branch 'main' of github.com:callstack-internal/Expensify-App in…
LukasMod File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -37,6 +37,7 @@ import Navigation from '@libs/Navigation/Navigation'; | |
| import {getConnectedIntegration} from '@libs/PolicyUtils'; | ||
| import {getSecondaryExportReportActions, isMergeActionForSelectedTransactions} from '@libs/ReportSecondaryActionUtils'; | ||
| import { | ||
| canEditMultipleTransactions, | ||
| getIntegrationIcon, | ||
| getReportOrDraftReport, | ||
| isBusinessInvoiceRoom, | ||
|
|
@@ -49,7 +50,7 @@ import {navigateToSearchRHP, shouldShowDeleteOption} from '@libs/SearchUIUtils'; | |
| import {shouldRestrictUserBillableActions} from '@libs/SubscriptionUtils'; | ||
| import {hasTransactionBeenRejected, isDeletedTransaction} from '@libs/TransactionUtils'; | ||
| import variables from '@styles/variables'; | ||
| import {canIOUBePaid, dismissRejectUseExplanation} from '@userActions/IOU'; | ||
| import {canIOUBePaid, dismissRejectUseExplanation, initBulkEditDraftTransaction} from '@userActions/IOU'; | ||
| import CONST from '@src/CONST'; | ||
| import ONYXKEYS from '@src/ONYXKEYS'; | ||
| import ROUTES from '@src/ROUTES'; | ||
|
|
@@ -63,6 +64,7 @@ import {useMemoizedLazyExpensifyIcons} from './useLazyAsset'; | |
| import useLocalize from './useLocalize'; | ||
| import useNetwork from './useNetwork'; | ||
| import useOnyx from './useOnyx'; | ||
| import usePermissions from './usePermissions'; | ||
| import usePersonalPolicy from './usePersonalPolicy'; | ||
| import useSelfDMReport from './useSelfDMReport'; | ||
| import useTheme from './useTheme'; | ||
|
|
@@ -98,6 +100,7 @@ function useSearchBulkActions({queryJSON}: UseSearchBulkActionsParams) { | |
| const {accountID} = currentUserPersonalDetails; | ||
| const allTransactions = useAllTransactions(); | ||
| const [allReports] = useOnyx(ONYXKEYS.COLLECTION.REPORT); | ||
| const [allReportActions] = useOnyx(ONYXKEYS.COLLECTION.REPORT_ACTIONS); | ||
| const [allReportNameValuePairs] = useOnyx(ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS); | ||
| const selfDMReport = useSelfDMReport(); | ||
| const [lastPaymentMethods] = useOnyx(ONYXKEYS.NVP_LAST_PAYMENT_METHOD); | ||
|
|
@@ -110,6 +113,7 @@ function useSearchBulkActions({queryJSON}: UseSearchBulkActionsParams) { | |
| const [allTransactionViolations] = useOnyx(ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS); | ||
| const personalPolicy = usePersonalPolicy(); | ||
| const [userBillingGraceEndPeriods] = useOnyx(ONYXKEYS.COLLECTION.SHARED_NVP_PRIVATE_USER_BILLING_GRACE_PERIOD_END); | ||
| const {isBetaEnabled} = usePermissions(); | ||
| const [ownerBillingGraceEndPeriod] = useOnyx(ONYXKEYS.NVP_PRIVATE_OWNER_BILLING_GRACE_PERIOD_END); | ||
| const undeleteTransactions = useUndeleteTransactions(); | ||
|
|
||
|
|
@@ -671,7 +675,9 @@ function useSearchBulkActions({queryJSON}: UseSearchBulkActionsParams) { | |
| ); | ||
|
|
||
| const onBulkPaySelectedRef = useRef(onBulkPaySelected); | ||
| onBulkPaySelectedRef.current = onBulkPaySelected; | ||
| useEffect(() => { | ||
| onBulkPaySelectedRef.current = onBulkPaySelected; | ||
| }); | ||
| const stableOnBulkPaySelected = useCallback((paymentMethod?: PaymentMethodType, additionalData?: BulkPaySelectionData) => { | ||
| onBulkPaySelectedRef.current?.(paymentMethod, additionalData); | ||
| }, []); | ||
|
|
@@ -886,6 +892,30 @@ function useSearchBulkActions({queryJSON}: UseSearchBulkActionsParams) { | |
| return [exportButtonOption]; | ||
| } | ||
|
|
||
| const isExpenseReportSearch = typeExpenseReport || searchResults?.search.type === CONST.SEARCH.DATA_TYPES.EXPENSE_REPORT; | ||
| const selectedTransactionsList = Object.values(selectedTransactions) | ||
| .map((transaction) => transaction.transaction) | ||
| .filter((transaction): transaction is Transaction => !!transaction); | ||
| const canEditMultiple = | ||
| canEditMultipleTransactions(selectedTransactionsList, allReportActions, allReports, policies, isExpenseReportSearch, searchResults?.data) && isBetaEnabled(CONST.BETAS.BULK_EDIT); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. NAB, probably could check for the beta first since that will be much faster but doubt it matters. |
||
|
|
||
| if (canEditMultiple) { | ||
| options.push({ | ||
| icon: expensifyIcons.Pencil, | ||
| text: translate('search.bulkActions.editMultiple'), | ||
| value: CONST.SEARCH.BULK_ACTION_TYPES.EDIT, | ||
| shouldCloseModalOnSelect: true, | ||
| onSelected: () => { | ||
| const selectedTransactionIDs = Object.keys(selectedTransactions).filter((transactionID) => { | ||
| const selectedTransaction = selectedTransactions[transactionID]; | ||
| return !!selectedTransaction?.transaction?.transactionID || !!allTransactions?.[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`]; | ||
| }); | ||
| initBulkEditDraftTransaction(selectedTransactionIDs); | ||
| Navigation.navigate(ROUTES.SEARCH_EDIT_MULTIPLE_TRANSACTIONS_RHP); | ||
| }, | ||
| }); | ||
| } | ||
|
|
||
| const areSelectedTransactionsIncludedInReports = selectedTransactionsKeys.every((id) => | ||
| selectedTransactions[id].reportID ? selectedReportIDs.includes(selectedTransactions[id].reportID) : true, | ||
| ); | ||
|
|
@@ -1190,6 +1220,7 @@ function useSearchBulkActions({queryJSON}: UseSearchBulkActionsParams) { | |
| expensifyIcons.ArrowCollapse, | ||
| expensifyIcons.DocumentMerge, | ||
| expensifyIcons.ArrowSplit, | ||
| expensifyIcons.Pencil, | ||
| expensifyIcons.Trashcan, | ||
| expensifyIcons.RotateLeft, | ||
| expensifyIcons.Exclamation, | ||
|
|
@@ -1205,6 +1236,7 @@ function useSearchBulkActions({queryJSON}: UseSearchBulkActionsParams) { | |
| selectedTransactionReportIDs, | ||
| selectedPolicyIDs, | ||
| policies, | ||
| allReportActions, | ||
| integrationsExportTemplates, | ||
| csvExportLayouts, | ||
| allReports, | ||
|
|
@@ -1242,6 +1274,9 @@ function useSearchBulkActions({queryJSON}: UseSearchBulkActionsParams) { | |
| userBillingGraceEndPeriods, | ||
| ownerBillingGraceEndPeriod, | ||
| currentSearchKey, | ||
| allTransactions, | ||
| isBetaEnabled, | ||
| shouldShowBusinessBankAccountOptions, | ||
| ]); | ||
|
|
||
| const handleOfflineModalClose = useCallback(() => { | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| import {useSearchStateContext} from '@components/Search/SearchContext'; | ||
| import {getSearchBulkEditPolicyID} from '@libs/SearchUIUtils'; | ||
| import {withSnapshotReports, withSnapshotTransactions} from '@pages/Search/SearchEditMultiple/SearchEditMultipleUtils'; | ||
| import CONST from '@src/CONST'; | ||
| import ONYXKEYS from '@src/ONYXKEYS'; | ||
| import useOnyx from './useOnyx'; | ||
|
|
||
| /** | ||
| * Resolves the bulk-edit policyID from the selected transactions, using | ||
| * snapshot-merged collections so that expenses only present in the search | ||
| * snapshot (e.g. after a hard refresh) are still resolved correctly. | ||
| */ | ||
| function useSearchBulkEditPolicyID(): string | undefined { | ||
| const {currentSearchResults} = useSearchStateContext(); | ||
| const [activePolicyID] = useOnyx(ONYXKEYS.NVP_ACTIVE_POLICY_ID); | ||
| const [draftTransaction] = useOnyx(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${CONST.IOU.OPTIMISTIC_BULK_EDIT_TRANSACTION_ID}`); | ||
| const [allTransactions] = useOnyx(ONYXKEYS.COLLECTION.TRANSACTION); | ||
| const [allReports] = useOnyx(ONYXKEYS.COLLECTION.REPORT); | ||
|
|
||
| const snapshotData = currentSearchResults?.data; | ||
| const mergedTransactions = withSnapshotTransactions(allTransactions, snapshotData); | ||
| const mergedReports = withSnapshotReports(allReports, snapshotData); | ||
|
|
||
| const selectedTransactionIDs = draftTransaction?.selectedTransactionIDs ?? []; | ||
|
|
||
| return getSearchBulkEditPolicyID(selectedTransactionIDs, activePolicyID, mergedTransactions, mergedReports); | ||
| } | ||
|
|
||
| export default useSearchBulkEditPolicyID; |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
❌ PERF-11 (docs)
useOnyx(ONYXKEYS.COLLECTION.REPORT_ACTIONS)subscribes to the entire report actions collection — one of the largest and most frequently updated collections in Onyx (every new chat message, reaction, or action update triggers a re-render). This hook is active on the search screen and will cause excessive re-renders.The data is only needed to pass into
canEditMultipleTransactions()for the selected transactions' reports. Consider either:canEditMultipleTransactionscheck into theonSelectedhandler where data can be read imperatively viaOnyx.getValue()rather than maintaining a live subscription.REPORT_ACTIONSkeys needed based on the selected transactions' report IDs.Please rate this suggestion with 👍 or 👎 to help us improve! Reactions are used to monitor reviewer efficiency.