diff --git a/app/(app)/layout.tsx b/app/(app)/layout.tsx index cdd8fae..5bc6df2 100644 --- a/app/(app)/layout.tsx +++ b/app/(app)/layout.tsx @@ -14,18 +14,34 @@ export default async function AppLayout({ children }: { children: React.ReactNod redirect('/login') } - const userRoles = await prisma.userRole.findMany({ - where: { user_id: session.userId }, - select: { role: true }, - }) + const [user, userRoles] = await Promise.all([ + prisma.user.findUnique({ + where: { id: session.userId }, + select: { username: true, bio: true }, + }), + prisma.userRole.findMany({ + where: { user_id: session.userId }, + select: { role: true }, + }), + ]) const roles = userRoles.map(r => r.role as string) + if (!user) { + redirect('/login') + } + return (
Ga naar inhoud - +
{children} diff --git a/components/shared/nav-bar.tsx b/components/shared/nav-bar.tsx index dcee6ab..bafdd5c 100644 --- a/components/shared/nav-bar.tsx +++ b/components/shared/nav-bar.tsx @@ -2,32 +2,22 @@ import Link from 'next/link' import { usePathname } from 'next/navigation' -import { logoutAction } from '@/actions/auth' -import { Button } from '@/components/ui/button' import { Badge } from '@/components/ui/badge' import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip' import { AppIcon } from '@/components/shared/app-icon' +import { UserMenu } from '@/components/shared/user-menu' import { cn } from '@/lib/utils' import { useProductStore } from '@/stores/product-store' -const ROLE_LABELS: Record = { - PRODUCT_OWNER: 'PO', - SCRUM_MASTER: 'SM', - DEVELOPER: 'Dev', -} - -const ROLE_FULL_LABELS: Record = { - PRODUCT_OWNER: 'Product Owner', - SCRUM_MASTER: 'Scrum Master', - DEVELOPER: 'Developer', -} - interface NavBarProps { isDemo: boolean roles: string[] + userId: string + username: string + bio: string | null } -export function NavBar({ isDemo, roles }: NavBarProps) { +export function NavBar({ isDemo, roles, userId, username, bio }: NavBarProps) { const pathname = usePathname() const currentProduct = useProductStore(s => s.currentProduct) @@ -105,36 +95,9 @@ export function NavBar({ isDemo, roles }: NavBarProps) { )}
- {/* Rechts: rollen + instellingen + uitloggen */} + {/* Rechts: account-menu */}
- {roles.length > 0 && ( - - - }> - {roles.map(r => ROLE_LABELS[r]).filter(Boolean).join(' · ')} - - - {roles.map(r => ROLE_FULL_LABELS[r]).filter(Boolean).join(' · ')} - - - - )} - - Instellingen - -
- -
+
) diff --git a/components/shared/user-menu.tsx b/components/shared/user-menu.tsx new file mode 100644 index 0000000..a7c750b --- /dev/null +++ b/components/shared/user-menu.tsx @@ -0,0 +1,113 @@ +'use client' + +import Link from 'next/link' +import { Settings, Sun, Globe, LogOut } from 'lucide-react' +import { logoutAction } from '@/actions/auth' +import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar' +import { Badge } from '@/components/ui/badge' +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuLabel, + DropdownMenuSeparator, + DropdownMenuTrigger, +} from '@/components/ui/dropdown-menu' + +const ROLE_LABELS: Record = { + PRODUCT_OWNER: 'Product Owner', + SCRUM_MASTER: 'Scrum Master', + DEVELOPER: 'Developer', +} + +interface UserMenuProps { + userId: string + username: string + bio: string | null + roles: string[] +} + +export function UserMenu({ userId, username, bio, roles }: UserMenuProps) { + const initials = username.slice(0, 2).toUpperCase() + const roleLabels = roles.map((r) => ROLE_LABELS[r]).filter(Boolean) + const subtitle = bio?.trim() ? bio.trim() : 'Lokaal account' + + return ( + + + + + + {initials} + + + + + +
+ + + + {initials} + + +
+
{username}
+
{subtitle}
+
+
+ + {roleLabels.length > 0 && ( + <> + + + Rollen + +
+ {roleLabels.join(', ')} +
+ + )} + + + + }> + + Instellingen + + + + + Thema: licht + + Binnenkort + + + + + + Taal: Nederlands + + Binnenkort + + + + + +
+ + } + > + + Uitloggen + +
+
+
+ ) +}