Allow rejecting expenses in bulk in NewDot#72855
Conversation
🦜 Polyglot Parrot! 🦜Squawk! Looks like you added some shiny new English strings. Allow me to parrot them back to you in other tongues: View the translation diffdiff --git a/src/languages/fr.ts b/src/languages/fr.ts
index 4af77e7b..806794bb 100644
--- a/src/languages/fr.ts
+++ b/src/languages/fr.ts
@@ -6221,7 +6221,7 @@ ${amount} pour ${merchant} - ${date}`,
delete: 'Supprimer',
hold: 'Attente',
unhold: 'Supprimer la suspension',
- reject: 'Rejeter',
+ reject: 'Refuser',
noOptionsAvailable: 'Aucune option disponible pour le groupe de dépenses sélectionné.',
},
filtersHeader: 'Filtres',
diff --git a/src/languages/zh-hans.ts b/src/languages/zh-hans.ts
index caac87fd..0ac72c15 100644
--- a/src/languages/zh-hans.ts
+++ b/src/languages/zh-hans.ts
@@ -6077,15 +6077,7 @@ ${merchant}的${amount} - ${date}`,
searchName: '搜索名称',
savedSearchesMenuItemTitle: '已保存',
groupedExpenses: '分组费用',
- bulkActions: {
- approve: '批准',
- pay: '支付',
- delete: '删除',
- hold: '保持',
- unhold: '移除保留',
- reject: '拒绝',
- noOptionsAvailable: '所选费用组没有可用选项。',
- },
+ bulkActions: {approve: '批准', pay: '支付', delete: '删除', hold: '保持', unhold: '移除保留', reject: '拒绝', noOptionsAvailable: '所选费用组没有可用选项。'},
filtersHeader: '筛选器',
filters: {
date: {
Note You can apply these changes to your branch by copying the patch to your clipboard, then running |
|
@ikevin127 Please copy/paste the Reviewer Checklist from here into a new comment on this PR and complete it. If you have the K2 extension, you can simply click: [this button] |
|
|
||
| const validate = useCallback( | ||
| (values: FormOnyxValues<typeof ONYXKEYS.FORMS.MONEY_REQUEST_REJECT_FORM>) => { | ||
| const errors: FormInputErrors<typeof ONYXKEYS.FORMS.MONEY_REQUEST_REJECT_FORM> = getFieldRequiredErrors(values, [INPUT_IDS.COMMENT]); |
There was a problem hiding this comment.
❌ Redundant validation logic
The validation logic here is redundant. Line 36 calls getFieldRequiredErrors(values, [INPUT_IDS.COMMENT]) and then line 38 manually checks if (!values.comment) for the same field.
Fix: Remove the redundant manual check on line 38-40 since getFieldRequiredErrors already handles this:
const validate = useCallback(
(values: FormOnyxValues<typeof ONYXKEYS.FORMS.MONEY_REQUEST_REJECT_FORM>) => {
const errors: FormInputErrors<typeof ONYXKEYS.FORMS.MONEY_REQUEST_REJECT_FORM> = getFieldRequiredErrors(values, [INPUT_IDS.COMMENT]);
return errors;
},
[translate],
);There was a problem hiding this comment.
This makes sense. Let's remove the manual check below
|
|
||
| const validate = useCallback( | ||
| (values: FormOnyxValues<typeof ONYXKEYS.FORMS.MONEY_REQUEST_REJECT_FORM>) => { | ||
| const errors: FormInputErrors<typeof ONYXKEYS.FORMS.MONEY_REQUEST_REJECT_FORM> = getFieldRequiredErrors(values, [INPUT_IDS.COMMENT]); |
There was a problem hiding this comment.
This makes sense. Let's remove the manual check below
|
|
||
| /** Link to previous page */ | ||
| backTo: Route; | ||
| backTo?: Route; |
There was a problem hiding this comment.
This one is a pre-existing file. The deprecated aspect of the backTo parameter can be handled in a follow up by the person in charge of the FE implementation of the Reject in NewDot project. cc @mananjadhav @truph01
There was a problem hiding this comment.
I'll take care of it.
| const errors: FormInputErrors<typeof ONYXKEYS.FORMS.MONEY_REQUEST_REJECT_FORM> = getFieldRequiredErrors(values, [INPUT_IDS.COMMENT]); | ||
| return errors; | ||
| }, | ||
| [translate], |
There was a problem hiding this comment.
❌ PERF-6 (docs)
In useCallback, specify individual object properties as dependencies instead of passing the entire context object.
const onSubmit = useCallback(
({comment}: FormOnyxValues<typeof ONYXKEYS.FORMS.MONEY_REQUEST_REJECT_FORM>) => {
rejectMoneyRequestsOnSearch(context.currentSearchHash, context.selectedTransactions, comment);
context.clearSelectedTransactions();
Navigation.goBack();
},
[context.currentSearchHash, context.selectedTransactions, context.clearSelectedTransactions],
);| }); | ||
|
|
||
| Object.entries(transactionsByReport).forEach(([reportID, reportTransactionIDs]) => { | ||
| // Share a single destination ID across all rejections from the same source report |
There was a problem hiding this comment.
❌ JSDoc Comments (docs)
Missing JSDoc documentation for the rejectMoneyRequestsOnSearch function. All functions should have proper JSDoc comments explaining their purpose, parameters, and return values.
/**
* Reject multiple money requests from search results in bulk
* @param hash - The search query hash
* @param selectedTransactions - Map of selected transactions with their metadata
* @param comment - The rejection reason comment
*/
function rejectMoneyRequestsOnSearch(hash: number, selectedTransactions: SelectedTransactions, comment: string) {| import ONYXKEYS from '@src/ONYXKEYS'; | ||
| import INPUT_IDS from '@src/types/form/MoneyRequestRejectReasonForm'; | ||
|
|
||
| function SearchRejectReasonPage() { |
There was a problem hiding this comment.
❌ JSDoc Comments (docs)
Missing JSDoc documentation for the SearchRejectReasonPage component. Component functions should have proper JSDoc comments explaining their purpose.
/**
* Page for entering a rejection reason when bulk rejecting expenses from search results
*/
function SearchRejectReasonPage() {|
@situchan @luacmartins @stitesExpensify ready for a re-review, tests pass. |
|
🚀 Deployed to staging by https://github.com/luacmartins in version: 9.2.41-0 🚀
|
|
🚀 Deployed to production by https://github.com/puneetlath in version: 9.2.41-6 🚀
|
Explanation of Change
Allow rejecting expenses in bulk in NewDot
Fixed Issues
$ https://github.com/Expensify/Expensify/issues/557590
PROPOSAL:
Tests
Screen.Recording.2025-10-17.at.11.08.08.mov
Prerequisites:
Reportspage as the workspace owner, bulk select the two expensesRejectOffline tests
NA, it's the reports page
QA Steps
Same as in tests
PR Author Checklist
### Fixed Issuessection aboveTestssectionOffline stepssectionQA stepssectiontoggleReportand notonIconClick)src/languages/*files and using the translation methodSTYLE.md) were followedAvatar, I verified the components usingAvatarare working as expected)StyleUtils.getBackgroundAndBorderStyle(theme.componentBG))Avataris modified, I verified thatAvataris working as expected in all cases)Designlabel and/or tagged@Expensify/designso the design team can review the changes.ScrollViewcomponent to make it scrollable when more elements are added to the page.mainbranch was merged into this PR after a review, I tested again and verified the outcome was still expected according to theTeststeps./** comment above it */thisproperly so there are no scoping issues (i.e. foronClick={this.submit}the methodthis.submitshould be bound tothisin the constructor)thisare necessary to be bound (i.e. avoidthis.submit = this.submit.bind(this);ifthis.submitis never passed to a component event handler likeonClick)Screenshots/Videos
Android: Native
Android: mWeb Chrome
iOS: Native
iOS: mWeb Safari
MacOS: Chrome / Safari
Screen.Recording.2025-10-17.at.11.08.08.mov
MacOS: Desktop