fix(dashboard): keep the onboarding plan step up during a billing refetch

Closed
FI
2d ago
+340-96

Follow-up to #1096, stacked on izadoesdev/onboarding-plan-step-release so this diff is just the fix.

Bug

offersPlans requires !billing.isLoading before ChoosePlan renders:

const offersPlans =
	!(isSelfHosted || isDashboardE2E || billing.isLoading || billing.isError) &&
	billing.canUserUpgrade &&
	isOn("onboarding-plan-step");

if (step === "plan" && websiteId && offersPlans) {
	return <ChoosePlan ... />;
}

On a hard reload while sitting on ?step=plan (e.g. returning from Stripe checkout), billing starts from a cold cache, so billing.isLoading is briefly true. During that window offersPlans is false, so the gate falls through and renders SetupChecklist instead — for however long the billing fetch takes — before flipping to ChoosePlan once it resolves. Someone coming back from paying sees the setup checklist flash before the plan screen shows up.

Fix

Split the static eligibility check (self-hosted, e2e, feature flag — none of which depend on billing's network state) from the full offersPlans check used to decide whether to route into the plan step in the first place. Add showPlanStep, which renders ChoosePlan optimistically while billing is still loading, and only falls back to the checklist once billing actually resolves and says the user can't upgrade:

const showPlanStep =
	step === "plan" &&
	Boolean(websiteId) &&
	planStepFlagEligible &&
	(billing.isLoading || (!billing.isError && billing.canUserUpgrade));

ChoosePlan already tolerates billing.isLoading gracefully (it shows "Your setup is saved" instead of the plan name), so this doesn't need any change inside that component.

offersPlans itself is untouched in meaning — still used as-is for the "Continue" button decision after setup.

Note

While tracing this I noticed isDashboardE2E unconditionally disables the plan step for the whole e2e run (it's a single process-wide env flag, not per-test), so the existing e2e suite can't actually reach ChoosePlan regardless of this fix. Didn't try to solve that here — flagging it since the original PR description mentions e2e coverage for "reload on the plan step," which doesn't look reachable under the current gating. No automated test added for this specific fix as a result; verified by tracing the render logic by hand plus tsc --noEmit clean across all 37 packages.

Disclosure: implemented with AI assistance (Claude Code); verified by manually tracing both render paths (fresh reload vs. billing already cached) against the actual component logic before submitting.


Summary by cubic

Stops the onboarding flow from flashing SetupChecklist when resuming at ?step=plan, such as returning from Stripe checkout. Previously ChoosePlan only rendered after billing finished fetching, so a cold billing state briefly fell through to the checklist; now the plan step renders optimistically while billing loads, and only falls back if billing resolves and says the user can't upgrade. offersPlans is unchanged and still drives the "Continue" button behavior.

Note: isDashboardE2E gates the plan step off for the whole e2e run (it's a process-wide env flag, not per-test), so the existing e2e suite can't actually reach ChoosePlan, and no automated test was added for this fix. Verified by hand-tracing the render paths and a clean tsc --noEmit.