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:
parent
48959190a0
commit
1b669bb1b7
3 changed files with 32 additions and 8 deletions
|
|
@ -126,6 +126,7 @@ export default function OnboardingPage() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result.complete) {
|
if (result.complete) {
|
||||||
|
await fetch("/api/auth/session");
|
||||||
router.replace("/");
|
router.replace("/");
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -56,15 +56,26 @@ export default function IntegrationsPage() {
|
||||||
const [providers, setProviders] = React.useState<ProviderInfo[]>([]);
|
const [providers, setProviders] = React.useState<ProviderInfo[]>([]);
|
||||||
const [loading, setLoading] = React.useState(true);
|
const [loading, setLoading] = React.useState(true);
|
||||||
|
|
||||||
|
const [fetchError, setFetchError] = React.useState("");
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
fetch("/api/integrations")
|
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) => {
|
.then((data) => {
|
||||||
setIntegrations(data.integrations || []);
|
setIntegrations(data.integrations || []);
|
||||||
setProviders(data.providers || []);
|
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) {
|
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 connectedProviderIds = new Set(integrations.map((i) => i.provider));
|
||||||
const availableProviders = providers.filter(
|
const availableProviders = providers.filter(
|
||||||
(p) => !connectedProviderIds.has(p.id)
|
(p) => !connectedProviderIds.has(p.id)
|
||||||
|
|
|
||||||
|
|
@ -59,11 +59,14 @@ export async function middleware(req: NextRequest) {
|
||||||
return NextResponse.redirect(loginUrl);
|
return NextResponse.redirect(loginUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
const hasOrg = !!token.orgId;
|
||||||
token.onboardingComplete === false &&
|
const onboardingDone = token.onboardingComplete === true;
|
||||||
token.orgRole === "owner" &&
|
|
||||||
!isOnboardingExempt(pathname)
|
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));
|
return NextResponse.redirect(new URL("/onboarding", req.url));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue