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
This commit is contained in:
Randall Stillwell 2026-04-15 14:18:51 -05:00
parent 48959190a0
commit 1b669bb1b7
3 changed files with 32 additions and 8 deletions

View file

@ -126,6 +126,7 @@ export default function OnboardingPage() {
}
if (result.complete) {
await fetch("/api/auth/session");
router.replace("/");
return result;
}

View file

@ -56,15 +56,26 @@ export default function IntegrationsPage() {
const [providers, setProviders] = React.useState<ProviderInfo[]>([]);
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 (
<div className="flex flex-col items-center justify-center gap-3 py-20 text-center">
<Plug className="size-10 text-muted-foreground/40" />
<p className="text-sm text-muted-foreground">{fetchError}</p>
</div>
);
}
const connectedProviderIds = new Set(integrations.map((i) => i.provider));
const availableProviders = providers.filter(
(p) => !connectedProviderIds.has(p.id)

View file

@ -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));
}