Skip to content

Render the generated distance receipt on every New Expensify surface - #98506

Open
yuwenmemon wants to merge 3 commits into
mainfrom
yuwen-97013-distance-receipt-values
Open

Render the generated distance receipt on every New Expensify surface#98506
yuwenmemon wants to merge 3 commits into
mainfrom
yuwen-97013-distance-receipt-values

Conversation

@yuwenmemon

@yuwenmemon yuwenmemon commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

@ahmedGaber93 @Valforte please review

Fixed Issues

$ #97013

Details

  1. The generated mileage receipt intentionally records the routed trip while the expense records what is billed, so the two disagree after a manual distance edit or a commuter exclusion. That is deliberate: Web-Expensify [HOLD for payment 2024-10-17] Expense preview disappear entirely clicking on one export report for a while #49853 made the receipt keep the original route for a customer who deducts commuting miles by hand and needs to check the deduction against it. Expensify Classic shows that file everywhere, so the numbers only ever appear once.
  2. New Expensify showed two different things for the same receipt. Hovering the receipt box and hovering a Search row drew a DistanceEReceipt card built from the expense, while expanding it rendered the generated file. That is the mismatch in the issue, and it is the only part that is actually broken.
  3. Now one predicate, shouldRenderLocalDistanceEReceipt, decides between the generated file and the local card, and every surface asks it. The surfaces cannot disagree. The card is the fallback for a file we cannot show: no receipt yet, the server is rebuilding it after an edit, the route errored, or an older expense that stored a bare map image instead of a PDF.
  4. Three smaller problems fall out of the same change. Expanding a receipt mid-regeneration used to request the invalidated URL, because the PDF branch returned before the distance branch could ever run. The card's map slot did the same, since that thumbnail is a page of the stored file and only waypoint edits were guarded. Download could hand over a file that did not match what was on screen.
  5. Two visible behaviour changes for QA. An odometer expense in the Search hover preview drew a distance card even though expanding it showed the stitched odometer photo; it now shows the photo in both. A merged distance-manual expense that still carries waypoints loses the hover card, which matches what expanding it already showed.

Worth knowing separately, and not addressed here: the receipt does not have one fixed meaning. A distance edit regenerates it from the Mapbox route, but a rate change regenerates it from the stored billed quantity, so which numbers it carries depends on which edit came last. I will raise that on its own.

Tests

  1. Create a map distance expense on a workspace with distance rates, and wait for the receipt to arrive.
  2. Hover the receipt in the expense view, hover the same expense's row in Search, and expand the receipt. Verify all three show the generated receipt and agree.
  3. Edit the distance to a different number and save.
  4. Before the new receipt arrives, verify the receipt box draws the route map, hovering shows the card with a pending map rather than a stale image, expanding shows the card, and Download is not offered.
  5. Wait for the new receipt, then repeat step 2. Verify the three surfaces still agree with each other.
  6. Change the rate on the same expense, wait for the receipt, and verify the three surfaces still agree.
  7. Open an odometer expense and verify its Search hover preview shows the odometer photo, matching what expanding it shows.
  8. Open a manual distance expense with no map and verify it is unchanged.
  9. Open the same expense in Expensify Classic and verify its receipt matches the one New Expensify now shows.

Automated: 372 tests in tests/unit/TransactionUtilsTest.ts including 7 new cases for the predicate, plus tests/ui/components/MoneyRequestReceiptViewTest.tsx, tests/ui/IOURequestStepDistanceTest.tsx and tests/unit/components/ReceiptPreviewPositionTest.ts. Typecheck, lint and the React Compiler compliance check pass.

  • [PR Author] I made sure this PR correctly handles default values (SO)

@yuwenmemon
yuwenmemon requested review from a team as code owners August 12, 2026 22:22
@melvin-bot
melvin-bot Bot requested review from ahmedGaber93 and garrettmknight and removed request for a team August 12, 2026 22:22
@melvin-bot

melvin-bot Bot commented Aug 12, 2026

Copy link
Copy Markdown

@ahmedGaber93 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]

@melvin-bot
melvin-bot Bot removed the request for review from a team August 12, 2026 22:22
@yuwenmemon
yuwenmemon requested a review from a team August 12, 2026 22:27
@codecov

codecov Bot commented Aug 12, 2026

Copy link
Copy Markdown

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.

Files with missing lines Coverage Δ
...nents/ReportActionItem/MoneyRequestReceiptView.tsx 71.20% <100.00%> (ø)
...ponents/ReportActionItem/ReportActionItemImage.tsx 70.49% <100.00%> (-0.48%) ⬇️
src/libs/TransactionUtils/index.ts 91.38% <100.00%> (+0.05%) ⬆️
...rc/components/Attachments/AttachmentView/index.tsx 51.93% <50.00%> (+0.79%) ⬆️
...onents/TransactionItemRow/ReceiptPreview/index.tsx 0.00% <0.00%> (ø)
...alScreen/routes/TransactionReceiptModalContent.tsx 0.00% <0.00%> (ø)
src/components/DistanceEReceipt.tsx 0.00% <0.00%> (ø)
... and 7 files with indirect coverage changes

@melvin-bot
melvin-bot Bot requested review from Valforte and removed request for a team August 12, 2026 22:28
@melvin-bot

melvin-bot Bot commented Aug 12, 2026

Copy link
Copy Markdown

@Valforte 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]

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8a0e6cee34

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/components/DistanceEReceipt.tsx Outdated
{isFetchingWaypointsFromServer(transaction) || !thumbnailSource ? (
{/* The thumbnail is a page of the stored receipt file, therefore an edit that makes the server
build a new file also invalidates it. Draw the pending map until the new file arrives. */}
{hasPendingDistanceReceiptRegeneration(transaction) || !thumbnailSource ? (

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Avoid loading stale receipts when the route has errors

When a route or waypoint error occurs while an old receipt source is still present, shouldRenderLocalDistanceEReceipt() now selects this card because hasDistanceRouteErrors() is true, but this condition only suppresses the thumbnail for pending regeneration. The card therefore requests and displays the stale/invalid generated receipt page, while the report receipt tile renders ConfirmedRoute, preserving the cross-surface mismatch this change is meant to remove. Treat route errors like pending regeneration here, or render the locally available route instead.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(Yuwen's Agent) Good catch — fixed in eef9971. The card now draws the pending map whenever the stored file cannot be trusted, which is hasPendingDistanceReceiptRegeneration || hasDistanceRouteErrors, so the error case no longer loads the stale receipt page while the report tile shows ConfirmedRoute.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant