Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion platform/src/app/me/ai-usage/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ export default async function PersonalAIUsagePage({
});

return (
<div className="mx-auto max-w-5xl space-y-8 px-4 py-28 lg:pt-44">
<div className="mx-auto max-w-5xl space-y-8">
<header className="space-y-2">
<h1 className="text-2xl font-bold">{t("meAiUsage.title")}</h1>
<p className="text-sm text-muted-foreground">
Expand Down
46 changes: 46 additions & 0 deletions platform/src/app/me/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import type { ReactNode } from "react";

import { redirect } from "next/navigation";

import { getServerSession } from "next-auth/next";

import { TenantNavbar } from "@/components/tenant/TenantNavbar";
import { TenantProvider } from "@/components/tenant/TenantProvider";
import { authOptions } from "@/lib/auth";

type SessionOrganization = {
slug: string;
role?: string | null;
};

type SessionUser = {
organizations?: SessionOrganization[];
};

// Routes under /me are authenticated but cross-organization (self-only), so
// they live outside /[tenant] and never get the tenant layout. Without this
// layout the root ConditionalNavbar fell back to the public/visitor navbar,
// making an authenticated page look logged out (issue #71). Render the
// authenticated TenantNavbar here, scoped to the user's primary org for its
// links and org switcher.
export default async function MeLayout({ children }: { children: ReactNode }) {
const session = await getServerSession(authOptions);
if (!session) {
redirect("/auth/signin?callbackUrl=/me/ai-usage");
}

const sessionUser = session.user as SessionUser | undefined;
const primaryOrg = sessionUser?.organizations?.[0];

return (
<TenantProvider
tenant={primaryOrg?.slug ?? ""}
tenantRole={primaryOrg?.role ?? "member"}
>
<div className="min-h-screen bg-background">
<TenantNavbar />
<main className="p-4 sm:p-6">{children}</main>
</div>
</TenantProvider>
);
}
5 changes: 4 additions & 1 deletion platform/src/components/ConditionalNavbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@ const PUBLIC_ROUTES = new Set([
'/deck',
]);

const PUBLIC_PREFIXES = ['/cli/', '/me/'];
// Note: /me/* is authenticated (self-only) and renders its own TenantNavbar
// via src/app/me/layout.tsx — it must NOT be treated as public here, otherwise
// the visitor navbar shows on a logged-in page (issue #71).
const PUBLIC_PREFIXES = ['/cli/'];

const HIDDEN_PREFIXES = [
'/auth',
Expand Down
Loading