37 lines
1.7 KiB
TypeScript
37 lines
1.7 KiB
TypeScript
import Link from "next/link";
|
|
import { getTranslations } from "next-intl/server";
|
|
import { requireAppAccess } from "@/server/app-access";
|
|
import { CraftviaLogo } from "@/components/brand/craftvia-logo";
|
|
import { AccountInactiveNotice } from "@/components/account-inactive-notice";
|
|
import { BottomNav } from "@/components/field/bottom-nav";
|
|
import { OnlineBadge } from "@/components/field/online-badge";
|
|
import { OfflineRuntime } from "@/components/offline/offline-runtime";
|
|
|
|
/**
|
|
* Mobile shell `/m` (ARCHITEKTUR §5): same session/account/MFA checks as the backoffice
|
|
* (src/server/app-access.ts), no sidebar, bottom navigation, online/offline badge.
|
|
* Module gates live one level below: (core) → "field", emergency → "emergency".
|
|
*/
|
|
export default async function FieldShell({ children }: Readonly<{ children: React.ReactNode }>) {
|
|
const access = await requireAppAccess();
|
|
if (access.kind === "inactive") return <AccountInactiveNotice />;
|
|
const t = await getTranslations("field.nav");
|
|
|
|
return (
|
|
<div className="flex min-h-screen flex-1 flex-col bg-background">
|
|
<header className="sticky top-0 z-20 flex h-14 items-center justify-between gap-3 border-b bg-card px-4 pt-[env(safe-area-inset-top)]">
|
|
<Link href="/m" aria-label={t("today")} className="flex min-h-12 items-center">
|
|
<CraftviaLogo variant="horizontal" height={26} />
|
|
</Link>
|
|
<div className="flex items-center gap-2">
|
|
{/* Slot für L6: <NotificationBell variant="mobile" /> aus src/components/notifications/bell.tsx */}
|
|
<OfflineRuntime />
|
|
<OnlineBadge />
|
|
</div>
|
|
</header>
|
|
<div className="mx-auto w-full max-w-xl flex-1 pb-28">{children}</div>
|
|
<BottomNav />
|
|
</div>
|
|
);
|
|
}
|