push
This commit is contained in:
120
innungsapp/apps/admin/app/[slug]/dashboard/layout.tsx
Normal file
120
innungsapp/apps/admin/app/[slug]/dashboard/layout.tsx
Normal file
@@ -0,0 +1,120 @@
|
||||
import { Sidebar } from '@/components/layout/Sidebar'
|
||||
import { Header } from '@/components/layout/Header'
|
||||
import { auth, getSanitizedHeaders } from '@/lib/auth'
|
||||
import { headers } from 'next/headers'
|
||||
import { redirect } from 'next/navigation'
|
||||
import { prisma } from '@innungsapp/shared'
|
||||
import { ForcePasswordChange } from './ForcePasswordChange'
|
||||
|
||||
export default async function DashboardLayout({
|
||||
children,
|
||||
params,
|
||||
}: {
|
||||
children: React.ReactNode
|
||||
params: Promise<{ slug: string }>
|
||||
}) {
|
||||
const sanitizedHeaders = await getSanitizedHeaders()
|
||||
const session = await auth.api.getSession({ headers: sanitizedHeaders })
|
||||
if (!session?.user) {
|
||||
redirect('/login')
|
||||
}
|
||||
|
||||
// Superadmin Redirect
|
||||
const superAdminEmail = process.env.SUPERADMIN_EMAIL || 'superadmin@innungsapp.de'
|
||||
if (session.user.email === superAdminEmail) {
|
||||
redirect('/superadmin')
|
||||
}
|
||||
|
||||
const { slug } = await params
|
||||
const org = await prisma.organization.findUnique({
|
||||
where: { slug }
|
||||
})
|
||||
|
||||
// Basic security: Check if the user is an admin of this organization
|
||||
const userRole = org
|
||||
? await prisma.userRole.findUnique({
|
||||
where: { orgId_userId: { orgId: org.id, userId: session.user.id } }
|
||||
})
|
||||
: null
|
||||
|
||||
// If not found for this slug, check if user is admin of ANY org and redirect there
|
||||
if (!userRole || userRole.role !== 'admin') {
|
||||
const anyAdminRole = await prisma.userRole.findFirst({
|
||||
where: { userId: session.user.id, role: 'admin' },
|
||||
include: { org: true },
|
||||
orderBy: { createdAt: 'asc' },
|
||||
})
|
||||
console.error('[Dashboard] Zugriff verweigert Debug:', {
|
||||
sessionUserId: session.user.id,
|
||||
sessionUserEmail: session.user.email,
|
||||
slug,
|
||||
orgFound: !!org,
|
||||
orgId: org?.id,
|
||||
userRoleFound: !!userRole,
|
||||
userRoleRole: userRole?.role,
|
||||
anyAdminRoleFound: !!anyAdminRole,
|
||||
anyAdminRoleOrgSlug: anyAdminRole?.org?.slug,
|
||||
})
|
||||
if (anyAdminRole?.org?.slug && anyAdminRole.org.slug !== slug) {
|
||||
redirect(`/${anyAdminRole.org.slug}/dashboard`)
|
||||
}
|
||||
}
|
||||
|
||||
// ONLY admins are allowed in the administrative portal
|
||||
if (!userRole || userRole.role !== 'admin') {
|
||||
return (
|
||||
<div className="min-h-screen bg-gray-50 flex flex-col items-center justify-center p-4">
|
||||
<div className="bg-white border rounded-xl p-8 max-w-md w-full text-center shadow-sm">
|
||||
<div className="mx-auto mb-4 flex h-12 w-12 items-center justify-center rounded-full bg-red-100 text-red-600">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" strokeWidth={2} stroke="currentColor" className="w-6 h-6">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="M12 9v3.75m0-10.036A11.959 11.959 0 0 1 3.598 6 11.99 11.99 0 0 0 3 9.75c0 5.592 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.31-.21-2.57-.598-3.75h-.152c-3.196 0-6.1-1.248-8.25-3.286Zm0 13.036h.008v.008H12v-.008Z" />
|
||||
</svg>
|
||||
</div>
|
||||
<h1 className="text-xl font-bold text-gray-900 mb-2">Zugriff verweigert</h1>
|
||||
<p className="text-gray-500 mb-6 text-sm">
|
||||
Dieses Portal ist ausschließlich für Administratoren reserviert. Ihr Account verfügt nicht über die notwendigen Berechtigungen für diesen Bereich.
|
||||
</p>
|
||||
<form action={async () => {
|
||||
'use server'
|
||||
const { auth } = await import('@/lib/auth')
|
||||
const { headers } = await import('next/headers')
|
||||
await auth.api.signOut({ headers: await headers() })
|
||||
redirect('/login')
|
||||
}}>
|
||||
<button type="submit" className="text-sm font-medium text-brand-600 hover:text-brand-700">
|
||||
Abmelden und mit anderem Konto anmelden
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
// Force Password Change Check
|
||||
// @ts-ignore - mustChangePassword is added via additionalFields
|
||||
if (session.user.mustChangePassword) {
|
||||
return (
|
||||
<div className="min-h-screen bg-gray-50 flex flex-col items-center justify-center p-4">
|
||||
<ForcePasswordChange slug={slug} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
// Inject Primary Color Theme
|
||||
const primaryColor = org?.primaryColor || '#E63946'
|
||||
|
||||
return (
|
||||
<div className="flex h-screen bg-gray-50">
|
||||
<style>{`
|
||||
:root {
|
||||
--color-brand-primary: ${primaryColor};
|
||||
}
|
||||
`}</style>
|
||||
<Sidebar orgName={org?.name} logoUrl={org?.logoUrl} />
|
||||
<div className="flex-1 flex flex-col min-w-0">
|
||||
<Header />
|
||||
<main className="flex-1 overflow-y-auto p-6">{children}</main>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user