Use PUSH instead of REPLACE for 2FA Download codes navigation on web#94761
Use PUSH instead of REPLACE for 2FA Download codes navigation on web#94761MobileMage wants to merge 2 commits into
Conversation
|
@parasharrajat 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] |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: e9adf2eecb
ℹ️ 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".
| setCodesAreCopied(); | ||
| announceStatus(translate('fileDownload.success.title')); | ||
| Navigation.navigate(createDynamicRoute(DYNAMIC_ROUTES.TWO_FACTOR_AUTH_VERIFY.path, backPath), {forceReplace: true}); | ||
| Navigation.navigate(createDynamicRoute(DYNAMIC_ROUTES.TWO_FACTOR_AUTH_VERIFY.path, backPath), {forceReplace: !isWeb}); |
There was a problem hiding this comment.
Preserve non-settings back paths after success
When this runs on web from a dynamic entry point such as the bank-account 2FA prompt or the required-Xero overlay, using PUSH leaves the recovery-codes screen underneath the later success screen. After the user enables 2FA, browser Back from the success page lands on that root screen; the root page redirects any enabled account to ROUTES.SETTINGS_2FA_ENABLED (lines 73-75), so the user is taken to Settings instead of back to the originating flow. Either keep this intermediate page out of history for non-settings entries or make that enabled-account redirect honor backPath.
Useful? React with 👍 / 👎.
Codecov Report✅ Changes either increased or maintained existing code coverage, great job!
|
| const baseState = getStateFromPath(backPath); | ||
| const focusedRoute = baseState ? findFocusedRoute(baseState) : undefined; | ||
| const isSecuritySettingsFlow = focusedRoute?.name === SCREENS.SETTINGS.SECURITY; |
Explanation of Change
On web, the Download codes button on the 2FA recovery-codes step navigated to the Verify step with
forceReplace: true(a REPLACE action). On macOS Chrome, the native "Save As" dialog blurs the tab and delays thepopstateevent past React Navigation's 100 mshistory.go(-1)safety window. The delayedpopstateis then treated as a user-initiated back press, souseLinkingmatches the cached pre-2FA/settings/securitystate and callsresetRoot, which unmounts the 2FA RHP and clears the recovery codes — the page "closes" instead of advancing to the Verify/QR step.The fix changes the navigation to
forceReplace: !isWeb:createMemoryHistory.go(-1)vspopstaterace can never occur, and the browser Back button correctly returns from Verify to the Recovery-codes step.forceReplace: true), preserving the back-stack behavior fixed in [BT-128] Migrate forwardTo Routes - 2FA Flow #89608.Fixed Issues
$ #92564
PROPOSAL: #92564 (comment)
Tests
Offline tests
Generating recovery codes requires a server response, so there is no offline-specific behavior for this flow — the change only affects client-side navigation (PUSH vs REPLACE) and does not alter any offline path.
QA Steps
PR Author Checklist
### Fixed Issuessection aboveTestssectionOffline stepssectionQA stepssectiontoggleReportand notonIconClick)Avatar, 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
Kapture.2026-06-27.at.06.16.49.mp4
Android: mWeb Chrome
iOS: Native
Kapture.2026-06-26.at.20.36.12.mp4
iOS: mWeb Safari
MacOS: Chrome / Safari
Kapture.2026-06-25.at.16.32.55.mp4