Part of the Bulk Edit expenses in NewDot project
Tracking issue: https://github.com/Expensify/Expensify/issues/541817
Doc section: https://docs.google.com/document/d/1IMn36LsoyA0xG0-_eLNrFvCYeddiumuoLGCefrdm1qU/
Project: Migrate
Summary
- Extend existing selection and editing to support bulk editing of multiple editable expenses.
- Reuse
SearchContext for multi-select, add a new “Edit multiple expenses” action, and implement a new edit page with optimistic updates and system messages per expense.
Objectives
- Support multi-selection of editable expenses.
- Add a multi-transaction permission helper.
- Add “Edit multiple expenses” menu item and navigation.
- Build
SearchEditMultiplePage (empty initial values, policy-aware).
- Implement optimistic updates and per-expense system messages using
UpdateMoneyRequest.
Implementation Steps
Bulk Edit Permission Check
- Add
canEditMultipleTransactions(selectedTransactions) in ReportUtils.ts.
- Behavior:
- Ensure at least 2 expenses are selected.
- For each selected transaction:
- Obtain its report action via
getIOUActionForTransactionID.
- Call
canEditFieldOfMoneyRequest for key fields (amount, merchant, category, tag, comment, taxCode, created, currency, state).
- If any transaction exposes at least one editable field, return
true to enable “Edit multiple”.
- Non-editable fields (due to transaction/report state) still render with a right caret; updates for those fields are ignored for those specific expenses when the command runs (parity with Classic).
- Add unit tests for both
canEditMultipleTransactions() and canEditFieldOfMoneyRequest().
Add “Edit Multiple” Option to Bulk Actions Menu
- The green “Selected” button is rendered by
ButtonWithDropdownMenu.
- Narrow screens:
SearchSelectedNarrow.
- Wide screens:
SearchFiltersBar.
- Extend
useSelectedTransactionsActions and SearchPage header buttons:
- Add a new option when
selectedTransactionsKeys.length >= 2.
- Option details:
- icon:
Expensicons.Pencil
- text:
translate('search.bulkActions.editMultiple')
- value:
CONST.SEARCH.BULK_ACTION_TYPES.EDIT (add this CONST)
- onSelected: navigate to
SearchEditMultiplePage
- Place this option as the FIRST item.
Build the Edit Multiple Expenses Page
- Create
SearchEditMultiplePage using a layout similar to MoneyRequestView.
- Fields render EMPTY initially (no prefill), matching Classic.
- Use
MenuItemWithTopDescription for each field.
- Determine
policyID:
- If selection originates from a single report context: use
report.policyID.
- If selection spans multiple reports or search: use submitter’s default from
ONYXKEYS.NVP_ACTIVE_POLICY_ID.
- Load policy via
ONYXKEYS.COLLECTION.POLICY[policyID].
- On field edit and save (per-field subpage), stage values for submission.
Save and Optimistic Updates
-
Add a bottom “Save” button (success styling) on SearchEditMultiplePage.
-
On press:
- Loop through selected transactions.
- For each transaction, call
UpdateMoneyRequest with only changed fields in updates.
- Generate
modifiedExpenseReportActionID via NumberUtils.rand().
-
Optimistic Onyx updates per transaction:
- Update
ONYXKEYS.COLLECTION.TRANSACTION[transactionID] with changed fields only.
- Set
pendingFields[field] = CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE for each changed field.
- Provide
successData to clear pendingFields.
- Provide
failureData to revert values and surface errors.
-
UpdateMoneyRequest parameters per request (one transaction per call):
authToken: string
transactionID: string
modifiedExpenseReportActionID: string (optimistic ID)
updates object (only include edited fields):
merchant: string (≤255 chars)
created: string (YYYY-MM-DD)
amount: number (cents; negative for expenses)
currency: string (3-letter code)
state: number (reimbursable/billable enums: 3 or 4)
category: string (name)
tag: string (name)
comment: string (description)
taxCode: string (externalID of tax UDF; only rate is editable in Bulk Edit UI)
6) Optimistic System Messages
- After each successful update, add one system message per updated expense.
- Prepare optimistic report actions so users see immediate feedback:
- type:
CONST.REPORT.ACTIONS.TYPE.MODIFIED_EXPENSE
- actionName:
CONST.REPORT.ACTIONS.TYPE.MODIFIED_EXPENSE
- originalMessage:
OriginalMessageModifiedExpense containing changed fields with old → new values
- Use
buildOptimisticModifiedExpenseReportAction.
- Add these optimistic actions to the corresponding transaction thread reports via
optimisticData.
Part of the Bulk Edit expenses in NewDot project
Tracking issue: https://github.com/Expensify/Expensify/issues/541817
Doc section: https://docs.google.com/document/d/1IMn36LsoyA0xG0-_eLNrFvCYeddiumuoLGCefrdm1qU/
Project: Migrate
Summary
SearchContextfor multi-select, add a new “Edit multiple expenses” action, and implement a new edit page with optimistic updates and system messages per expense.Objectives
SearchEditMultiplePage(empty initial values, policy-aware).UpdateMoneyRequest.Implementation Steps
Bulk Edit Permission Check
canEditMultipleTransactions(selectedTransactions)inReportUtils.ts.getIOUActionForTransactionID.canEditFieldOfMoneyRequestfor key fields (amount, merchant, category, tag, comment, taxCode, created, currency, state).trueto enable “Edit multiple”.canEditMultipleTransactions()andcanEditFieldOfMoneyRequest().Add “Edit Multiple” Option to Bulk Actions Menu
ButtonWithDropdownMenu.SearchSelectedNarrow.SearchFiltersBar.useSelectedTransactionsActionsandSearchPageheader buttons:selectedTransactionsKeys.length >= 2.Expensicons.Penciltranslate('search.bulkActions.editMultiple')CONST.SEARCH.BULK_ACTION_TYPES.EDIT(add this CONST)SearchEditMultiplePageBuild the Edit Multiple Expenses Page
SearchEditMultiplePageusing a layout similar toMoneyRequestView.MenuItemWithTopDescriptionfor each field.policyID:report.policyID.ONYXKEYS.NVP_ACTIVE_POLICY_ID.ONYXKEYS.COLLECTION.POLICY[policyID].Save and Optimistic Updates
Add a bottom “Save” button (success styling) on
SearchEditMultiplePage.On press:
UpdateMoneyRequestwith only changed fields inupdates.modifiedExpenseReportActionIDviaNumberUtils.rand().Optimistic Onyx updates per transaction:
ONYXKEYS.COLLECTION.TRANSACTION[transactionID]with changed fields only.pendingFields[field] = CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATEfor each changed field.successDatato clearpendingFields.failureDatato revert values and surface errors.UpdateMoneyRequestparameters per request (one transaction per call):authToken: stringtransactionID: stringmodifiedExpenseReportActionID: string (optimistic ID)updatesobject (only include edited fields):merchant: string (≤255 chars)created: string (YYYY-MM-DD)amount: number (cents; negative for expenses)currency: string (3-letter code)state: number (reimbursable/billable enums: 3 or 4)category: string (name)tag: string (name)comment: string (description)taxCode: string (externalID of tax UDF; only rate is editable in Bulk Edit UI)6) Optimistic System Messages
CONST.REPORT.ACTIONS.TYPE.MODIFIED_EXPENSECONST.REPORT.ACTIONS.TYPE.MODIFIED_EXPENSEOriginalMessageModifiedExpensecontaining changed fields with old → new valuesbuildOptimisticModifiedExpenseReportAction.optimisticData.