Skip to content

fix: onboarding back button redirects to blank modal for private-domain VSB/SMB#95001

Merged
mollfpr merged 7 commits into
Expensify:mainfrom
dilshodmackbook-sketch:dilshod/fix-93660-onboarding-back-button
Jul 9, 2026
Merged

fix: onboarding back button redirects to blank modal for private-domain VSB/SMB#95001
mollfpr merged 7 commits into
Expensify:mainfrom
dilshodmackbook-sketch:dilshod/fix-93660-onboarding-back-button

Conversation

@dilshodmackbook-sketch

@dilshodmackbook-sketch dilshodmackbook-sketch commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

Explanation of Change

During onboarding, a private-domain VSB/SMB user who signs up with accessible domain policies saw a back arrow on the How many employees do you have? (OnboardingEmployees) screen that navigated to a blank Workspaces modal.

Root cause: getDomainPrefix in getOnboardingStepCounter.ts hardcoded both PRIVATE_DOMAIN and WORKSPACES for every private-domain user, even though a user only ever traverses one of them before EMPLOYEES (gated by account validation in BaseOnboardingPersonalDetails). The phantom WORKSPACES step inflated the step counter and made the EMPLOYEES back button resolve to a screen the user never visited, which renders blank.

This change gates the private-domain prefix on account validation — the same signal BaseOnboardingPersonalDetails branches on, mirroring the public-domain fix from #93399:

  • Unvalidated[PERSONAL_DETAILS, PRIVATE_DOMAIN] — Back lands on PRIVATE_DOMAIN (the screen the user came from).
  • Validated, has joinable workspaces[PERSONAL_DETAILS, WORKSPACES] — Back lands on WORKSPACES.
  • Validated, no joinable workspaces (that screen auto-skips) → [PERSONAL_DETAILS] — Back lands on PERSONAL_DETAILS.

The hasJoinablePolicies signal is threaded into the flow context from JOINABLE_POLICIES in both context builders (useOnboardingStepCounter and BaseOnboardingEmployees). Public-domain and no-domain flows are untouched.

Fixed Issues

$ #93660
PROPOSAL: #93660 (comment)

Tests

  1. Sign up as a new user on a private domain that has accessible/joinable policies, choosing Manage expenses for 1-9 employees (VSB) on the landing page.
  2. Do not validate the account. Enter first/last name on the Personal Details screen and continue.
  3. On the People you may know (private domain) screen, press Skip to reach the How many employees do you have? screen.
  4. Press the back arrow.
  5. Verify it returns to the People you may know (private domain) screen — not a blank modal.
  6. Verify the step counter on the Employees screen is accurate (no skipped/phantom step).
  7. Repeat for a validated private-domain user with joinable workspaces: Back from Employees returns to Join workspaces.
  8. Repeat for a validated private-domain user with no joinable workspaces (Join workspaces auto-skips): Back from Employees returns to Personal details.
  • Verify that no errors appear in the JS console

Offline tests

Same as tests.

QA Steps

  1. On staging, select Manage expenses for 1-9 employees, then sign up with a valid private-domain email (e.g. a tstsg.com address) that has accessible policies.
  2. Click Get started for free > Join, enter a first name and proceed.
  3. On the private-domain screen, Skip to reach the employee count modal.
  4. Click the back arrow.
  5. Verify the previous screen is shown (not a blank modal).
  • 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 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 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)
  • 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)
  • 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.
  • 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
Screen.Recording.2026-06-30.at.23.57.37.mp4
Android: mWeb Chrome
androidMweb.mp4
iOS: Native
iosNative.mp4
iOS: mWeb Safari
ios.mov
MacOS: Chrome / Safari
chrome.mp4
safari.mov

The EMPLOYEES screen back button redirected to a blank Workspaces modal
because getDomainPrefix hardcoded both PRIVATE_DOMAIN and WORKSPACES for
every private-domain user, even though only one is ever traversed.

Gate the private-domain prefix on account validation (mirroring Expensify#93399's
public-domain fix): unvalidated users keep PRIVATE_DOMAIN, validated users
get WORKSPACES, and validated users without joinable workspaces (which
auto-skip that screen) get neither. Back now resolves to the screen the
user actually came from and the step counter is accurate.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@dilshodmackbook-sketch
dilshodmackbook-sketch requested review from a team as code owners June 30, 2026 17:10
@melvin-bot
melvin-bot Bot requested review from jayeshmangwani and trjExpensify and removed request for a team and trjExpensify June 30, 2026 17:10
@melvin-bot

melvin-bot Bot commented Jun 30, 2026

Copy link
Copy Markdown

@jayeshmangwani 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 June 30, 2026 17:10

@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: a9d457b59c

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

purposeSelected: purposeSelected ?? undefined,
isMergeAccountStepSkipped: onboardingValues?.isMergeAccountStepSkipped,
isAccountValidated: !!account?.validated,
hasJoinablePolicies: Object.keys(joinablePolicies ?? {}).length > 0,

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 Exclude hidden submit policies from hasJoinablePolicies

When the only entries in JOINABLE_POLICIES are SUBMIT policies and SUBMIT_2026 is disabled, onboarding treats Workspaces as not shown: BaseOnboardingPrivateDomain counts only policies passing policyType !== SUBMIT || canUseSubmit2026, and BaseOnboardingWorkspaces renders the same filtered list. This unfiltered Object.keys check marks those hidden policies as joinable, so a validated private-domain VSB/SMB user can get an inflated flow and have Back from Employees route to an empty/skipped Workspaces screen. Please derive hasJoinablePolicies with the same visibility filter used by the Workspaces flow.

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.

Good catch, this is valid. The flow branch in BaseOnboardingPrivateDomain filters out SUBMIT policies when SUBMIT_2026 is off, so a validated VSB/SMB user whose only joinable policies are SUBMIT skips WORKSPACES — but hasJoinablePolicies was computed from an unfiltered Object.keys(...) count, adding a phantom WORKSPACES step and routing Back from EMPLOYEES to a blank screen.

Fixed in b15e80b by centralizing the visibility filter in a getVisibleJoinablePoliciesCount helper and using it in the step counter, the EMPLOYEES flow context, and the PrivateDomain branch, so all sites stay in sync. Added a unit test covering the all-SUBMIT / beta-off case.

A validated private-domain VSB/SMB user whose only joinable policies are
SUBMIT type (with the SUBMIT_2026 beta off) skips the WORKSPACES screen,
because BaseOnboardingPrivateDomain filters those policies out. But the
step counter and the EMPLOYEES back button computed hasJoinablePolicies
from an unfiltered count, adding a phantom WORKSPACES step and routing
Back from EMPLOYEES to a blank, never-visited Workspaces screen.

Centralize the visibility filter in getVisibleJoinablePoliciesCount and
use it in the step counter, the EMPLOYEES flow context, and the
PrivateDomain branch so all sites stay in sync.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@dilshodmackbook-sketch

Copy link
Copy Markdown
Contributor Author

Addressed the Codex P2 finding in b15e80b: hasJoinablePolicies now uses the same visibility filter as the Workspaces/PrivateDomain flow (SUBMIT policies are excluded while SUBMIT_2026 is off), centralized in a getVisibleJoinablePoliciesCount helper, with a unit test covering the all-SUBMIT / beta-off case. This is ready for review.

isTrackOnboardingChoice is only ever imported as the default export, so
exporting it as a named binding too tripped the knip unused-export check.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@jayeshmangwani

Copy link
Copy Markdown
Contributor

@codex review

@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: 91460260bc

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

Comment on lines +93 to +95
if (!context.isAccountValidated) {
return [ONBOARDING.PERSONAL_DETAILS, ONBOARDING.PRIVATE_DOMAIN];
}

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 Use the same validation signal as the onboarding branch

This branch treats private-domain users as unvalidated unless account.validated is true, but the screen that sends them to the previous step uses isCurrentUserValidated(loginList, session?.email) to choose WORKSPACES vs PRIVATE_DOMAIN (BaseOnboardingPersonalDetails). When the current login has a validatedDate before account.validated is populated, a user can legitimately go Personal details → Workspaces → Employees, but the Employees back route is computed as PRIVATE_DOMAIN, recreating the never-visited/blank modal path this change is trying to avoid. The step counter/back-route context needs to use the same current-login validation signal as the navigation branch.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I'm trying to verify this comment to determine whether it's a legitimate bug, but I can't reproduce any issue. I'm also not sure how validatedDate would be set in order to test this scenario.

@dilshodmackbook-sketch Are you seeing any issue when testing this flow?

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.

@jayeshmangwani you're right, I couldn't reproduce it either. This flow only runs for the signed-in primary login, and its validatedDate and account.validated reflect the same validation state, so I couldn't find a path where the two diverge before this screen renders — the back route stays in sync with navigation.

If we want to be defensive about it, I can point the step-counter context at the same isCurrentUserValidated helper the navigation already uses, so the two can never drift later. It's a one-line change — happy to add it if you think it's worth it, otherwise fine to leave as is.

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.

Went ahead and added the defensive change we discussed — the step-counter/back-route context now derives validation from isCurrentUserValidated(loginList, session?.email), the same signal BaseOnboardingPersonalDetails navigates on, instead of account.validated. Even though we couldn't reproduce a divergence, this guarantees the back route and navigation can't drift apart later. It's in b024a340b76, touching only the two context builders (useOnboardingStepCounter and BaseOnboardingEmployees). Ready for another look whenever you get a chance.

if (!context.isAccountValidated) {
return [ONBOARDING.PERSONAL_DETAILS, ONBOARDING.PRIVATE_DOMAIN];
}
return context.hasJoinablePolicies ? [ONBOARDING.PERSONAL_DETAILS, ONBOARDING.WORKSPACES] : [ONBOARDING.PERSONAL_DETAILS];

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 Keep Workspaces in the flow until it actually auto-skips

Dropping WORKSPACES whenever hasJoinablePolicies is false does not match the current validated private-domain flow: BaseOnboardingPersonalDetails still navigates validated VSB/SMB users to ONBOARDING_WORKSPACES, and BaseOnboardingWorkspaces only fetches/renders the Skip button when the list is empty; it does not auto-skip. In that no-visible-policy case, pressing Skip takes the user to Employees, but this flow makes the Employees back button go to Personal details instead of the Workspaces screen they just visited.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

We already check isPrivateDomainAndHasAccessiblePolicies in BaseOnboardingPersonalDetails before navigating, so I don't think this will cause any bug.

cc: @dilshodmackbook-sketch

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.

@jayeshmangwani agreed. Excluding WORKSPACES when there are no visible joinable policies is intentional — it uses the same getVisibleJoinablePoliciesCount visibility filter as the rest of the flow, so the back route and step counter only account for screens with something to show. That empty state is what made the back button land on a blank modal in the original report, so keeping the flow consistent with the visible screens is what avoids it. And as you noted, the isPrivateDomainAndHasAccessiblePolicies gate already scopes this to private-domain accounts, so nothing else reaches this branch.

@codecov

codecov Bot commented Jul 3, 2026

Copy link
Copy Markdown

Codecov Report

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

Files with missing lines Coverage Δ
src/hooks/useOnboardingStepCounter.ts 100.00% <100.00%> (ø)
src/libs/OnboardingUtils.ts 100.00% <100.00%> (ø)
src/libs/getOnboardingStepCounter.ts 96.82% <100.00%> (+0.10%) ⬆️
...es/OnboardingEmployees/BaseOnboardingEmployees.tsx 91.80% <100.00%> (+0.89%) ⬆️
...rdingPrivateDomain/BaseOnboardingPrivateDomain.tsx 50.00% <100.00%> (ø)
... and 144 files with indirect coverage changes

@dilshodmackbook-sketch

Copy link
Copy Markdown
Contributor Author

@jayeshmangwani fixed ✅

@jayeshmangwani

Copy link
Copy Markdown
Contributor

@dilshodmackbook-sketch Can we please fix the navigation here? When we press the back button in the header on the onboarding/employees page, we navigate back to onboarding/private-domain, but the transition animates as a forward navigation instead of a backward one.

navigation-forward.mov

…ation

The EMPLOYEES header back button called Navigation.navigate(previousRoute),
which plays a forward (push) transition even though it returns the user to a
screen they came from (e.g. PRIVATE_DOMAIN). Switch to Navigation.goBack so the
transition animates as a backward pop, matching every other onboarding screen.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@dilshodmackbook-sketch

dilshodmackbook-sketch commented Jul 3, 2026

Copy link
Copy Markdown
Contributor Author

Good catch, fixed. The back button was calling Navigation.navigate(previousRoute), which always plays a forward (push) transition even though we're sending the user back to a screen they already came from. Switched it to Navigation.goBack(previousRoute) so it animates as a backward pop, consistent with the other onboarding screens.

Screen.Recording.2026-07-03.at.15.37.42.mov

dilshodmackbook-sketch and others added 2 commits July 7, 2026 12:57
…nboarding-back-button

# Conflicts:
#	src/libs/OnboardingUtils.ts
Use isCurrentUserValidated(loginList, session?.email) for the private-domain
back-route context, matching the signal BaseOnboardingPersonalDetails branches
on, so the step counter and navigation can never drift.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@jayeshmangwani

Copy link
Copy Markdown
Contributor

Reviewer Checklist

  • I have verified the author checklist is complete (all boxes are checked off).
  • I verified the correct issue is linked in the ### Fixed Issues section above
  • I verified testing steps are clear and they cover the changes made in this PR
    • I verified the steps for local testing are in the Tests section
    • I verified the steps for Staging and/or Production testing are in the QA steps section
    • I verified the steps cover any possible 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 checked that screenshots or videos are included for tests on all platforms
  • I included screenshots or videos for tests on all platforms
  • I verified that the composer does not automatically focus or open the keyboard on mobile unless explicitly intended. This includes checking that returning the app from the background does not unexpectedly open the keyboard.
  • I verified tests pass on all platforms & I tested again on:
    • Android: HybridApp
    • Android: mWeb Chrome
    • iOS: HybridApp
    • iOS: mWeb Safari
    • MacOS: Chrome / Safari
  • If there are any errors in the console that are unrelated to this PR, I either fixed them (preferred) or linked to where I reported them in Slack
  • I verified proper code patterns were followed (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 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)
  • If a new code pattern is added I verified it was agreed to be used by multiple Expensify engineers
  • I verified that this PR follows the guidelines as stated in the Review Guidelines
  • I verified other components that can be impacted by these changes have been tested, and I retested again (i.e. if the PR modifies a shared library or component like Avatar, I verified the components using Avatar have been tested & I retested again)
  • If a new component is created I verified that:
    • A similar component doesn't exist in the codebase
    • All props are defined accurately and each prop has a /** comment above it */
    • The file is named correctly
    • The component has a clear name that is non-ambiguous and the purpose of the component can be inferred from the name alone
    • The only data being stored in the state is data necessary for rendering and nothing else
    • For Class Components, any internal methods passed to components event handlers are bound to this properly so there are no scoping issues (i.e. for onClick={this.submit} the method this.submit should be bound to this in the constructor)
    • Any internal methods bound to this are necessary to be bound (i.e. avoid this.submit = this.submit.bind(this); if this.submit is never passed to a component event handler like onClick)
    • All JSX used for rendering exists in the render method
    • The component has the minimum amount of code necessary for its purpose, and it is broken down into smaller components in order to separate concerns and functions
  • 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 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.
  • For any bug fix or new feature in this PR, I verified that sufficient unit tests are included to prevent regressions in this 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.
  • I have checked off every checkbox in the PR reviewer checklist, including those that don't apply to this PR.

Screenshots/Videos

Android: HybridApp
Android.mov
Android: mWeb Chrome
mweb-chrome.mov
iOS: HybridApp
iOS.mov
iOS: mWeb Safari
mweb-safari.mov
MacOS: Chrome / Safari
web.mov

@jayeshmangwani jayeshmangwani left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM 🚀

@melvin-bot
melvin-bot Bot requested a review from mollfpr July 8, 2026 17:10
@dilshodmackbook-sketch

Copy link
Copy Markdown
Contributor Author

@mollfpr this is approved by @jayeshmangwani and all checks are green, so it's ready for your final review whenever you get a chance. Thanks!

@mollfpr
mollfpr merged commit 7b907c2 into Expensify:main Jul 9, 2026
35 of 36 checks passed
@github-actions

github-actions Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

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

@OSBotify

OSBotify commented Jul 9, 2026

Copy link
Copy Markdown
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.

@OSBotify

OSBotify commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

🚀 Deployed to staging by https://github.com/mollfpr in version: 9.4.32-0 🚀

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

@MelvinBot

Copy link
Copy Markdown
Contributor

🤖 No help site changes required.

I reviewed the changes in this PR against the help site articles under docs/articles, and no updates are needed.

Why: This PR is a purely internal bug fix to the onboarding navigation state machine — it corrects the back-button destination and step counter on the How many employees do you have? screen for private-domain VSB/SMB users. Specifically it:

  • Gates the private-domain step prefix (PRIVATE_DOMAIN vs WORKSPACES) on account validation + joinable-workspace visibility, removing a phantom step.
  • Centralizes joinable-policy counting in getVisibleJoinablePoliciesCount.
  • Switches Navigation.navigateNavigation.goBack for the back action.

There is no user-facing product change here — no new features, screens, copy, settings, tabs, or buttons. The help site documents how to use Expensify features, and it does not document the internal routing/step-count behavior of the sign-up onboarding wizard (the affected screens are transient sign-up steps, not documented product surfaces). A search of docs/articles surfaced no article describing this flow's back-navigation or step counter, so there is nothing to update.

If a reviewer believes a specific help article should cover part of this flow, point me to it and I'll take another look.


@dilshodmackbook-sketch — no draft help site PR was created because no documentation changes are warranted for this internal navigation fix. Let me know if you'd like me to reconsider a specific article.

@OSBotify

Copy link
Copy Markdown
Contributor

🚀 Deployed to production by https://github.com/grgia in version: 9.4.32-3 🚀

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

Bundle Size Analysis (Sentry):

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.

5 participants