Re-add Rotate and Crop buttons for stitched odometer receipt images - #98540
Conversation
Co-authored-by: DylanDylann <DylanDylann@users.noreply.github.com>
Codecov Report✅ Changes either increased or maintained existing code coverage, great job!
|
|
All the actual CI checks (typecheck, tests, ESLint, Oxfmt, perf tests, etc.) are now passing — there's nothing broken in the code to fix. When you triggered this, The only two remaining red checks are process gates that I can't resolve with a code push:
Both are on the "don't auto-fix" list, so no fix was pushed. Once the checklist/test steps are filled in and the PR gets its independent approval, these will clear. |
|
@MelvinBot Mark PR ready |
|
@DylanDylann 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] |
|
Done — I've marked this PR as ready for review. ✅ One heads-up before reviewers dig in: the PR body still has the |
Reviewer Checklist
Screenshots/VideosAndroid: HybridAppScreen.Recording.2026-08-13.at.13.35.00.movAndroid: mWeb ChromeScreen.Recording.2026-08-13.at.13.30.23.moviOS: HybridAppScreen.Recording.2026-08-13.at.13.32.44.moviOS: mWeb SafariScreen.Recording.2026-08-13.at.13.26.30.movMacOS: Chrome / SafariScreen.Recording.2026-08-13.at.13.22.43.mov |
|
🤖 Marked this PR as ready for review. Verification: I ran the fix through the web tester but couldn't produce a stitched odometer receipt end-to-end — both the odometer photo step and a normal receipt scan require a native file upload ( I verified the fix at the code level instead. In
Tester evidence (as far as the web driver reached)Full stitched-odometer verification was blocked by the native file-upload requirement; screenshots show the flow up to that point. |
|
No change since my previous comment — all real CI checks pass. The only two red checks are still process gates that a code push can't fix:
Both are on the do-not-auto-fix list, so there's nothing for me to push here. |
|
@Julesssss I can't edit the author checklist. Could you help to fill it out? |
garrettmknight
left a comment
There was a problem hiding this comment.
Looks good from a product perspective.
|
✋ This PR was not deployed to staging yet because QA is ongoing. It will be automatically deployed to staging after the next production release. |
Android test results —
|
| # | Step | Result |
|---|---|---|
| 1 | Create distance expense with stitched odometer receipt | ✅ Pass |
| 2 | Open the odometer receipt attachment | ✅ Pass |
| 3 | Rotate & Crop visible and functional on odometer receipt | |
| 4 | Replace button stays hidden for odometer receipt | ✅ Pass (hidden in both contexts) |
| 5 | Normal receipt still shows Rotate, Crop, Replace (no regression) | ✅ Pass |
| 6 | No console errors | ⚪ Not verified (log stream wasn't active for the session) |
Evidence
Pre-creation (Confirm details) — matches PR intent: Rotate + Crop shown, Replace hidden, both functional.
Post-creation (open the created expense → view receipt) — no buttons at all (the gap):
Normal (non-odometer) receipt post-creation — all three buttons present, no regression:
Why the buttons are hidden post-creation (root cause)
In TransactionReceiptModalContent.tsx:362-371, shouldShowRotateAndCropReceiptButton now gates on canEditReceiptButtons, which depends on canEditReceipt = canEditFieldOfMoneyRequest({fieldToEdit: RECEIPT, ...}).
That shared permission check at ReportUtils.ts:5336-5345 excludes all non-manual distance requests:
(!isDistanceRequest(transaction) || isManualDistanceRequestTransactionUtils(transaction)) &&Odometer transactions are distance requests and not manual, so this returns false for them. canEditReceiptButtons then falls back to isDraftTransaction (the action route param), which is only truthy on the pre-creation confirmation route. Once the expense exists and the receipt opens via ROUTES.TRANSACTION_RECEIPT without an action param (the everyday view path), canEditReceiptButtons is false, hiding Rotate/Crop as well as Replace.
So to fully meet the PR's goal, the odometer case likely also needs to be allowed through the RECEIPT-field check in canEditFieldOfMoneyRequest (or canEditReceiptButtons needs an odometer-specific path that doesn't depend on it).
Note: step 6 (console errors) couldn't be verified — the log stream wasn't active for this session, so nothing was captured either way.
|
🚀 Deployed to staging by https://github.com/Julesssss in version: 9.4.54-0 🚀
|
|
🤖 Help site review: no changes required. This PR is a narrow UI bug fix — it restores the Rotate and Crop buttons for stitched odometer receipt images that were unintentionally suppressed by the Articles I checked in
|










Explanation of Change
The
RotateandCropbuttons were hidden for stitched odometer receipt images becauseshouldShowRotateAndCropReceiptButtonwas derived fromshouldShowReplaceReceiptButton, which carries the!isStitchedOdometerReceiptexclusion. That exclusion was only meant to hide the "replace image" button for stitched odometer receipts, but it unintentionally suppressed rotate/crop too.This PR extracts the shared editability precondition into
canEditReceiptButtonsand applies!isStitchedOdometerReceiptonly to the replace button.shouldShowRotateAndCropReceiptButtonnow depends oncanEditReceiptButtonsinstead, so rotate/crop is restored for stitched odometer receipts while the replace button stays hidden as intended. Its existing guards (hasReceiptSource/hasOdometerImageSource,!isEReceipt,isImage,!isTestDriveReceipt) are unchanged.Fixed Issues
$ #98513
PROPOSAL: #98513 (comment)
Tests
// TODO: The human co-author must fill out the tests you ran before marking this PR as "ready for review".
Suggested steps to validate the fix:
RotateandCropbuttons are visible and functional.Rotate,Crop, and the replace button (no regression).Offline tests
QA Steps
// TODO: These must be filled out, or the issue title must include "[No QA]."
// The human co-author must fill out the QA steps before marking this PR as "ready for review". "Same as tests" is acceptable if QA can run the steps in the Tests section.
PR Author Checklist
### Fixed Issuessection aboveTestssectionOffline stepssectionQA stepssectionAvatar, 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.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