import { notFound } from 'next/navigation'; import { eq } from 'drizzle-orm'; import { db } from '@/lib/db'; import { ports as portsTable } from '@/lib/db/schema/ports'; import { isResidentialModuleEnabled } from '@/lib/services/residential-module.service'; import { ModuleDisabledPage } from '@/components/shared/module-disabled-page'; interface ResidentialLayoutProps { children: React.ReactNode; params: Promise<{ portSlug: string }>; } /** * Layout-level gate for the entire /residential subtree (clients + * interests, list + detail). When the port has * residential_module_enabled = false, every route under /residential * renders the ModuleDisabledPage instead of the real content. This is * the route-level half of the "hybrid hide+block" model (the sidebar * "Residential" section + mobile entry are independently hidden via * residentialModuleByPort on the SSR-resolved sidebar prop). * * Using a layout rather than per-page guards means: (a) one place to * change the gate logic, (b) nested routes ([id]) are covered * automatically, (c) the children subtree never mounts when disabled, * so its data-fetching effects don't fire. */ export default async function ResidentialLayout({ children, params }: ResidentialLayoutProps) { const { portSlug } = await params; const port = await db.query.ports.findFirst({ where: eq(portsTable.slug, portSlug), columns: { id: true }, }); // Fail closed: an unresolved slug means the port doesn't exist (or the // user mistyped one) — 404 rather than silently rendering the gated // subtree without a module check. if (!port) notFound(); const enabled = await isResidentialModuleEnabled(port.id); if (enabled) return children; return ( ); }