Skip to content

fix: Redirect completed users from onboarding deep link routes to home#83193

Merged
Beamanator merged 13 commits intomainfrom
claude-redirectCompletedUsersFromOnboardingRoutes
Feb 23, 2026
Merged

fix: Redirect completed users from onboarding deep link routes to home#83193
Beamanator merged 13 commits intomainfrom
claude-redirectCompletedUsersFromOnboardingRoutes

Conversation

@MelvinBot
Copy link
Contributor

@MelvinBot MelvinBot commented Feb 23, 2026

Explanation of Change

When a user who has completed onboarding clicks a "Continue Onboarding" deep link (/onboarding/purpose) from a Concierge message, nothing happens — the navigation silently fails. This is because the OnboardingModalNavigator is conditionally excluded from the navigation stack when isOnboardingCompleted !== false (in AuthScreens.tsx), so the route can't resolve. The OnboardingGuard blindly returns ALLOW when onboarding is completed, without checking whether the user is trying to navigate to an onboarding route.

This PR adds a check in OnboardingGuard.evaluate() that detects when a completed user is navigating to an onboarding route via deep link (RESET action) and redirects them to the home screen instead of silently failing. This follows the same pattern established by TestDriveModalGuard, which redirects to ROUTES.HOME when a user navigates to a dismissed test drive modal.

Fixed Issues

$ #79588

Tests

  1. Log into an account that has already completed the onboarding/guided setup flow
  2. Navigate to https://staging.new.expensify.com/onboarding/purpose directly (or any /onboarding/* route)
  3. Verify you are redirected to the home/inbox screen instead of nothing happening
  4. Try other onboarding routes like /onboarding/personal-details and /onboarding/work-email
  5. Verify all redirect to home
  6. Log into a fresh account that has NOT completed onboarding
  7. Verify the normal onboarding flow still works correctly
  8. Run npx jest tests/unit/Navigation/guards/OnboardingGuard.test.ts — all tests pass
  • Verify that no errors appear in the JS console

Offline tests

This change only affects deep link navigation routing logic, which is handled synchronously in the navigation guard. No network requests are involved. Offline behavior is unaffected.

QA Steps

  1. Log into an account that has already completed the onboarding/guided setup flow
  2. Navigate to any chat and send message link: https://staging.new.expensify.com/onboarding/purpose
  3. Verify you are redirected to the home/inbox screen
  4. Try other onboarding routes like /onboarding/personal-details and /onboarding/work-email
  5. Verify all redirect to home
  6. Log into a fresh account that has NOT completed onboarding
  7. Verify the normal onboarding flow still works correctly
  • Verify that no errors appear in the JS console

PR Author Checklist

  • I linked the correct issue in the ### Fixed Issues section above
  • I wrote clear testing steps that cover the changes made in this PR
    • I added steps for local testing in the Tests section
    • I added steps for the expected offline behavior in the Offline steps section
    • I added steps for Staging and/or Production testing in the QA steps section
    • I added steps to cover failure scenarios (i.e. verify an input displays the correct error message if the entered data is not correct)
    • I turned off my network connection and tested it while offline to ensure it matches the expected behavior (i.e. verify the default avatar icon is displayed if app is offline)
    • I tested this PR with a High Traffic account against the staging or production API to ensure there are no regressions (e.g. long loading states that impact usability).
  • I included screenshots or videos for tests on all platforms
  • I ran the tests on all platforms & verified they passed on:
    • Android: Native
    • Android: mWeb Chrome
    • iOS: Native
    • iOS: mWeb Safari
    • MacOS: Chrome / Safari
  • I verified there are no console errors (if there's a console error not related to the PR, report it or open an issue for it to be fixed)
  • I verified there are no new alerts related to the canBeMissing param for useOnyx
  • I followed proper code patterns (see Reviewing the code)
    • I verified that any callback methods that were added or modified are named for what the method does and never what callback they handle (i.e. toggleReport and not onIconClick)
    • I verified that comments were added to code that is not self explanatory
    • I verified that any new or modified comments were clear, correct English, and explained "why" the code was doing something instead of only explaining "what" the code was doing.
    • I verified any copy / text shown in the product is localized by adding it to src/languages/* files and using the translation method
      • If any non-english text was added/modified, I used JaimeGPT to get English > Spanish translation. I then posted it in #expensify-open-source and it was approved by an internal Expensify engineer. Link to Slack message:
    • I verified all numbers, amounts, dates and phone numbers shown in the product are using the localization methods
    • I verified any copy / text that was added to the app is grammatically correct in English. It adheres to proper capitalization guidelines (note: only the first word of header/labels should be capitalized), and is either coming verbatim from figma or has been approved by marketing (in order to get marketing approval, ask the Bug Zero team member to add the Waiting for copy label to the issue)
    • I verified proper file naming conventions were followed for any new files or renamed files. All non-platform specific files are named after what they export and are not named "index.js". All platform-specific files are named for the platform the code supports as outlined in the README.
    • I verified the JSDocs style guidelines (in STYLE.md) were followed
  • If a new code pattern is added I verified it was agreed to be used by multiple Expensify engineers
  • I followed the guidelines as stated in the Review Guidelines
  • I tested other components that can be impacted by my changes (i.e. if the PR modifies a shared library or component like Avatar, I verified the components using Avatar are working as expected)
  • I verified all code is DRY (the PR doesn't include any logic written more than once, with the exception of tests)
  • I verified any variables that can be defined as constants (ie. in CONST.ts or at the top of the file that uses the constant) are defined as such
  • I verified that if a function's arguments changed that all usages have also been updated correctly
  • If any new file was added I verified that:
    • The file has a description of what it does and/or why is needed at the top of the file if the code is not self explanatory
  • If a new CSS style is added I verified that:
    • A similar style doesn't already exist
    • The style can't be created with an existing StyleUtils function (i.e. StyleUtils.getBackgroundAndBorderStyle(theme.componentBG))
  • If new assets were added or existing ones were modified, I verified that:
    • The assets are optimized and compressed (for SVG files, run npm run compress-svg)
    • The assets load correctly across all supported platforms.
  • If the PR modifies code that runs when editing or sending messages, I tested and verified there is no unexpected behavior for all supported markdown - URLs, single line code, code blocks, quotes, headings, bold, strikethrough, and italic.
  • If the PR modifies a generic component, I tested and verified that those changes do not break usages of that component in the rest of the App (i.e. if a shared library or component like Avatar is modified, I verified that Avatar is working as expected in all cases)
  • If the PR modifies a component related to any of the existing Storybook stories, I tested and verified all stories for that component are still working as expected.
  • If the PR modifies a component or page that can be accessed by a direct deeplink, I verified that the code functions as expected when the deeplink is used - from a logged in and logged out account.
  • If the PR modifies the UI (e.g. new buttons, new UI components, changing the padding/spacing/sizing, moving components, etc) or modifies the form input styles:
    • I verified that all the inputs inside a form are aligned with each other.
    • I added Design label and/or tagged @Expensify/design so the design team can review the changes.
  • If a new page is added, I verified it's using the ScrollView component to make it scrollable when more elements are added to the page.
  • I added unit tests for any new feature or bug fix in this PR to help automatically prevent regressions in this user flow.
  • If the main branch was merged into this PR after a review, I tested again and verified the outcome was still expected according to the Test steps.

Screenshots/Videos

Android: Native

N/A - Navigation guard logic only, no UI changes

Android: mWeb Chrome

N/A - Navigation guard logic only, no UI changes

iOS: Native

N/A - Navigation guard logic only, no UI changes

iOS: mWeb Safari

N/A - Navigation guard logic only, no UI changes

MacOS: Chrome / Safari

N/A - Navigation guard logic only, no UI changes

When a user who has completed onboarding clicks a deep link to
/onboarding/purpose (e.g. from a Concierge message), the navigation
silently fails because the OnboardingModalNavigator is not mounted.

Add a check in OnboardingGuard to detect when a completed user is
navigating to an onboarding route via deep link (RESET action) and
redirect them to the home screen instead.

Co-authored-by: Linh Vo <linhvovan29546@users.noreply.github.com>
Co-authored-by: Linh Vo <linhvovan29546@users.noreply.github.com>
@MelvinBot
Copy link
Contributor Author

Fixed the failing Prettier check. The imports in src/languages/de.ts were not sorted alphabetically — ran Prettier to reorder them.

@linhvovan29546
Copy link
Contributor

@MelvinBot Please add a comment to the test based on the instructions in this README: https://github.com/Expensify/App/blob/main/tests/README.md

Following the test documentation guidelines in tests/README.md, each test
now includes Given/When/Then comment sections that explain why the test
exists and what behavior it verifies.

Co-authored-by: Linh Vo <linhvovan29546@users.noreply.github.com>
@MelvinBot
Copy link
Contributor Author

Added Given/When/Then documentation comments to all 17 tests in OnboardingGuard.test.ts, following the guidelines in tests/README.md. Each test now has:

  • Given — explains the initial condition and why it matters
  • When — describes the action being tested
  • Then — explains the expected outcome and why it should behave that way

All 17 tests still pass after the changes.

MelvinBot and others added 3 commits February 23, 2026 11:48
…eModal pattern

Restructured the function to follow the same approach as
isNavigatingToTestDriveModal in TestDriveModalGuard:
- Accept state parameter and check current focused route first
- Use string literal 'RESET' and findFocusedRoute on the action payload
- Remove the manual routes array check for ONBOARDING_MODAL_NAVIGATOR
- Remove unused NAVIGATORS import from both guard and test files
- Simplified the RESET test payload to match the cleaner pattern

Co-authored-by: Linh Vo <linhvovan29546@users.noreply.github.com>
…eModal pattern

Restructures the function to follow the same approach as
isNavigatingToTestDriveModal in TestDriveModalGuard: checks the current
focused route first, then checks the RESET action payload. Removes the
extra routes.some() check for ONBOARDING_MODAL_NAVIGATOR since
findFocusedRoute traverses into nested states.

Co-authored-by: Linh Vo <linhvovan29546@users.noreply.github.com>
Preferred CONST.NAVIGATION_ACTIONS.RESET over literal 'RESET' string
for consistency with the rest of the file.

Co-authored-by: Linh Vo <linhvovan29546@users.noreply.github.com>
@codecov
Copy link

codecov bot commented Feb 23, 2026

Codecov Report

✅ Changes either increased or maintained existing code coverage, great job!

Files with missing lines Coverage Δ
src/libs/Navigation/guards/OnboardingGuard.ts 100.00% <100.00%> (ø)
... and 20 files with indirect coverage changes

Comment on lines +136 to +151
function isNavigatingToOnboardingFlow(state: NavigationState, action: NavigationAction): boolean {
const currentRoute = findFocusedRoute(state);
if (isOnboardingFlowName(currentRoute?.name)) {
return true;
}

if (action.type === CONST.NAVIGATION_ACTIONS.RESET && action.payload) {
const targetRoute = findFocusedRoute(action.payload as NavigationState);
if (isOnboardingFlowName(targetRoute?.name)) {
return true;
}
}

return false;
}

This comment was marked as resolved.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Applied this suggestion. The isNavigatingToOnboardingFlow function now checks for NAVIGATE/PUSH actions targeting NAVIGATORS.ONBOARDING_MODAL_NAVIGATOR instead of checking RESET action payloads with findFocusedRoute. Updated tests accordingly — all 18 tests pass.

@MelvinBot
Copy link
Contributor Author

The only failing check is the PR Reviewer Checklist (checklist), which fails with No PR Reviewer Checklist was found. This is not a code issue — it requires a human reviewer to post the reviewer checklist comment on the PR.

All code-related checks are passing: tests (all 8 jobs), typecheck, ESLint, Prettier, all builds, Storybook tests, codecov, verifySignedCommits, and CLA. No code fix is needed.

@MelvinBot
Copy link
Contributor Author

The only failing check is the PR Reviewer Checklist (reviewerChecklist.js), which fails with:

No PR Reviewer Checklist was found

This is not a code issue — it fails because no reviewer has posted the reviewer checklist comment on the PR yet. All code-related checks (ESLint, typecheck, Prettier, tests, builds, spellcheck, signed commits, etc.) are passing. This check will resolve automatically once a reviewer posts their checklist.

@linhvovan29546
Copy link
Contributor

@MelvinBot Apply this suggestion #83193 (comment)

Apply review suggestion: instead of checking RESET action payloads
with findFocusedRoute, check for NAVIGATE/PUSH actions that directly
target NAVIGATORS.ONBOARDING_MODAL_NAVIGATOR. Updated tests to match.

Co-authored-by: Linh Vo <linhvovan29546@users.noreply.github.com>
@MelvinBot
Copy link
Contributor Author

The only failing check is PR Reviewer Checklist / checklist, which fails because no reviewer has posted the reviewer checklist comment yet. This is not a code issue — it will resolve once a reviewer picks up the PR and posts their checklist. No code fix is needed.

@linhvovan29546
Copy link
Contributor

@MelvinBot Please update the PR title to follow the PR_AUTHOR_REVIEWER_BEST_PRACTICES.md guidelines https://github.com/Expensify/App/blob/main/contributingGuides/PR_AUTHOR_REVIEWER_BEST_PRACTICES.md

@MelvinBot MelvinBot changed the title Redirect completed users from onboarding routes to home fix: Redirect completed users from onboarding deep link routes to home Feb 23, 2026
@MelvinBot
Copy link
Contributor Author

Updated the PR title to follow the PR_AUTHOR_REVIEWER_BEST_PRACTICES.md convention:

Before: Redirect completed users from onboarding routes to home
After: fix: Redirect completed users from onboarding deep link routes to home

Added the fix type prefix since this PR fixes a bug (#79588).

@linhvovan29546
Copy link
Contributor

@MelvinBot Make the PR Ready for review

@MelvinBot MelvinBot marked this pull request as ready for review February 23, 2026 12:18
@MelvinBot MelvinBot requested a review from a team as a code owner February 23, 2026 12:18
@MelvinBot
Copy link
Contributor Author

Marked this PR as Ready for review.

@melvin-bot melvin-bot bot removed the request for review from a team February 23, 2026 12:18
MelvinBot and others added 2 commits February 23, 2026 15:50
Add two additional tests that verify the boundary conditions of the
isNavigatingToOnboardingFlow function:
- RESET actions containing onboarding routes are NOT intercepted
- REPLACE actions targeting onboarding navigator are NOT intercepted

These confirm the function only handles NAVIGATE and PUSH action types.

Co-authored-by: Situ Chandra Shil <situchan@users.noreply.github.com>
…ttps://github.com/Expensify/App into claude-redirectCompletedUsersFromOnboardingRoutes

Co-authored-by: Situ Chandra Shil <situchan@users.noreply.github.com>
Copy link
Contributor

@situchan situchan left a comment

Choose a reason for hiding this comment

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

@MelvinBot update Tests step 4 a bit.
/onboarding/work path not exist. It leads to not found page. The correct path is /onboarding/work-email

@situchan
Copy link
Contributor

@codex review

Copy link

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

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: 95a3a542a6

ℹ️ 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".

@situchan
Copy link
Contributor

Tests pass

Screen.Recording.2026-02-23.at.10.16.32.PM.mov

import {getAdminPoliciesConnectedToNetSuite} from '@libs/actions/Policy/Policy';
import Navigation from '@libs/Navigation/Navigation';
import {useAccountingContext} from '@pages/workspace/accounting/AccountingContext';
import {getInitialSubPageForNetsuiteTokenInput} from '@pages/workspace/accounting/netsuite/utils';
Copy link
Contributor

Choose a reason for hiding this comment

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

FYI: This prettier issue is being fixed in #83221

Copy link
Contributor

Choose a reason for hiding this comment

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

It's merged now.
@MelvinBot pull main again

Copy link

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

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: 95a3a542a6

ℹ️ 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".

…tedUsersFromOnboardingRoutes

Co-authored-by: Situ Chandra Shil <situchan@users.noreply.github.com>
@MelvinBot
Copy link
Contributor Author

Merged main into this branch. No conflicts — merge was clean.

@situchan
Copy link
Contributor

@Beamanator all yours

The inline comment was redundant with the JSDoc description above the function.

Co-authored-by: flaviadefaria <flaviadefaria@users.noreply.github.com>
Copy link
Contributor

@Beamanator Beamanator left a comment

Choose a reason for hiding this comment

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

Loving the minimal changes with all the clarified & added tests! 🙏

@Beamanator Beamanator merged commit 889028b into main Feb 23, 2026
32 checks passed
@Beamanator Beamanator deleted the claude-redirectCompletedUsersFromOnboardingRoutes branch February 23, 2026 17:37
@OSBotify
Copy link
Contributor

✋ This PR was not deployed to staging yet because QA is ongoing. It will be automatically deployed to staging after the next production release.

@github-actions
Copy link
Contributor

🚧 @Beamanator has triggered a test Expensify/App build. You can view the workflow run here.

@mitarachim
Copy link

@linhvovan29546 @situchan This PR is failing because of a regression issue #83273

The issue is reproducible in: Web

Bug7086493_1771890486034!ExpensifyOnboardingWorkNotFound

@linhvovan29546
Copy link
Contributor

@mitarachim Apologies, that’s not a bug, just a typo generated by the AI.

@mitarachim
Copy link

@linhvovan29546 Noted, Thanks for letting me know

@OSBotify
Copy link
Contributor

🚀 Deployed to staging by https://github.com/Beamanator in version: 9.3.25-0 🚀

platform result
🕸 web 🕸 success ✅
🤖 android 🤖 failure ❌
🍎 iOS 🍎 cancelled 🔪

@situchan
Copy link
Contributor

@MelvinBot update Tests step 4 a bit. /onboarding/work path not exist. It leads to not found page. The correct path is /onboarding/work-email

Melvin skipped my message 😄

@MelvinBot
Copy link
Contributor Author

Updated the PR body — changed /onboarding/work to /onboarding/work-email in both the Tests (step 4) and QA Steps (step 4) sections. Good catch!

@OSBotify
Copy link
Contributor

🚀 Deployed to production by https://github.com/puneetlath in version: 9.3.25-13 🚀

platform result
🕸 web 🕸 success ✅
🤖 android 🤖 success ✅
🍎 iOS 🍎 success ✅

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.

6 participants