feat: show tenancy scope (Org → Chapter) in chapter & member portals
Surface where the logged-in user sits in the hierarchy via a ScopeCard in the sidebar, below the brand mark. API: - Enrich chapter login/me responses with tenantName + organization (LoginResponse.admin, AdminProfile types updated) - Add GET /my/scope returning member's chapter + organization Web: - ScopeCard component (Organisation row + Chapter row, themed icons) - Chapter portal: scope from auth context, blue accent - Member portal: scope fetched server-side in layout, emerald accent - PortalShell gains a `scope` slot rendered under the brand Org and admin portals intentionally omit it — org IS the scope, admin is platform-wide. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,14 +1,31 @@
|
||||
import { getMemberToken } from '../_lib/api';
|
||||
import { getMemberToken, getApiBaseUrl } from '../_lib/api';
|
||||
import { redirect } from 'next/navigation';
|
||||
import { MemberNav } from './member-nav';
|
||||
|
||||
interface MemberScope {
|
||||
member: { displayName: string | null };
|
||||
chapter: { id: string; slug: string; name: string };
|
||||
organization: { id: string; slug: string; name: string } | null;
|
||||
}
|
||||
|
||||
async function fetchScope(token: string): Promise<MemberScope | null> {
|
||||
const res = await fetch(`${getApiBaseUrl()}/my/scope`, {
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
cache: 'no-store',
|
||||
}).catch(() => null);
|
||||
if (!res || !res.ok) return null;
|
||||
return (await res.json()) as MemberScope;
|
||||
}
|
||||
|
||||
export default async function MemberLayout({ children }: { children: React.ReactNode }) {
|
||||
const token = await getMemberToken();
|
||||
if (!token) redirect('/member-login');
|
||||
|
||||
const scope = await fetchScope(token);
|
||||
|
||||
return (
|
||||
<div className="flex h-screen overflow-hidden">
|
||||
<MemberNav />
|
||||
<MemberNav scope={scope} />
|
||||
<main className="flex-1 overflow-auto bg-muted/30">
|
||||
<div className="p-6 lg:p-8 max-w-6xl mx-auto w-full">{children}</div>
|
||||
</main>
|
||||
|
||||
Reference in New Issue
Block a user