Files
ApiCore/ApiCore-Frontend/src/app/(app)/layout.tsx
T
Nick Szaunig 55b6dff31b
Backend Image / build-and-push (push) Successful in 3m9s
Frontend Image / build-and-push (push) Successful in 2m55s
fix: Kontomenü stürzt beim Öffnen ab (Base UI error #31)
DropdownMenuLabel (rendert Menu.GroupLabel) stand direkt im
DropdownMenuContent statt in einem DropdownMenuGroup - Base UI wirft
dafür beim Öffnen einen ungefangenen Fehler, der den kompletten
React-Baum crasht. Das war die eigentliche Ursache des seit Sitzungsbeginn
gemeldeten "This page couldn't load" beim Klick auf das Profilbild
oben rechts, nicht der Service Worker (der war schon korrekt).
2026-09-01 17:23:39 +02:00

94 lines
3.2 KiB
TypeScript

"use client";
import { ReactNode, useEffect } from "react";
import Link from "next/link";
import { useRouter } from "next/navigation";
import { Hexagon } from "lucide-react";
import { useAuth } from "@/lib/auth/auth-context";
import { NotificationBell } from "@/components/notification-bell";
import { OfflineSyncBadge } from "@/components/offline-sync-badge";
import { UserAvatar } from "@/components/user-avatar";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuGroup,
DropdownMenuItem,
DropdownMenuLabel,
DropdownMenuSeparator,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import { Sidebar } from "./sidebar";
import { BottomNav } from "./bottom-nav";
import { QuickAddMenu } from "./quick-add-menu";
import { PageTransition } from "./page-transition";
export default function AppLayout({ children }: { children: ReactNode }) {
const router = useRouter();
const { user, isLoading, logout } = useAuth();
useEffect(() => {
if (!isLoading && !user) {
router.replace("/login");
}
}, [isLoading, user, router]);
if (isLoading || !user) {
return null;
}
return (
<div className="flex min-h-screen">
<Sidebar user={user} />
<div className="flex min-w-0 flex-1 flex-col">
<header className="sticky top-0 z-10 flex items-center justify-between gap-3 bg-card/85 px-4 py-3 shadow-[var(--shadow-soft)] backdrop-blur-md sm:justify-end sm:px-6">
<Link
href="/dashboard"
className="flex items-center gap-1.5 font-heading font-semibold sm:hidden"
>
<span
className="flex size-7 items-center justify-center rounded-lg"
style={{ background: "var(--gradient-honey)" }}
>
<Hexagon className="size-4 fill-white/25 text-white" strokeWidth={2.25} />
</span>
ApiCore
</Link>
<div className="flex shrink-0 items-center gap-2 text-sm">
<OfflineSyncBadge />
<NotificationBell />
<DropdownMenu>
<DropdownMenuTrigger className="rounded-full">
<UserAvatar name={user.name} hasAvatar={user.hasAvatar} size="sm" />
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
<DropdownMenuGroup>
<DropdownMenuLabel className="max-w-48 truncate font-normal text-muted-foreground">
{user.email}
</DropdownMenuLabel>
</DropdownMenuGroup>
<DropdownMenuSeparator />
<DropdownMenuItem render={<Link href="/profile" />}>
Profil
</DropdownMenuItem>
<DropdownMenuItem
variant="destructive"
onClick={() => {
void logout().then(() => router.push("/login"));
}}
>
Abmelden
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
</div>
</header>
<div className="flex-1 overflow-y-auto pb-16 sm:pb-0">
<PageTransition>{children}</PageTransition>
</div>
</div>
<BottomNav />
<QuickAddMenu />
</div>
);
}