feat(site-scope): load the allowed site list in the dashboard layout

This commit is contained in:
DEls 2026-09-11 23:02:30 +02:00
parent c88ebb1715
commit 63eb8ed931
2 changed files with 54 additions and 5 deletions

View file

@ -1,13 +1,25 @@
import { Sidebar } from "@/components/layout/sidebar";
import { AuthGate } from "@/components/auth-gate";
import { SiteScopeProvider } from "@/components/layout/site-scope-provider";
import { getSiteScope, scopeFallbackValue } from "@/lib/site-scope";
export const dynamic = "force-dynamic";
export default async function DashboardLayout({ children }: { children: React.ReactNode }) {
// No searchParams here — layouts cannot read them and do not re-render
// on navigation. This call supplies `allowed` (stable for the session)
// and the cookie-resolved default; the switcher reads the live value
// from the URL itself.
const scope = await getSiteScope();
export default function DashboardLayout({ children }: { children: React.ReactNode }) {
return (
<AuthGate>
<div className="flex min-h-screen w-full bg-background">
<Sidebar />
<div className="min-w-0 flex-1">{children}</div>
</div>
<SiteScopeProvider allowed={scope.allowed} fallbackValue={scopeFallbackValue(scope)}>
<div className="flex min-h-screen w-full bg-background">
<Sidebar />
<div className="min-w-0 flex-1">{children}</div>
</div>
</SiteScopeProvider>
</AuthGate>
);
}

View file

@ -0,0 +1,37 @@
"use client";
import * as React from "react";
import type { ScopeSite } from "@/lib/site-scope";
interface SiteScopeContextValue {
/** Every site the user may see. Loaded once by the dashboard layout. */
allowed: ScopeSite[];
/**
* What to show when the URL carries no ?site= — the cookie-resolved
* default. Deliberately NOT the active scope: active always comes
* from useSearchParams() so the control's state is the URL.
*/
fallbackValue: string;
}
const SiteScopeContext = React.createContext<SiteScopeContextValue | undefined>(
undefined
);
export function SiteScopeProvider({
allowed,
fallbackValue,
children,
}: SiteScopeContextValue & { children: React.ReactNode }) {
const value = React.useMemo(
() => ({ allowed, fallbackValue }),
[allowed, fallbackValue]
);
return <SiteScopeContext.Provider value={value}>{children}</SiteScopeContext.Provider>;
}
export function useSiteScope() {
const ctx = React.useContext(SiteScopeContext);
if (!ctx) throw new Error("useSiteScope must be used inside SiteScopeProvider");
return ctx;
}