import Link from "next/link"; import { getTranslations } from "next-intl/server"; import { requireAppAccess } from "@/server/app-access"; import { can } from "@/server/services/context"; import { fieldPageContext } from "@/server/services/field/page-context"; import { getMyActiveSession } from "@/server/services/field/sessions"; import { countPendingTimeEntries } from "@/server/services/field/time-entries"; import { cn } from "@/lib/utils"; 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 { RunningClockBar, type ClockSession } from "@/components/field/running-clock-bar"; import { OfflineRuntime } from "@/components/offline/offline-runtime"; import { TrialBanner } from "@/components/trial/trial-banner"; /** L12: own running/paused session + open approvals for the shell (never blocks the page). */ async function shellTimeState(): Promise<{ clock: ClockSession | null; approvals: number }> { try { const ctx = await fieldPageContext(); const [session, approvals] = await Promise.all([can(ctx, "field:execute") ? getMyActiveSession(ctx) : Promise.resolve(null), countPendingTimeEntries(ctx)]); return { clock: session ? { status: session.status, workOrderId: session.workOrderId, number: session.number, title: session.title, segmentType: session.segmentType, segmentStartedAt: session.segmentStartedAt, closedSeconds: session.closedSeconds } : null, approvals, }; } catch { // module "field" disabled or no field permissions: shell without clock/badge return { clock: null, approvals: 0 }; } } /** * 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". * L12: running clock bar above the bottom navigation on every /m page. */ export default async function FieldShell({ children }: Readonly<{ children: React.ReactNode }>) { const access = await requireAppAccess(); if (access.kind === "inactive") return ; const [t, time] = await Promise.all([getTranslations("field.nav"), shellTimeState()]); return (
{/* Slot für L6: aus src/components/notifications/bell.tsx */}
{/* L15 Testphase: Countdown ab 7 Tagen bzw. Nur-Lesen-Hinweis */}
{children}
); }