Skip to content

[Due for payment 2026-04-14] Odometer - Removed photo is shown on confirm page when it is removed from Distance page #85368

Closed

Description

@nlemma

If you haven’t already, check out our contributing guidelines for onboarding and email contributors@expensify.com to request to join our Slack channel!


Version Number: 9.3.38-0
Reproducible in staging?: Yes
Reproducible in production?: N/A - new feature, doesn't exist in prod
If this was caught during regression testing, add the test name, ID and link from BrowserStack: #83556
Email or phone of affected tester (no customers): applausetester+sjddjois2j1d@applause.expensifail.com
Issue reported by: Applause Internal Team
Bug source: Exploratory - Significant User Experience Deterioration
Device used: Mac 26.2 / Chrome
App Component: Money Requests

Action Performed:

Precondition:

  • Log in with Expensifail account.
  1. Go to staging.new.expensify.com
  2. Go to workspace chat.
  3. Click + > Track distance > Odometer.
  4. Enter Start and End reading.
  5. Insert Start and End photo.
  6. Click Next.
  7. On confirm page, click Distance.
  8. Click End photo.
  9. Remove the photo.
  10. Click RHP back button.
  11. Click Distance.

Expected Result:

Since odometer photo is removed from Distance page, receipt on confirm page will not show the removed photo.

Actual Result:

Odometer photo is removed from Distance page, but the receipt on confirm page still shows the removed photo.

Workaround:

Unknown

Platforms:

  • Android: App
  • Android: mWeb Chrome
  • iOS: App
  • iOS: mWeb Safari
  • iOS: mWeb Chrome
  • Windows: Chrome
  • MacOS: Chrome / Safari

Screenshots/Videos

Bug7104094_1773658242527.9.mp4

View all open jobs on GitHub

Issue OwnerCurrent Issue Owner: @DylanDylann

Activity

  1. added
    BugSomething is broken. Auto assigns a BugZero manager.
    on Mar 16, 2026
  2. melvin-bot commented on Mar 16, 2026

    @melvin-bot

    You have been assigned to this deploy blocker because you recently merged this PR: #83556

  3. melvin-bot commented on Mar 16, 2026

    @melvin-bot

    💬 A slack conversation has been started in #expensify-open-source

  4. github-actions commented on Mar 16, 2026

    @github-actions
    Contributor

    👋 Friendly reminder that deploy blockers are time-sensitive ⏱ issues! Check out the open `StagingDeployCash` deploy checklist to see the list of PRs included in this release, then work quickly to do one of the following:

    1. Identify the pull request that introduced this issue and revert it.
    2. Find someone who can quickly fix the issue.
    3. Fix the issue yourself.
  5. OSBotify commented on Mar 16, 2026

    @OSBotify
    Contributor

    Investigation Summary

    Classification: Frontend bug
    Causing PR: #83556 - Odometer Image stitching by @jakubkalinski0 (High confidence)

    Recommendation: REVERT

    PR #83556 introduced the odometer image stitching feature. The bug occurs because when a user deletes one of the odometer images, the stitched receipt on the confirmation page is not updated to reflect the deletion.

    Labels: Keeping DeployBlockerCash (this is a frontend bug affecting the App deploy).

    Evidence

    The issue reproduces following steps from the bug report:

    1. Add both start and end odometer photos
    2. Navigate to confirmation page (stitched image created)
    3. Go back to Distance page
    4. Delete one of the photos
    5. Return to confirmation page
    6. BUG: The deleted photo still appears in the stitched receipt

    Root Cause

    In IOURequestStepDistanceOdometer.tsx, the navigateToNextPage function only updates the receipt when clicking Next/Save. When a user deletes an image from the Distance page and navigates back to confirmation using the RHP back button, the receipt is not re-stitched or cleared. The previously stitched image persists even though one of the source images was deleted.

    The fix requires updating the receipt whenever odometer images change, not just on form submission.

  6. MelvinBot commented on Mar 16, 2026

    @MelvinBot
    Contributor

    Proposal

    Please re-state the problem that we are trying to solve in this issue.

    When a user adds start and end odometer photos, navigates to the confirm page, then goes back to the Distance page and removes a photo, the confirm page still displays the old stitched receipt image that includes the removed photo.

    What is the root cause of that problem?

    There are two separate data paths that get out of sync:

    1. Odometer images are stored in transaction.comment.odometerStartImage / odometerEndImage
    2. The receipt (stitched combination of both images) is stored in transaction.receipt.source

    When the user first clicks "Next" on the odometer page, navigateToNextPage() at IOURequestStepDistanceOdometer.tsx:381-398 stitches the two odometer images together and stores the result in transaction.receipt.source via setMoneyRequestReceipt().

    When the user later removes a photo via the preview modal, deleteOdometerImageAndClose() at TransactionReceiptModalContent.tsx:244-250 calls removeMoneyRequestOdometerImage() at IOU/index.ts:1689-1699. This function only nullifies transaction.comment.odometerStartImage or odometerEndImage — it does not touch transaction.receipt.

    When the user then navigates back to the confirm page using the RHP back button, navigateBack() at IOURequestStepDistanceOdometer.tsx:346-352 calls Navigation.goBack(confirmationRoute) directly — it does not call navigateToNextPage(), so the receipt is never re-stitched or updated. The confirm page reads the stale transaction.receipt.source at IOURequestStepConfirmation.tsx:273-274 and displays the old stitched image.

    There is also a secondary issue: even if the user presses "Save" instead of the back button, navigateToNextPage() at line 390 has a condition if (stitchedImage ?? odometerStartImage ?? odometerEndImage) — if both images were removed, this condition is entirely falsy and setMoneyRequestReceipt is never called, leaving the stale receipt intact.

    What changes do you think we should make in order to solve the problem?

    In removeMoneyRequestOdometerImage() at src/libs/actions/IOU/index.ts, after nullifying the odometer image in transaction.comment, also clear transaction.receipt by merging receipt: {source: '', filename: ''}. This ensures the stale stitched receipt is removed immediately when any odometer photo is deleted. The receipt will be properly re-generated when the user presses Save/Next on the odometer page (via navigateToNextPage()).

    As a safety net, also add an else clause to the condition at IOURequestStepDistanceOdometer.tsx:390 to clear the receipt when all odometer images have been removed:

    if (stitchedImage ?? odometerStartImage ?? odometerEndImage) {
        // existing code to set receipt
    } else {
        // Clear stale receipt when all odometer images have been removed
        setMoneyRequestReceipt(transactionID, '', '', isTransactionDraft);
    }
    

    What alternative solutions did you explore? (Optional)

    1. Only fix navigateToNextPage: Adding the else clause alone would only fix the "Save" path but not the "back without saving" path, which is the primary bug trigger per the issue steps.
    2. Update removeMoneyRequestOdometerImage to re-stitch with the remaining image: Instead of clearing the receipt, update it to show just the remaining single image. This provides better UX (receipt stays visible with the remaining photo) but adds complexity to the action function. Could be a follow-up enhancement.
    3. Force navigateBack to always call navigateToNextPage: This would re-stitch on every back navigation, but has side effects like recalculating distance and potentially triggering form errors unnecessarily.

    Next Steps for Contributor+ team: Reply with @MelvinBot implement this to create a draft PR, @MelvinBot <your feedback> to refine this analysis, or explain why you are rejecting Melvin's proposal.

  7. jakubkalinski0 commented on Mar 16, 2026

    @jakubkalinski0
    Member

    @nlemma This PR [Odometer] Move odometer image stitching to confirmation page moves this logic from odometer screen to confirmation page where it will work exactly as pointed out in expected result. With that in mind and knowing that odometer is hidden behind beta I think we can close this issue.

  8. 23 remaining items

  9. added
    Awaiting PaymentAuto-added when associated PR is deployed to production
    and removed on Apr 2, 2026
  10. changed the title [-]Odometer - Removed photo is shown on confirm page when it is removed from Distance page[/-] [+][Due for payment 2026-04-14] Odometer - Removed photo is shown on confirm page when it is removed from Distance page[/+] on Apr 7, 2026
  11. melvin-bot commented on Apr 7, 2026

    @melvin-bot

    Reviewing label has been removed, please complete the "BugZero Checklist".

  12. melvin-bot commented on Apr 7, 2026

    @melvin-bot

    The solution for this issue has been 🚀 deployed to production 🚀 in version 9.3.52-9 and is now subject to a 7-day regression period 📆. Here is the list of pull requests that resolve this issue:

    If no regressions arise, payment will be issued on 2026-04-14. 🎊

    For reference, here are some details about the assignees on this issue:

  13. melvin-bot commented on Apr 7, 2026

    @melvin-bot

    @DylanDylann The PR fixing this issue has been merged! The following checklist (instructions) will need to be completed before the issue can be closed. Please copy/paste the BugZero Checklist from here into a new comment on this GH and complete it. If you have the K2 extension, you can simply click: [this button]

  14. melvin-bot commented on Apr 7, 2026

    @melvin-bot

    Triggered auto assignment to @mallenexpensify (Awaiting Payment)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

Awaiting PaymentAuto-added when associated PR is deployed to productionBugSomething is broken. Auto assigns a BugZero manager.EngineeringReviewingHas a PR in reviewWeeklyKSv2

Type

No type

Projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions