Fix approve button not shown because of invisible broken card connection violation#74738
Conversation
…provide an email to isViolationDismissed
Codecov Report❌ Looks like you've decreased code coverage for some files. Please write tests to increase, or at least maintain, the existing level of code coverage. See our documentation here for how to interpret this table.
|
src/libs/TransactionUtils/index.ts
Outdated
| return !!transaction?.comment?.dismissedViolations?.[violation.name]; | ||
| } | ||
|
|
||
| return !!transaction?.comment?.dismissedViolations?.[violation.name]?.[currentUserEmail ?? deprecatedCurrentUserEmail]; |
There was a problem hiding this comment.
the deprecatedCurrentUserEmail is not needed now?
lets add / update tests for this method
There was a problem hiding this comment.
the deprecatedCurrentUserEmail is not needed now?
It was added in #72940. Based on this comment, @DylanDylann might be working on a PR to remove it. @DylanDylann, can you please confirm?
There was a problem hiding this comment.
Yeah but if currentUserEmail is falsey we will never get there so we could remove it from this line now, right?
There was a problem hiding this comment.
I agree, I've removed it 👍
There was a problem hiding this comment.
currentUserEmail could still be undefined, so let's keep deprecatedCurrentUserEmail as a fallback for now. I'm still working on completely removing deprecatedCurrentUserEmail.
|
@Krishna2323 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] |
…se for duplicatedExpense violation, if the submitter dismisses it, the approver should still see it, and vice versa
I checked all App/src/libs/TransactionUtils/index.ts Line 1320 in 5dc4f0c I've pushed a commit to handle this case: 4871b1f In all the following App/src/hooks/useTransactionViolations.ts Line 29 in 5dc4f0c Line 920 in 5dc4f0c App/src/libs/TransactionUtils/index.ts Line 1081 in 5dc4f0c In the following usages, we don't pass the email parameter, which is intentional because we want to check if the violation has been dismissed by any user: App/src/libs/TransactionUtils/index.ts Line 1369 in 5dc4f0c App/src/libs/TransactionUtils/index.ts Line 1397 in 5dc4f0c App/src/libs/TransactionUtils/index.ts Line 1418 in 5dc4f0c
To clarify, App/src/libs/ReportPreviewActionUtils.ts Line 85 in 5dc4f0c
The logic in this PR aligns with this comment in Auth:
You can also see a log here showing that the approver did receive the dismissed violation data: https://logs.expensify.com/goto/f57262f0-bf3d-11f0-aa21-6b7684ca60b0 |
|
@Krishna2323 Can you re-review the PR and test it to make sure it works well? |
|
I will start reviewing this in an hour. |
|
Reviewing... |
|
@rayane-d one report preview shows a “Review” button when there’s a violation in the preview, but on the expense details page I don’t see any violation. Another report preview shows a “View” button even though the expense has a violation. Are both of these expected? Monosnap.screencast.2025-11-21.01-51-41.mp4 |
|
@Krishna2323 - This is because the Onyx exported state contains masked data - specifically, the |
|
Hmm 🤔, I'm pretty sure that I executed snippets in the console. Will try again, maybe I did something wrong. |
…enCardConnection-violation
Reviewer Checklist
Screenshots/VideosAndroid: HybridAppandroid_native.mp4Android: mWeb Chromeandroid_chrome.mp4iOS: HybridAppios_native.mp4iOS: mWeb SafariMacOS: Chrome / Safariweb_chrome.mp4MacOS: Desktopdesktop_app.mp4 |
There was a problem hiding this comment.
Everything looks good and works well. I wasn’t able to test on mWeb Safari, but I don’t think that’s a blocker.
@rayane-d could you please fix the ESLint check? Thanks!
…enCardConnection-violation
Fixed |
|
@cead22 All yours! |
| import type {Attendee, Participant, SplitExpense} from '@src/types/onyx/IOU'; | ||
| import type {Errors, PendingAction} from '@src/types/onyx/OnyxCommon'; | ||
| import type {OnyxData} from '@src/types/onyx/Request'; | ||
| // eslint-disable-next-line @typescript-eslint/no-deprecated |
There was a problem hiding this comment.
| // eslint-disable-next-line @typescript-eslint/no-deprecated | |
| // eslint-disable-next-line @typescript-eslint/no-deprecated |
| // Further filter to only violations visible to the current user | ||
| shouldShowViolation(report, policy, violation.name, currentUserEmail), | ||
| ); | ||
| // Check if there is pending rter violation in the filtered violations |
There was a problem hiding this comment.
| // Check if there is pending rter violation in the filtered violations | |
| // Check if there is pending rter violation in the filtered violations |
| currentUserEmail: string, | ||
| iouReport: OnyxEntry<Report>, | ||
| policy: OnyxEntry<Policy>, | ||
| // eslint-disable-next-line @typescript-eslint/no-deprecated |
There was a problem hiding this comment.
| // eslint-disable-next-line @typescript-eslint/no-deprecated | |
| // eslint-disable-next-line @typescript-eslint/no-deprecated |
| const hasFieldErrors = hasMissingSmartscanFields(transaction); | ||
| const isPaidGroupPolicy = isPaidGroupPolicyUtil(iouReport); | ||
| const hasViolationsOfTypeNotice = hasNoticeTypeViolation(transaction, violations, true) && isPaidGroupPolicy; | ||
| const currentUserEmail = getCurrentUserEmail(); |
There was a problem hiding this comment.
Don't use getCurrentUserEmail function anymore please, please pass data from UI. I will fix in here
| return false; | ||
| } | ||
|
|
||
| const currentUserAccountID = deprecatedCurrentUserAccountID; |
There was a problem hiding this comment.
@rayane-d why are we still using deprecatedCurrentUserAccountID here even though it’s marked as deprecated?
There was a problem hiding this comment.
@rayane-d @Krishna2323 Could you please create a PR to remove the usage of deprecatedCurrentUserAccountID?
There was a problem hiding this comment.
Sorry about that, @DylanDylann — I got confused between deprecatedCurrentUserAccountID and deprecatedCurrentUserEmail. #74738 (comment)
@rayane-d are you available to raise the PR, or should I?
There was a problem hiding this comment.
When a variable is marked as deprecated like deprecatedCurrentUserAccountID and deprecatedCurrentUserEmail, please don't introduce new usage of it anymore BUT if it already been used before and you only update that logic, It's fine to keep it.
There was a problem hiding this comment.
Also, please avoid using functions like getCurrentUserEmail that rely on Onyx.connect. Onyx.connect is deprecated and needs to be fully removed from our app. This means functions like getCurrentUserEmail will also be removed, so please don’t use them in new code.
There was a problem hiding this comment.
@rayane-d @Krishna2323 Could you please create a PR to remove the usage of deprecatedCurrentUserAccountID?
Working on a PR 👍
|
@rayane-d can you please share QA steps? |
|
🚀 Deployed to staging by https://github.com/cead22 in version: 9.2.64-0 🚀
|
|
@IuliiaHerets the QA steps should be the same as the tests section. Sorry for missing that. cc: @rayane-d |
|
@Krishna2323 We don’t have access to the link from Step 1. Pasting the code into the console doesn’t generate a report as described in Step 3. It seems the steps are still incorrect bandicam.2025-11-26.22-14-04-470.mp4 |
@IuliiaHerets I've DMed you the file in Slack 👍 |
|
🚀 Deployed to production by https://github.com/marcaaron in version: 9.2.64-5 🚀
|


Explanation of Change
Problem
When a submitter dismisses an RTER (broken card connection) violation on an expense report, the "Approve" button on the report preview doesn't appear for the approver, even though the approver should not see this violation at all.
Root Cause
The issue has two parts:
TransactionUtils.shouldShowViolation()correctly hides RTER violations from approvers (non-submitters) on non-instant-submit policies:App/src/libs/TransactionUtils/index.ts
Lines 1225 to 1228 in d82a640
This means approvers should never see RTER violations on non instant-submit policies.
ReportPreviewActionUtils.canApprove()was checkingReportUtils.hasAnyViolations()which:App/src/libs/ReportPreviewActionUtils.ts
Line 66 in d82a640
So the issue is that we were checking if violations exist, but not checking if those violations are visible to the current user.
Solution
This PR ensures that "Approve" action availability logic in
ReportPreviewActionUtils.canApprove()only considers violations visible to the current user by properly integrating the dismissal and visibility logic.1. Enhanced
isViolationDismissed()to support all Auth dismissal rulesThe function now implements the same three conditions as the Auth backend:
https://github.com/Expensify/Auth/blob/6005bc71c5ee81f4e89f9a70535d853b19eb57a5/auth/lib/Violations.cpp#L430-L451
The violation is considered dismissed if:
2. Fixed "Approve" action availability logic in
ReportPreviewActionUtils.canApprove()to respect violation visibilityUpdated to use
hasVisibleViolationsForUser()which checks both:isViolationDismissed)shouldShowViolation)For the reported bug:
shouldShowViolation()returnsfalsebecause:hasVisibleViolationsForUser()returnsfalse(no visible violations)Before:
After:
3. Fixed empty "Next Step" message for dismissed violations
Problem:
When all violations were dismissed, the header tried to display a status message but
useTransactionViolationsfiltered them out, resulting in an empty status bar.Fix:
Added check to ensure violations exist before showing status:
Before:
After:
4. Fixed "Mark as cash" primary action button on the report header instead of "Approve" button
Problem:
isMarkAsCashActionwas usingallHavePendingRTERViolationandshouldShowBrokenConnectionViolationForMultipleTransactionsto display the "Mark as cash" button when it returnstrue.allHavePendingRTERViolationandshouldShowBrokenConnectionViolationForMultipleTransactionswas considering all non-dismissed violations, it:App/src/libs/ReportPrimaryActionUtils.ts
Line 279 in d82a640
App/src/libs/TransactionUtils/index.ts
Lines 1236 to 1250 in d82a640
App/src/libs/ReportPrimaryActionUtils.ts
Line 289 in d82a640
App/src/libs/TransactionUtils/index.ts
Lines 1163 to 1179 in d82a640
Fix:
Updated
allHavePendingRTERViolation()andshouldShowBrokenConnectionViolationForMultipleTransactionsto check for both:isViolationDismissed)shouldShowViolation)Before:
After:
Fixed Issues
$ #73098
PROPOSAL:
Tests
commentdata to the transaction and to correct the violation name:#96832091)#1814181775632892)Offline tests
N/A
QA Steps
// TODO: These must be filled out, or the issue title must include "[No QA]."
Same as tests
PR Author Checklist
### Fixed Issuessection aboveTestssectionOffline stepssectionQA stepssectioncanBeMissingparam foruseOnyxtoggleReportand notonIconClick)src/languages/*files and using the translation methodSTYLE.md) were followedAvatar, I verified the components usingAvatarare working as expected)StyleUtils.getBackgroundAndBorderStyle(theme.componentBG))npm run compress-svg)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.Screenshots/Videos
Android: Native
Android: mWeb Chrome
iOS: Native
iOS: mWeb Safari
MacOS: Chrome / Safari
MacOS: Desktop