71 lines
2.8 KiB
TypeScript
71 lines
2.8 KiB
TypeScript
import { redirect } from 'next/navigation';
|
|
import { headers } from 'next/headers';
|
|
import { eq } from 'drizzle-orm';
|
|
|
|
import { auth } from '@/lib/auth';
|
|
import { db } from '@/lib/db';
|
|
import { ports as portsTable } from '@/lib/db/schema/ports';
|
|
import { userPortRoles, userProfiles } from '@/lib/db/schema/users';
|
|
import { QueryProvider } from '@/providers/query-provider';
|
|
import { SocketProvider } from '@/providers/socket-provider';
|
|
import { PortProvider } from '@/providers/port-provider';
|
|
import { PermissionsProvider } from '@/providers/permissions-provider';
|
|
import { Sidebar } from '@/components/layout/sidebar';
|
|
import { Topbar } from '@/components/layout/topbar';
|
|
import { MobileLayout } from '@/components/layout/mobile/mobile-layout';
|
|
|
|
export default async function DashboardLayout({ children }: { children: React.ReactNode }) {
|
|
const session = await auth.api.getSession({ headers: await headers() });
|
|
if (!session?.user) redirect('/login');
|
|
|
|
// Super admins have implicit access to every port; everyone else only sees
|
|
// ports they have an explicit user_port_roles row for.
|
|
const profile = await db.query.userProfiles.findFirst({
|
|
where: eq(userProfiles.userId, session.user.id),
|
|
});
|
|
|
|
const portRoles = await db.query.userPortRoles.findMany({
|
|
where: eq(userPortRoles.userId, session.user.id),
|
|
with: { port: true, role: true },
|
|
});
|
|
|
|
const ports = profile?.isSuperAdmin
|
|
? await db.query.ports.findMany({ orderBy: portsTable.name })
|
|
: portRoles.map((pr) => pr.port);
|
|
|
|
return (
|
|
<QueryProvider>
|
|
<PortProvider ports={ports} defaultPortId={ports[0]?.id ?? null}>
|
|
<PermissionsProvider>
|
|
<SocketProvider>
|
|
{/* Desktop shell — hidden by CSS on mobile */}
|
|
<div data-shell="desktop" className="flex h-screen overflow-hidden bg-background">
|
|
<Sidebar
|
|
portRoles={portRoles}
|
|
isSuperAdmin={profile?.isSuperAdmin ?? false}
|
|
user={{
|
|
name: profile?.displayName ?? session.user.name ?? session.user.email,
|
|
email: session.user.email,
|
|
}}
|
|
/>
|
|
<div className="flex-1 flex flex-col overflow-hidden min-w-0">
|
|
<Topbar
|
|
ports={ports}
|
|
user={{
|
|
name: profile?.displayName ?? session.user.name ?? session.user.email,
|
|
email: session.user.email,
|
|
}}
|
|
/>
|
|
<main className="flex-1 overflow-y-auto bg-background p-6">{children}</main>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Mobile shell — hidden by CSS on desktop */}
|
|
<MobileLayout>{children}</MobileLayout>
|
|
</SocketProvider>
|
|
</PermissionsProvider>
|
|
</PortProvider>
|
|
</QueryProvider>
|
|
);
|
|
}
|