proj/Frontend/components/layout/app-shell.tsx
2026-01-21 09:52:33 +01:00

130 lines
5.4 KiB
TypeScript

"use client"
import type { ReactNode } from "react"
import { useAuth } from "@/lib/auth-context"
import { Button } from "@/components/ui/button"
import { Avatar, AvatarFallback } from "@/components/ui/avatar"
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuLabel,
DropdownMenuSeparator,
DropdownMenuTrigger,
DropdownMenuSub,
DropdownMenuSubTrigger,
DropdownMenuSubContent,
DropdownMenuCheckboxItem,
} from "@/components/ui/dropdown-menu"
import { LogOut, User, Building2, Cpu } from "lucide-react"
interface AppShellProps {
children: ReactNode
}
export function AppShell({ children }: AppShellProps) {
const { user, logout, rooms, updateRooms } = useAuth()
const initials = user?.name
?.split(" ")
.map((n) => n[0])
.join("")
.toUpperCase()
.slice(0, 2) || ""
return (
<div className="min-h-screen bg-background">
<header className="sticky top-0 z-50 w-full border-b border-border/60 bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/60">
<div className="container flex h-16 items-center justify-between px-4">
<div className="flex items-center gap-3">
<div className="flex h-9 w-9 items-center justify-center rounded-lg bg-primary">
<Cpu className="h-5 w-5 text-primary-foreground" />
</div>
<div className="flex flex-col">
<span className="font-semibold tracking-tight">Elektronikschule</span>
<span className="text-xs text-muted-foreground">IT-Support-Portal</span>
</div>
</div>
<div className="flex items-center gap-4">
<div className="hidden items-center gap-2 rounded-lg bg-muted/50 px-3 py-1.5 md:flex">
{user?.role === "LEHRKRAFT" ? (
<User className="h-4 w-4 text-muted-foreground" />
) : (
<Building2 className="h-4 w-4 text-muted-foreground" />
)}
<span className="text-sm font-medium capitalize">
{user?.role === "LEHRKRAFT" ? "Lehrkraft" : "Raumbetreuer"}
</span>
</div>
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="ghost" className="relative h-9 w-9 rounded-full">
<Avatar className="h-9 w-9">
<AvatarFallback className="bg-primary text-primary-foreground text-sm font-medium">
{initials}
</AvatarFallback>
</Avatar>
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent className="w-56" align="end" forceMount>
<DropdownMenuLabel className="font-normal">
<div className="flex flex-col space-y-1">
<p className="text-sm font-medium leading-none">{user?.name}</p>
<p className="text-xs leading-none text-muted-foreground">{user?.email}</p>
</div>
</DropdownMenuLabel>
<DropdownMenuSeparator />
<DropdownMenuItem className="text-muted-foreground">
<User className="mr-2 h-4 w-4" />
<span className="capitalize">{user?.role === "LEHRKRAFT" ? "Lehrkraft" : "Raumbetreuer"}</span>
</DropdownMenuItem>
{user?.role === "RAUMBETREUER" && user.supervisedRooms && (
<DropdownMenuSub>
<DropdownMenuSubTrigger>
<Building2 className="mr-2 h-4 w-4" />
<span>{user.supervisedRooms.length} Betreute Räume</span>
</DropdownMenuSubTrigger>
<DropdownMenuSubContent className="max-h-60 overflow-y-auto">
<DropdownMenuLabel>Räume verwalten</DropdownMenuLabel>
{rooms.map((room) => {
const isChecked = user.supervisedRooms.some((r) => r.id === room.id)
return (
<DropdownMenuCheckboxItem
key={room.id}
checked={isChecked}
onCheckedChange={(checked) => {
const currentIds = user.supervisedRooms.map((r) => r.id)
let newIds
if (checked) {
newIds = [...currentIds, room.id]
} else {
newIds = currentIds.filter((id) => id !== room.id)
}
updateRooms(newIds)
}}
onSelect={(e) => e.preventDefault()}
>
{room.name}
</DropdownMenuCheckboxItem>
)
})}
</DropdownMenuSubContent>
</DropdownMenuSub>
)}
<DropdownMenuSeparator />
<DropdownMenuItem onClick={logout} className="text-destructive focus:text-destructive">
<LogOut className="mr-2 h-4 w-4" />
<span>Abmelden</span>
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
</div>
</div>
</header>
<main className="container px-4 py-8">{children}</main>
</div>
)
}