fix(GRO-2099): show loading state during CustomerPortal SSO bridge bootstrap #44
Reference in New Issue
Block a user
Delete Branch "flea/gro-2099-fix-authed-portal-nav"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Root cause
Dashboard.tsx:194runs!sessionId && !isImpersonating && !getDevUser()and redirects to/loginifsessionIdis null. For SSO customers, the CustomerPortal's useEffect has to call/api/auth/get-sessionthen/api/portal/session-from-authto populateportalSessionId. During that 100-300ms bootstrap window,sessionIdis null and the Dashboard's guard fires — redirecting the user to/login.App.tsxadditionally returnednullat/loginfor authenticated users (showCustomerPortalis false at/login), leaving a blank React root even when the redirect target was /login itself.Reproduction (verified on UAT image
2026.06.01-ec29f71)about:blank, complete customer SSO asuat-customer.browser_navigateto/portal./login, React rootinnerHTML.length === 0./portal, dashboard renders with customer name.Fix
CustomerPortal.tsx: show arole="status"'Loading…' state while!initComplete. The portal chrome and its child sections only mount once the bootstrap has resolved.App.tsx: at/loginwith a valid session, redirect to/. The!authDisabled && !sessionearly-return now only fires at/login, so other portal routes defer the auth check toCustomerPortal(where the SSO bridge runs).UAT_PLAYBOOK.md: add §5.27 with 8 cases covering the bug, the loading state, the /login auto-redirect, the unauth fallback, and the groomer / impersonation non-regressions.src/__tests__/portal.test.tsx: regression test that asserts the loading state is shown during the bridge and the portal nav is NOT in the DOM mid-bootstrap.Verification
pnpm typecheck: clean.pnpm test: 137/137 pass (1 new GRO-2099 regression test added).Refs: GRO-2099, GRO-1859, GRO-2026, GRO-1867.