import { redirect } from 'next/navigation' import { requireSession } from '@/lib/auth-guard' import { prisma } from '@/lib/prisma' import { productAccessFilter } from '@/lib/product-access' import { resolveActiveSprint } from '@/lib/active-sprint' import { sprintStatusToApi, type SprintStatusApi } from '@/lib/task-status' import { NavBar } from '@/components/shared/nav-bar' import { MinWidthBanner } from '@/components/shared/min-width-banner' import { StatusBar } from '@/components/shared/status-bar' import { SoloRealtimeBridge } from '@/components/solo/realtime-bridge' import { NotificationsBridge } from '@/components/notifications/notifications-bridge' import { AlertToast } from '@/components/shared/alert-toast' import { Suspense } from 'react' export default async function AppLayout({ children }: { children: React.ReactNode }) { const session = await requireSession() const [user, userRoles, accessibleProducts] = await Promise.all([ prisma.user.findUnique({ where: { id: session.userId }, select: { username: true, email: true, active_product_id: true, min_quota_pct: true }, }), prisma.userRole.findMany({ where: { user_id: session.userId }, select: { role: true }, }), prisma.product.findMany({ where: { archived: false, ...productAccessFilter(session.userId) }, orderBy: { name: 'asc' }, select: { id: true, name: true }, }), ]) const roles = userRoles.map(r => r.role as string) if (!user) { redirect('/login') } // Resolve active product — clear stale reference if archived or inaccessible let activeProduct: { id: string; name: string } | null = null let sprints: { id: string; code: string; status: SprintStatusApi }[] = [] let activeSprint: { id: string; code: string; status: SprintStatusApi } | null = null let buildingSprintIds: string[] = [] if (user.active_product_id) { const product = await prisma.product.findFirst({ where: { id: user.active_product_id, archived: false, ...productAccessFilter(session.userId) }, select: { id: true, name: true }, }) if (product) { activeProduct = product const allSprints = await prisma.sprint.findMany({ where: { product_id: product.id }, orderBy: { created_at: 'desc' }, select: { id: true, code: true, status: true }, }) sprints = allSprints.map(s => ({ id: s.id, code: s.code, status: sprintStatusToApi(s.status), })) const resolved = await resolveActiveSprint(product.id) activeSprint = resolved ? { id: resolved.id, code: resolved.code, status: sprintStatusToApi(resolved.status) } : null if (allSprints.length > 0) { const runs = await prisma.sprintRun.findMany({ where: { sprint_id: { in: allSprints.map(s => s.id) }, status: { in: ['QUEUED', 'RUNNING'] }, }, select: { sprint_id: true }, }) buildingSprintIds = Array.from(new Set(runs.map(r => r.sprint_id))) } } else { await prisma.user.update({ where: { id: session.userId }, data: { active_product_id: null }, }) redirect('/dashboard?alert=product_unavailable') } } return (
Ga naar inhoud
{children}
) }