feat(GRO-2359): route Authentik new-SSO users into OOBE (web)
The post-auth handler in CustomerPortal previously rendered the
"Portal access not configured" card when the SSO bridge returned 404
(no client row for the user's email). That trapped first-time SSO
users on a dead-end screen with no path to portal creation.
This change routes the 404 to a new OOBE component (src/portal/OOBE.tsx)
that drives portal creation:
* Mounts inline inside CustomerPortal so the post-auth flow stays
inside the portal render tree (no App-level router needed).
* Also reachable as a direct deep-link via the new /onboarding route
in App.tsx (for grooming admins or recovery flows).
* Submits to a new POST /api/portal/clients-from-auth endpoint in
groombook-api (companion commit) that creates a fresh client row
bound to the Better Auth email. 409 means the email already has a
portal record — the OOBE shows a portal-selection message.
* Uses the canonical shared signOut() from lib/auth-client (GRO-2358
invariant) for the Sign out button.
* Full window.location.href reload on submit success to reset the
bridge's cached state and land the user in their portal.
The no-access card itself is preserved for the deep-link deleted-portal
case (a customer whose portal was disabled/deleted), signalled via
?noAccess=deleted-portal on a portal sub-route. The OOBE handles the
first-time-creation case; the no-access card handles the "had a portal
but lost it" case.
Test coverage:
* "routes to /onboarding when session-from-auth returns 404 (GRO-2359)"
— proves the post-auth 404 mounts the OOBE inline, not the legacy
no-access card.
* 6 new OOBE tests: render from direct link, name prefill, form
submission, 409 portal-selection, required-name validation, shared
signOut(), redirect on no-session.
* P1 no-access tests reworked to use ?noAccess=deleted-portal so the
GRO-2358 signOut invariant is still verified on the only surviving
path to the no-access card.
UAT_PLAYBOOK §5.25.5–6e rewritten to cover the OOBE flow (form submit,
409, deep-link mount, deleted-portal no-access card).
Paired with the api PR on feature/2357-p2-portal-clients-from-auth.
Co-Authored-By: Paperclip <noreply@paperclip.ing>
(cherry picked from commit 250c7a5ac9)
This commit is contained in:
+13
-1
@@ -16,6 +16,7 @@ import { BookingCancelledPage } from "./pages/BookingCancelled.js";
|
||||
import { BookingErrorPage } from "./pages/BookingError.js";
|
||||
import { SetupWizard } from "./pages/SetupWizard.tsx";
|
||||
import { CustomerPortal } from "./portal/CustomerPortal.js";
|
||||
import { OOBE } from "./portal/OOBE.js";
|
||||
import { DevLoginSelector, getDevUser } from "./pages/DevLoginSelector.js";
|
||||
import { DevSessionIndicator } from "./components/DevSessionIndicator.js";
|
||||
import { BrandingProvider, useBranding } from "./BrandingContext.js";
|
||||
@@ -406,7 +407,13 @@ export function App() {
|
||||
}
|
||||
|
||||
// Don't render portal chrome at /login — DevLoginSelector is shown instead
|
||||
const showCustomerPortal = !location.pathname.startsWith("/admin") && location.pathname !== "/login";
|
||||
const showCustomerPortal = !location.pathname.startsWith("/admin") && location.pathname !== "/login" && location.pathname !== "/onboarding";
|
||||
// GRO-2359: OOBE is mountable from a direct link (deep-link to /onboarding)
|
||||
// and from the post-auth callback (CustomerPortal navigates here when the
|
||||
// SSO bridge returns 404). Render the OOBE component standalone so it's
|
||||
// outside the portal chrome (no `!sessionId` guards, no `!initComplete`
|
||||
// loading states to fight — the OOBE handles its own auth resolution).
|
||||
const showOOBE = location.pathname === "/onboarding";
|
||||
|
||||
// At /login with a valid session, redirect to the portal root. Without this,
|
||||
// the final render returns null at /login (showCustomerPortal is false) and
|
||||
@@ -425,6 +432,11 @@ export function App() {
|
||||
</Routes>
|
||||
{authDisabled && <DevSessionIndicator />}
|
||||
</>
|
||||
) : showOOBE ? (
|
||||
<>
|
||||
<OOBE />
|
||||
{authDisabled && <DevSessionIndicator />}
|
||||
</>
|
||||
) : showCustomerPortal ? (
|
||||
<>
|
||||
<CustomerPortal />
|
||||
|
||||
Reference in New Issue
Block a user