Repository navigation
[Payment due @DylanDylann] [Odometer] Show discard changes modal when switching tabs - #89612
Conversation
Codecov Report✅ Changes either increased or maintained existing code coverage, great job!
|
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 4a624d5330
ℹ️ About Codex in GitHub
Codex has been enabled to automatically 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 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 31b9b37c2f
ℹ️ About Codex in GitHub
Codex has been enabled to automatically 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 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: b2690b40a8
ℹ️ About Codex in GitHub
Codex has been enabled to automatically 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 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: b2690b40a8
ℹ️ About Codex in GitHub
Codex has been enabled to automatically 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 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: bd1d392ced
ℹ️ About Codex in GitHub
Codex has been enabled to automatically 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 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: f9086f72ef
ℹ️ About Codex in GitHub
Codex has been enabled to automatically 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 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 4f59a798f4
ℹ️ About Codex in GitHub
Codex has been enabled to automatically 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 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 62149d8334
ℹ️ About Codex in GitHub
Codex has been enabled to automatically 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 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 62149d8334
ℹ️ About Codex in GitHub
Codex has been enabled to automatically 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 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
|
@codex review |
|
Codex Review: Didn't find any major issues. Hooray! ℹ️ About Codex in GitHubCodex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback". |
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: b64dcc998d
ℹ️ About Codex in GitHub
Codex has been enabled to automatically 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 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
isExternalOdometerResync slides the readings discard-baseline, yet it also fired on image-only changes. In the create flow, adding then reverting an odometer image re-baselined still-unsent readings, so the "Discard changes?" prompt was silently dropped on tab switch / back. Make the predicate readings-only (drop the unused image fields and deps). Image edits are still tracked separately against the never-slid image baseline. Add hook- and UI-level regression tests.
|
@codex review |
|
@codex review please |
|
Codex Review: Didn't find any major issues. Delightful! Reviewed commit: ℹ️ About Codex in GitHubCodex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback". |
…_modal_when_switching_tabs
…rtPage
The tabBar={(props) => <TabSelector {...props}/>} wrapper was only needed
by the old page-level DistanceTabGuardContext to capture navigation/state.
That guard moved into OnyxTabNavigator's generic tab-switch guard, so the
wrapper is now a no-op identical to passing TabSelector directly. Revert to
tabBar={TabSelector}, matching every other caller. Zero net diff vs main.
…e from OdometerImageUtil Move isExternalOdometerResync, shouldInitializeOdometerFromTransaction, and OdometerResyncState out of the page-level odometerResync.ts into src/libs. Rename OdometerImageUtils.ts -> OdometerUtils.ts to hold all odometer pure utils. Update all importers and the unit test. No behavior change.
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 6257c1fce3
ℹ️ About Codex in GitHub
Codex has been enabled to automatically 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 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
|
🎯 @DylanDylann, thanks for reviewing and testing this PR! 🎉 A payment issue will be created for your review once this PR is deployed to production. If payment is not needed (e.g., regression PR review fix etc), react with 👎 to this comment to prevent the payment issue from being created. |
In the saved-for-later recovery path, hasVerifiedBlobs flipped true before hydrateOdometerDraftIntoTransaction's Onyx.merge landed, letting the readings hook snapshot its image baseline from the stale dead-blob image. A later swap to the re-minted image then read as a phantom "Discard changes?". Flip verification and navigate only after the merge resolves.
|
@codex review |
The recovery path now awaits hydrateOdometerDraftIntoTransaction() before flipping verification (commit b483157), but the test mock returned undefined, so .then() threw and hasVerifiedBlobs stayed false. Return Promise.resolve() to match the real Promise<void> signature.
|
@codex review please |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 375d63bd2e
ℹ️ About Codex in GitHub
Codex has been enabled to automatically 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 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
|
@codex review please |
|
Codex Review: Didn't find any major issues. More of your lovely PRs please. Reviewed commit: ℹ️ About Codex in GitHubCodex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback". |
|
@DylanDylann Could I ask for a re-approve? Pretty please 🥺 (I was resolving one comment from codex review #89612 (comment) when you approved, sorry 🙇) |
|
Taking over this PR with a clone here. |
Explanation of Change
This PR adds a feature we agreed on in this discussion to show a Discard Changes confirmation modal when the user tries to switch away from the Odometer tab to another tab with unsaved changes.
The tab-switch guard is generic, not odometer-specific. A new
TabSwitchGuardContextlets any tab screen registergetHasUnsavedChanges/onDiscard/onCancelcallbacks keyed by tab name, andOnyxTabNavigatorinterceptstabPressto show the shared "Discard changes?" modal - on confirm it runsonDiscardand then jumps to the target tab (it always jumps, even ifonDiscardfails, surfacing a Growl error rather than stranding the user). It's wired through the existinguseDiscardChangesConfirmationhook via a newonTabSwitchDiscardoption that self-disables outside a tab navigator, and both the nav-away and tab-switch paths render an identical modal fromgetDiscardChangesModalConfig. On the Odometer tab, confirming clears the readings/images (or restores the confirmation-edit backup when editing) before the tab switch.The discard diff is hardened against false positives: image changes use a re-mint-invariant identity (
getOdometerImageIdentity,name|size|lastModified) that survives the draft round-trip but still detects a real swap, and the resync / unsaved-changes branching is extracted into unit-tested pure predicates (odometerResync.ts,getOdometerHasUnsavedChanges) that won't re-hydrate readings the user intentionally cleared.Fixed Issues
$ #89940
PROPOSAL: N/A
Tests
OnyxTabNavigator-based flow that does not register a guard (e.g. the Map/Manual distance tabs with no unsaved odometer changes) and verify tab switches happen immediately with no modal.Nav-away discard still works
Save-for-later draft
Offline tests
Same as Tests
QA Steps
Same as 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))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
untitled.webm
Android: mWeb Chrome
untitled2.webm
iOS: Native
Simulator.Screen.Recording.-.iPhone.16.Pro.Max.-.2026-06-16.at.23.05.25.mov
iOS: mWeb Safari
Simulator.Screen.Recording.-.iPhone.16.Pro.Max.-.2026-06-16.at.23.22.23.mov
MacOS: Chrome / Safari
Screen.Recording.2026-06-16.at.20.56.57.mov