From 1b669bb1b7c6914afd586b849ced4497e45e5895 Mon Sep 17 00:00:00 2001 From: Randall Stillwell Date: Wed, 15 Apr 2026 14:18:51 -0500 Subject: [PATCH] Fix onboarding redirect and integrations empty state - Middleware now redirects to /onboarding when user has no org (previously required orgRole=owner which was undefined for new users) - Refresh JWT cookie after onboarding completes so middleware sees updated orgId/onboardingComplete on next navigation - Integrations page shows meaningful error instead of empty grid when API returns 401 due to missing org Made-with: Cursor --- src/app/(dashboard)/onboarding/page.tsx | 1 + .../settings/integrations/page.tsx | 26 ++++++++++++++++--- src/middleware.ts | 13 ++++++---- 3 files changed, 32 insertions(+), 8 deletions(-) diff --git a/src/app/(dashboard)/onboarding/page.tsx b/src/app/(dashboard)/onboarding/page.tsx index 3b51e9e..04e4884 100644 --- a/src/app/(dashboard)/onboarding/page.tsx +++ b/src/app/(dashboard)/onboarding/page.tsx @@ -126,6 +126,7 @@ export default function OnboardingPage() { } if (result.complete) { + await fetch("/api/auth/session"); router.replace("/"); return result; } diff --git a/src/app/(dashboard)/settings/integrations/page.tsx b/src/app/(dashboard)/settings/integrations/page.tsx index 7874a05..ffb5aa0 100644 --- a/src/app/(dashboard)/settings/integrations/page.tsx +++ b/src/app/(dashboard)/settings/integrations/page.tsx @@ -56,15 +56,26 @@ export default function IntegrationsPage() { const [providers, setProviders] = React.useState([]); const [loading, setLoading] = React.useState(true); + const [fetchError, setFetchError] = React.useState(""); + React.useEffect(() => { fetch("/api/integrations") - .then((r) => r.json()) + .then((r) => { + if (!r.ok) throw new Error(r.status === 401 ? "org" : "fetch"); + return r.json(); + }) .then((data) => { setIntegrations(data.integrations || []); setProviders(data.providers || []); - setLoading(false); }) - .catch(() => setLoading(false)); + .catch((err) => { + setFetchError( + err.message === "org" + ? "Complete onboarding to set up your organization first." + : "Failed to load integrations." + ); + }) + .finally(() => setLoading(false)); }, []); if (loading) { @@ -75,6 +86,15 @@ export default function IntegrationsPage() { ); } + if (fetchError) { + return ( +
+ +

{fetchError}

+
+ ); + } + const connectedProviderIds = new Set(integrations.map((i) => i.provider)); const availableProviders = providers.filter( (p) => !connectedProviderIds.has(p.id) diff --git a/src/middleware.ts b/src/middleware.ts index 220d2f3..b7f2007 100644 --- a/src/middleware.ts +++ b/src/middleware.ts @@ -59,11 +59,14 @@ export async function middleware(req: NextRequest) { return NextResponse.redirect(loginUrl); } - if ( - token.onboardingComplete === false && - token.orgRole === "owner" && - !isOnboardingExempt(pathname) - ) { + const hasOrg = !!token.orgId; + const onboardingDone = token.onboardingComplete === true; + + if (!hasOrg && !isOnboardingExempt(pathname)) { + return NextResponse.redirect(new URL("/onboarding", req.url)); + } + + if (hasOrg && !onboardingDone && !isOnboardingExempt(pathname)) { return NextResponse.redirect(new URL("/onboarding", req.url)); }