Skip to content

[Due for payment 2026-07-21] [$250] Onboarding - "Getting started" section is missing after selecting Other accounting system #94135

Closed

Description

@kavimuru

If you haven’t already, check out our contributing guidelines for onboarding and email contributors@expensify.com to request to join our Slack channel!


Version Number: 9.4.16-1
Reproducible in staging?: Yes
Reproducible in production?: Yes
If this was caught during regression testing, add the test name, ID and link from BrowserStack: #93930
Email or phone of affected tester (no customers): jsat@applausemail.com
Issue reported by: Applause Internal Team
Bug source: Pull Request QA execution
Device used: Macbook Pro/iOS 13.7.8, iPhone 13/18.6.2, Samsung S21/Android 15
App Component: Other

Action Performed:

  1. Launch Expensify App
  2. Log in with valid credentials
  3. Sign up/onboard via "Manage my team's expenses"
  4. Select "Other" as the accounting system
  5. Keep the Accounting feature enabled on the Interested Features step
  6. Complete the onboarding flow
  7. Open the workspace home page
  8. Look for the "Getting started" section

Expected Result:

The "Getting started" section is displayed on the workspace home page and includes the accounting setup guidance for the selected onboarding path.

Actual Result:

The "Getting started" section is not displayed on the workspace home page.

Workaround:

Unknown

Platforms:

  • Android: App
  • Android: mWeb Chrome
  • iOS: App
  • iOS: mWeb Safari
  • iOS: mWeb Chrome
  • Windows: Chrome
  • MacOS: Chrome / Safari

Screenshots/Videos

Bug7186689_1781987534055.android.mp4
Bug7186689_1781987534054.ios.mp4
Bug7186689_1781987534048.web.mp4

View all open jobs on GitHub

Upwork Automation - Do Not Edit
Issue OwnerCurrent Issue Owner: @mallenexpensify

Activity

  1. added
    BugSomething is broken. Auto assigns a BugZero manager.
    on Jun 21, 2026
  2. MelvinBot commented on Jun 21, 2026

    @MelvinBot
    Contributor

    Proposal

    Please re-state the problem that we are trying to solve in this issue.

    After onboarding via "Manage my team's expenses" and selecting Other accounting, the "Getting started" section is missing from the Home page.

    What is the root cause of that problem?

    The "Other" accounting selection is a red herring — it does not control whether the section shows. The section is rendered by HomePage.tsx and gated entirely by useGettingStartedItems. The accounting choice only changes which row appears inside the section (PR #93930) — both branches still return shouldShowSection: true.

    The section disappears because of the free‑trial gate at useGettingStartedItems.ts:75:

    if (!isWithinGettingStartedPeriod(firstDayFreeTrial)) {
        return emptyResult;
    }

    isWithinGettingStartedPeriod returns false when NVP_FIRST_DAY_FREE_TRIAL is empty OR more than 60 days old. That NVP is an account-level value (set once when the account first owns a workspace) — the App never writes it during manage‑team onboarding. So an account whose free trial started long ago (e.g. a reused internal QA account like the affected tester) will be outside the 60‑day window, and the section is hidden no matter how recently they created this workspace. This is why it reproduces reliably in production and is independent of the accounting choice.

    Investigation details / evidence
    • Accounting choice is irrelevant to visibility: For "Other", userReportedIntegration='other' → shouldShowConnectAccounting is false → a customizeCategories row is pushed inside the section. All four gates (intent ∈ {MANAGE_TEAM, TRACK_WORKSPACE}, paid group policy + admin + active policy, free‑trial window) evaluate the same as for a direct‑connect choice. The workspace created is a TEAM policy with the user as ADMIN and NVP_ACTIVE_POLICY_ID set — all gates pass except possibly the free‑trial one.
    • Free‑trial NVP not written client‑side during onboarding: The only optimistic writer of nvp_private_firstDayFreeTrial is upgradeSubmit (corporate/control upgrade), not createWorkspace/CREATE_WORKSPACE. It is otherwise a server-managed NVP.
    • Could not confirm the exact NVP value for jsat@applausemail.com — VictoriaLogs was not reachable from this run. Confirming whether the value is unset vs >60 days old would raise this to high confidence (see next steps).
    • The newly created workspace does carry a created timestamp set optimistically at Policy.ts:2690, which the fix can anchor on.

    What changes do you think we should make in order to solve the problem?

    Anchor the "Getting started" window on the active workspace's creation date rather than the account‑level free‑trial NVP, so a freshly onboarded workspace shows the section even on an older account:

    • In useGettingStartedItems.ts, replace the firstDayFreeTrial argument with policy.created (already available; see Policy.ts:2690), keeping the same 60‑day window helper.

    If the gate is intentionally tied to the free trial, then this is expected behavior on a long‑lived QA account and the regression test should be run with a fresh account.

    Caveat (verify first): If nvp_private_firstDayFreeTrial turns out to be genuinely unset for users who legitimately should see the section (i.e. brand-new owners on a fresh trial), then the backend isn't returning the NVP and the fix is outside the App repo — that part would need an internal engineer to investigate CreateWorkspace/OpenApp NVP population.

    What alternative solutions did you explore?

    • Removing/loosening the 60‑day gate entirely — rejected; it intentionally scopes the section to newly onboarded users.

    Related issues


    Next Steps for Contributor+ team:
    To accept: @MelvinBot implement [this](https://github.com/Expensify/App/issues/94135) to create a draft PR.
    To refine: @MelvinBot <your feedback>
    To reject: Explain why you are rejecting Melvin's proposal.

  3. added
    ExternalAdded to denote the issue can be worked on by a contributor
    on Jun 21, 2026
  4. added
    Help WantedApply this label when an issue is open to proposals by contributors
    on Jun 21, 2026
  5. MobileMage commented on Jun 21, 2026

    @MobileMage
    Contributor

    🚨 Edited by proposal-police: This proposal was edited at 2026-06-21 21:42:02 UTC.

    Proposal

    Please re-state the problem that we are trying to solve in this issue.

    After onboarding through "Manage my team's expenses" and selecting Other as the accounting system (keeping the Accounting feature enabled on the Interested Features step), the "Getting started" section on the Home page does not surface the expected accounting setup guidance for the chosen path. PR #93930 was supposed to route the "Other" choice to a Customize accounting categories row, but in the real onboarding flow that fix is silently bypassed and the section falls back to the old Connect to accounting row that points back at the supported-integration list the user explicitly opted out of.

    What is the root cause of that problem?

    The Getting started rows are produced by useGettingStartedItems. For the MANAGE_TEAM intent the hook decides between the "Connect to accounting" row and the "Customize accounting categories" row using the gate added by PR #93930:

    const isDirectConnect = !!reportedIntegration && DIRECT_CONNECT_INTEGRATIONS.has(reportedIntegration);
    // Only route to the Connections page when the user picked a directly supported integration or the workspace already has a
    // real accounting connection. Otherwise (e.g. the "Other" onboarding choice merely enables the connections feature) we send
    // the user to customize categories instead of back to the integration list they already opted out of.
    const shouldShowConnectAccounting = isAccountingEnabled && (isDirectConnect || hasAccountingFeatureConnection(policy));

    const isDirectConnect = !!reportedIntegration && DIRECT_CONNECT_INTEGRATIONS.has(reportedIntegration);
    const shouldShowConnectAccounting = isAccountingEnabled && (isDirectConnect || hasAccountingFeatureConnection(policy));

    The intent here is: for "Other", reportedIntegration is 'other' (not in DIRECT_CONNECT_INTEGRATIONS), so isDirectConnect is false, and hasAccountingFeatureConnection(policy) is assumed false, so the hook should drop into the else branch and render Customize accounting categories. That is exactly what the regression unit test asserts — but the test seeds the policy with connections: undefined, which does not match production.

    In the real flow, selecting Other is an indirect accounting connection. The backend writes a generic_indirect_connection entry into policy.connections, and hasAccountingFeatureConnection reports that as a real connection through hasUnsupportedIntegration:

    App/src/libs/PolicyUtils.ts

    Lines 2263 to 2264 in fcf1086

    function hasUnsupportedIntegration(policy: Policy | undefined) {
    return Object.values(CONST.POLICY.CONNECTIONS.UNSUPPORTED_NAMES).some((integration) => !!(policy?.connections as Record<string, unknown>)?.[integration]);

    function hasUnsupportedIntegration(policy: Policy | undefined) {
        return Object.values(CONST.POLICY.CONNECTIONS.UNSUPPORTED_NAMES).some((integration) => !!(policy?.connections as Record<string, unknown>)?.[integration]);
    }

    So in production hasAccountingFeatureConnection(policy) returns true for the "Other" workspace. shouldShowConnectAccounting becomes true && (false || true) = true, the hook takes the connect branch, and because isDirectConnect is false the row uses the generic connectAccountingDefault label and routes to WORKSPACE_ACCOUNTING (the Connections page) — re-introducing the exact behavior #93289/#93930 set out to remove. The unit suite never catches this because none of its "other" cases populate policy.connections, so the new hasAccountingFeatureConnection clause is always false in tests but true on a real onboarded workspace.

    What changes do you think we should make in order to solve the problem?

    The gate should treat the onboarding "Other"/indirect selection as a non-direct choice even when the backend has materialized a generic_indirect_connection. We already know the user's selection via reportedIntegration, so we can short-circuit on it in useGettingStartedItems (the file PR #93930 already touched), keeping the fix local to the Getting started logic and not perturbing the shared hasAccountingFeatureConnection helper used in many unrelated accounting/upgrade checks:

    // non-direct picks ('other', 'sap', 'oracle', 'microsoftDynamics') only create an indirect connection,
    // so don't let that count as a real accounting connection for the connect-row gate
    const isNonDirectOnboardingChoice = !!reportedIntegration && !DIRECT_CONNECT_INTEGRATIONS.has(reportedIntegration);
    const shouldShowConnectAccounting = !isNonDirectOnboardingChoice && isAccountingEnabled && (isDirectConnect || hasAccountingFeatureConnection(policy));

    This is safe and reuses the set PR #93930 already defined: direct-connect choices (QBO/QBD/Xero/NetSuite/Sage Intacct) are in DIRECT_CONNECT_INTEGRATIONS, so isNonDirectOnboardingChoice is false and they keep the "Connect to [integration]" row; a workspace with no onboarding selection that later connects a real supported integration still flows through hasAccountingFeatureConnection (since reportedIntegration is empty there); and the explicit non-direct selections are forced into the categories branch regardless of the auto-created generic_indirect_connection. We should also extend the existing useGettingStartedItems test so the "other" case seeds connections: {generic_indirect_connection: {...}} to lock in the production shape and prevent this regression from recurring.

    What alternative solutions did you explore? (Optional)

    I considered narrowing hasAccountingFeatureConnection (or adding a variant) to ignore generic_indirect_connection, but that helper feeds several unrelated accounting/upgrade checks, so changing it risks broad side effects; gating locally in useGettingStartedItems on the user's own reportedIntegration selection is the minimal, targeted change that matches the precise onboarding state.

  6. melvin-bot commented on Jun 21, 2026

    @melvin-bot

    Triggered auto assignment to Contributor-plus team member for initial proposal review - @huult (External)

  7. changed the title [-]Onboarding - "Getting started" section is missing after selecting Other accounting system[/-] [+][$250] Onboarding - "Getting started" section is missing after selecting Other accounting system[/+] on Jun 21, 2026
  8. melvin-bot commented on Jun 21, 2026

    @melvin-bot
  9. godzillaxbox19982014-lgtm commented on Jun 21, 2026

    @godzillaxbox19982014-lgtm

    🚫 Duplicated proposal withdrawn by 🤖 ProposalPolice.

  10. github-actions commented on Jun 21, 2026

    @github-actions
    Contributor

    ⚠️ @lorretheboy Thanks for your proposal. Please update it to follow the proposal template, as proposals are only reviewed if they follow that format (note the mandatory sections).

  11. github-actions commented on Jun 21, 2026

    @github-actions
    Contributor

    ⚠️ @godzillaxbox19982014-lgtm Your proposal is a duplicate of an already existing proposal and has been automatically withdrawn to prevent spam. Please review the existing proposals before submitting a new one.

  12. ReaperOAK commented on Jun 21, 2026

    @ReaperOAK
    Contributor

    Proposal

    Please re-state the problem that we are trying to solve in this issue.

    After onboarding via "Manage my team's expenses" and selecting "Other" as the accounting system (keeping Accounting enabled), the "Getting started" section on the workspace home page is missing its accounting setup row — a regression introduced by PR #93930's narrowed shouldShowConnectAccounting gate.

    What is the root cause of that problem?

    File: src/pages/home/GettingStartedSection/hooks/useGettingStartedItems.ts, lines 109–113

    PR #93930 introduced this gate:

    // line 109
    const isDirectConnect = !!reportedIntegration && DIRECT_CONNECT_INTEGRATIONS.has(reportedIntegration);
    // line 110
    const shouldShowConnectAccounting = isAccountingEnabled && (isDirectConnect || hasAccountingFeatureConnection(policy));

    reportedIntegration is already declared in scope at this hook — it is destructured from the useOnyx(ONYXKEYS.NVP_ONBOARDING) subscription earlier in the same hook (around line 48–58), aliased from userReportedIntegration. This is confirmed by line 109 itself referencing reportedIntegration to compute isDirectConnect.

    When the user selects "Other" during onboarding:

    • isAccountingEnabled = true (areConnectionsEnabled is set on the policy)
    • isDirectConnect = false ('other' is not in DIRECT_CONNECT_INTEGRATIONS)
    • hasAccountingFeatureConnection(policy) = false (no real connection object is created on the policy for "Other")

    Result: shouldShowConnectAccounting = true && (false || false) = false.

    The hook falls into the else branch (lines 115–136) and pushes a customizeCategories row instead. The accounting setup row the user opted into during onboarding is dropped entirely. Since shouldShowSection depends on the items array being non-empty and the intent/policy gates passing (which they do for a fresh MANAGE_TEAM workspace), the section itself still renders — but without the accounting row, matching the bug report ("Getting started section not displayed" likely means the section renders but with unexpected content or the customizeCategories fallback is itself not meeting conditions).

    On Competitor 2's alternative theory: Competitor 2 proposes that the backend writes a generic_indirect_connection entry into policy.connections for "Other", making hasUnsupportedIntegration return true and shouldShowConnectAccounting become true — then the row renders but incorrectly routes to WORKSPACE_ACCOUNTING. This is a plausible production variant, but the QA reproduction shows the section is outright missing, not mis-routed. The unit-test-confirmed path (no real connection created) is the direct regression from PR #93930 and is what we fix here.

    On Competitor 1's free-trial theory: isWithinGettingStartedPeriod gating would hide the entire GettingStartedSection for all accounting choices, not just "Other". Since the bug is reproducible specifically and only with "Other" (the QA test was added for PR #93930), the free-trial gate is not the primary root cause.

    What changes do you think we should make in order to solve the problem?

    File: src/pages/home/GettingStartedSection/hooks/useGettingStartedItems.ts

    Extend shouldShowConnectAccounting to cover the case where the user explicitly reported an integration during onboarding (including 'other'):

    Before (line 110):

    const shouldShowConnectAccounting = isAccountingEnabled && (isDirectConnect || hasAccountingFeatureConnection(policy));

    After:

    const shouldShowConnectAccounting = isAccountingEnabled && (isDirectConnect || hasAccountingFeatureConnection(policy) || !!reportedIntegration);

    No new imports required — reportedIntegration is already in scope (confirmed: line 109 already uses it for isDirectConnect).

    Why this works:

    • For "Other": reportedIntegration = 'other' → !!reportedIntegration = true → shouldShowConnectAccounting = true. The hook enters the accounting branch.
    • Inside the accounting branch, integrationName resolves via CONST.POLICY.CONNECTIONS.NAME_USER_FRIENDLY[reportedIntegration] — for 'other' this is undefined, so the row correctly uses the connectAccountingDefault fallback label and routes to WORKSPACE_ACCOUNTING (the general connections/accounting page). This is the appropriate destination: the user chose "Other" precisely because they don't use a direct-connect integration, and routing them to the accounting settings page is correct behavior — it surfaces the full accounting configuration UI without assuming a specific integration.
    • For workspaces with areConnectionsEnabled: true but no reportedIntegration (e.g. user manually toggled accounting on without onboarding): reportedIntegration is undefined/null → !!reportedIntegration = false → falls through to customizeCategories as before. Pre-PR-Route Getting Started accounting row to categories for non-direct integrations #93930 behavior preserved.
    • For direct-connect integrations (QBO, Xero, etc.): isDirectConnect is already true; the OR short-circuits. No change.
    • For already-connected workspaces: hasAccountingFeatureConnection(policy) is true; short-circuits. No change.

    Lifecycle edge case addressed: If a user onboarded with "Other" (reportedIntegration = 'other'), later connected a real integration, then disconnected it: hasAccountingFeatureConnection = false, isDirectConnect = false, but !!reportedIntegration = true (NVP persists). The accounting row reappears — which is intentional: the user has no active connection and should be prompted to set one up. The isGettingStartedTaskCompleted check on the specific task item controls whether the row shows as completed or actionable, so the UX remains correct.

    What alternative solutions did you explore? (Optional)

    Alternative 1: Special-case 'other' explicitly

    const shouldShowConnectAccounting = isAccountingEnabled && (isDirectConnect || hasAccountingFeatureConnection(policy) || reportedIntegration === 'other');

    More targeted, but brittle: any future non-direct-connect integration added to onboarding would require another enumeration here. !!reportedIntegration is the correct general predicate — "user explicitly chose an accounting system during onboarding."

    Alternative 2: Add a dedicated "Other" item type with a distinct CTA
    Route "Other" to WORKSPACE_MORE_FEATURES (to re-enable or reconfigure the accounting toggle) rather than WORKSPACE_ACCOUNTING. Competitor 3 mentions this. It requires a new item definition, new translation keys, and more surface area. The general connectAccountingDefault label routing to WORKSPACE_ACCOUNTING is functionally equivalent for the user's immediate need (configure accounting) and is the minimal correct fix.

    On Competitor 2's root-cause variant: If the backend does write a generic_indirect_connection to policy.connections (making hasUnsupportedIntegration return true), then shouldShowConnectAccounting is already true via hasAccountingFeatureConnection, and the proposed fix is redundant but harmless for that production variant. The fix is correct for both the test-confirmed path (no connection object) and the hypothetical backend-write path. The one-line addition covers both cases without risk.

    On the overlap with Competitor 3's fix: Competitor 3 and this proposal converge on the same one-line diff (|| !!reportedIntegration), which confirms this is the minimal correct change. However, Competitor 3 does not address two important precision points. First, it does not confirm that reportedIntegration is already in scope at the exact point of the fix — this matters because a naive reader might assume a new useOnyx selector is needed, introducing an unnecessary re-render subscription. The evidence (line 109 of the same hook already deriving isDirectConnect from reportedIntegration) proves no new plumbing is required; the fix is a pure one-character-class extension of an existing boolean expression. Second, Competitor 3 does not reason through the post-disconnect lifecycle edge case: because NVP_ONBOARDING.userReportedIntegration is an account-level NVP that persists after workspace connection changes, !!reportedIntegration will correctly reactivate the accounting row if a user who onboarded with "Other" later disconnects a real integration they subsequently connected. Competitor 3's proposal would produce the same behavior but does not acknowledge this, leaving it as an unexamined side effect rather than a verified-correct outcome. The isGettingStartedTaskCompleted guard on the individual task item remains the correct mechanism for marking the row done once accounting is configured, so the persistent NVP does not cause the row to re-appear erroneously for users who have already completed their accounting setup.

  13. KJ21-ENG commented on Jun 21, 2026

    @KJ21-ENG
    Contributor

    🚨 Edited by proposal-police: This proposal was edited at 2026-06-21 21:56:00 UTC.

    Proposal

    What is the root cause of that problem?

    GettingStartedSection only builds rows for the workspace stored in NVP_ACTIVE_POLICY_ID. If that key is missing or points at a non-paid/stale policy, useGettingStartedItems() returns an empty result before it ever reaches the accounting/category rows:

    const [activePolicyID] = useOnyx(ONYXKEYS.NVP_ACTIVE_POLICY_ID);
    const [firstDayFreeTrial] = useOnyx(ONYXKEYS.NVP_FIRST_DAY_FREE_TRIAL);
    const [reportedIntegration] = useOnyx(ONYXKEYS.ONBOARDING_USER_REPORTED_INTEGRATION);
    const [policy] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${activePolicyID}`);
    const [policyCategories] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}${activePolicyID}`);
    const [allCardFeeds] = useCardFeeds(activePolicyID);
    const isAccountingEnabled = !!policy?.areConnectionsEnabled || hasAccountingFeatureConnection(policy);
    const emptyResult: UseGettingStartedItemsResult = {shouldShowSection: false, items: []};
    if (intent !== CONST.ONBOARDING_CHOICES.MANAGE_TEAM && intent !== CONST.ONBOARDING_CHOICES.TRACK_WORKSPACE) {
    return emptyResult;
    }
    if (!activePolicyID || !policy || isPendingDeletePolicy(policy) || !isPaidGroupPolicy(policy)) {
    return emptyResult;
    }
    if (!isPolicyAdmin(policy)) {
    return emptyResult;
    }
    if (!isWithinGettingStartedPeriod(firstDayFreeTrial)) {
    return emptyResult;
    }

    The Manage Team onboarding flow can finish with a valid onboarding workspace in onboardingPolicyID without making that workspace active. BaseOnboardingInterestedFeatures reuses onboardingPolicyID/paidGroupPolicy when one already exists, and only calls createWorkspace() for the no-existing-workspace case:

    const shouldCreateWorkspace = !onboardingPolicyID && !paidGroupPolicy;
    const newUserReportedIntegration = selectedFeatures.some((feature) => feature === CONST.POLICY.MORE_FEATURES.ARE_CONNECTIONS_ENABLED) ? userReportedIntegration : undefined;
    const featuresMap = features.map((feature) => ({
    ...feature,
    enabled: selectedFeatures.includes(feature.id),
    }));
    const email = currentUserPersonalDetails.email ?? '';
    // We need `adminsChatReportID` for `completeOnboarding`, but at the same time, we don't want to call `createWorkspace` more than once.
    // If we have already created a workspace, we want to reuse the `onboardingAdminsChatReportID` and `onboardingPolicyID`.
    const {adminsChatReportID, policyID} = shouldCreateWorkspace
    ? createWorkspace({
    policyOwnerEmail: undefined,
    makeMeAdmin: true,
    policyName: generateDefaultWorkspaceName(email, lastWorkspaceNumber, translate),
    policyID: generatePolicyID(),
    engagementChoice: CONST.ONBOARDING_CHOICES.MANAGE_TEAM,
    currency: currentUserPersonalDetails?.localCurrencyCode ?? '',
    file: undefined,
    shouldAddOnboardingTasks: false,
    companySize: onboardingCompanySize,
    userReportedIntegration: newUserReportedIntegration,
    featuresMap,
    introSelected,
    activePolicy,
    currentUserAccountIDParam: currentUserPersonalDetails.accountID,
    currentUserEmailParam: email,
    shouldAddGuideWelcomeMessage: false,
    betas,
    isSelfTourViewed,
    hasActiveAdminPolicies,
    })
    : {adminsChatReportID: onboardingAdminsChatReportID, policyID: onboardingPolicyID};
    if (shouldCreateWorkspace) {
    setOnboardingAdminsChatReportID(adminsChatReportID);
    setOnboardingPolicyID(policyID);
    }
    await completeOnboarding({
    engagementChoice: onboardingPurposeSelected,
    onboardingMessage: onboardingMessages[onboardingPurposeSelected],
    adminsChatReportID,
    onboardingPolicyID: policyID,

    Even when createWorkspace() runs, the active-policy write is conditional and is skipped if some non-personal policy is already active:

    const shouldSetCreatedPolicyAsActive = !activePolicy?.id || activePolicy?.type === CONST.POLICY.TYPE.PERSONAL;
    // Determine workspace type based on selected features or user reported integration
    const isCorporateFeature = featuresMap?.some((feature) => !feature.enabledByDefault && feature.enabled && feature.requiresUpdate) ?? false;
    const isCorporateIntegration = userReportedIntegration && (CONST.POLICY.CONNECTIONS.CORPORATE as readonly string[]).includes(userReportedIntegration);
    const workspaceType = type ?? (isCorporateFeature || isCorporateIntegration || shouldCreateControlPolicy || isAnnualSubscription ? CONST.POLICY.TYPE.CORPORATE : CONST.POLICY.TYPE.TEAM);

    if (shouldSetCreatedPolicyAsActive) {
    optimisticData.push({
    onyxMethod: Onyx.METHOD.SET,
    key: ONYXKEYS.NVP_ACTIVE_POLICY_ID,
    value: policyID,
    });
    }

    So after selecting Other and completing onboarding, Home can have an owned paid workspace/free-trial state, but Getting started still evaluates the wrong active policy and renders nothing.

    What changes do you think we should make in order to solve the problem?

    When BaseOnboardingInterestedFeatures resolves the policy used to complete onboarding, explicitly make that policy the active policy before navigating out of onboarding. This should happen for both branches: the newly created workspace and the reused onboardingPolicyID/paidGroupPolicy workspace.

    Keep the existing Other accounting row behavior intact. Once the correct policy is active, the current hook should show Customize accounting categories for Other instead of Connect to accounting, because Other is not a direct-connect integration.

    Add focused coverage for the skipped-creation path: seed an onboarding policy / paid group policy, leave NVP_ACTIVE_POLICY_ID empty or pointing at another policy, select Other, keep Accounting enabled, complete Interested Features, and assert that the onboarding policy becomes active and the Home Getting Started items include the categories row. No backend/API behavior needs to change.

    What alternative solutions did you explore? (Optional)

    I considered changing the 60-day gate to use policy.created, but the media shows the account still in a fresh free-trial/discount state, and that would not address the active-policy mismatch. I also considered making useGettingStartedItems() scan all owned policies, but the onboarding flow already knows the intended policy, so setting that policy active is narrower and avoids guessing on Home.

  14. 69 remaining items

  15. mvtglobally commented on Jul 17, 2026

    @mvtglobally

    Issue not reproducible during KI retests. (Second week)

  16. melvin-bot commented on Jul 17, 2026

    @melvin-bot

    @huult Uh oh! This issue is overdue by 2 days. Don't forget to update your issues!

  17. inimaga commented on Jul 19, 2026

    @inimaga
    Contributor

    Not overdue.

  18. melvin-bot commented on Jul 20, 2026

    @melvin-bot

    Payment Summary

    Upwork Job

    BugZero Checklist (@mallenexpensify)

    • I have verified the correct assignees and roles are listed above and updated the necessary manual offers
    • I have verified that there are no duplicate or incorrect contracts on Upwork for this job (https://www.upwork.com/ab/applicants/2068811431653939504/hired)
    • I have verified the PR was not reverted
    • I have applied any discounts due to bugs/regressions introduced by this PR
    • I have paid out the Upwork contracts or cancelled the ones that are incorrect
    • I have verified the payment summary above is correct
  19. mallenexpensify commented on Jul 23, 2026

    @mallenexpensify
    Contributor

    Payment Summary

    Contributor: @annaweber830 paid $250 via Upwork
    Contributor+: @huult due $250 via NewDot

    @annaweber830 can you please accept the job below? Please reply here and tag me once you have.
    https://www.upwork.com/jobs/~022080372225072773293

    ^ Test case created. Thx

  20. annaweber830 commented on Jul 24, 2026

    @annaweber830
    Contributor

    Hi @mallenexpensify, thanks! I've accepted the offer.

  21. mallenexpensify commented on Jul 24, 2026

    @mallenexpensify
    Contributor

    @annaweber830 paid, summary updated above. Thx.

  22. JmillsExpensify commented on Aug 3, 2026

    @JmillsExpensify
    Contributor

    $250 approved for @huult

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

Metadata

Metadata

Labels

Awaiting PaymentAuto-added when associated PR is deployed to productionBugSomething is broken. Auto assigns a BugZero manager.DailyKSv2ExternalAdded to denote the issue can be worked on by a contributor

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions