Files
breakpilot-lehrer/website/app/admin/compliance/role-select/page.tsx
Benjamin Boenisch 5a31f52310 Initial commit: breakpilot-lehrer - Lehrer KI Platform
Services: Admin-Lehrer, Backend-Lehrer, Studio v2, Website,
Klausur-Service, School-Service, Voice-Service, Geo-Service,
BreakPilot Drive, Agent-Core

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-11 23:47:26 +01:00

385 lines
16 KiB
TypeScript

'use client'
/**
* Compliance Portal - Rollen-Auswahl Landing Page
*
* Ermoeglicht Stakeholdern die Auswahl ihrer bevorzugten Ansicht:
* - Executive: Ueberblick, Trends, Ampel-Status
* - Auditor: Checkliste, Sign-off, Reports
* - Compliance Officer: Workflows, Anforderungsmanagement
* - Entwickler: Tech-Docs, Code-Referenzen
*/
import { useState, useEffect } from 'react'
import { useRouter } from 'next/navigation'
import AdminLayout from '@/components/admin/AdminLayout'
import { Language } from '@/lib/compliance-i18n'
interface RoleCard {
id: string
title: {
de: string
en: string
}
subtitle: {
de: string
en: string
}
description: {
de: string
en: string
}
features: {
de: string[]
en: string[]
}
icon: JSX.Element
href: string
color: string
borderColor: string
}
const roles: RoleCard[] = [
{
id: 'executive',
title: { de: 'Executive', en: 'Executive' },
subtitle: { de: 'Management-Ueberblick', en: 'Management Overview' },
description: {
de: 'Strategische Compliance-Ansicht mit Ampel-Status, Trends und Top-Risiken fuer schnelle Entscheidungen.',
en: 'Strategic compliance view with traffic light status, trends and top risks for quick decisions.'
},
features: {
de: ['Compliance-Ampel', 'Trend-Analyse', 'Top 5 Risiken', 'Deadline-Kalender'],
en: ['Compliance Traffic Light', 'Trend Analysis', 'Top 5 Risks', 'Deadline Calendar']
},
icon: (
<svg className="w-12 h-12" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={1.5} d="M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z" />
</svg>
),
href: '/admin/compliance?tab=executive',
color: 'from-blue-500 to-blue-600',
borderColor: 'border-blue-500'
},
{
id: 'auditor',
title: { de: 'Auditor', en: 'Auditor' },
subtitle: { de: 'Pruefungs-Checkliste', en: 'Audit Checklist' },
description: {
de: 'Strukturierte Pruefungsumgebung mit Checklisten, Sign-off-Workflows und PDF-Reports fuer Auditoren.',
en: 'Structured audit environment with checklists, sign-off workflows and PDF reports for auditors.'
},
features: {
de: ['Audit-Checkliste', 'Sign-off Workflow', 'PDF Reports', 'Digitale Signaturen'],
en: ['Audit Checklist', 'Sign-off Workflow', 'PDF Reports', 'Digital Signatures']
},
icon: (
<svg className="w-12 h-12" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={1.5} d="M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z" />
</svg>
),
href: '/admin/compliance/audit-checklist',
color: 'from-green-500 to-green-600',
borderColor: 'border-green-500'
},
{
id: 'compliance-officer',
title: { de: 'Compliance Officer', en: 'Compliance Officer' },
subtitle: { de: 'Vollstaendige Verwaltung', en: 'Full Management' },
description: {
de: 'Umfassende Compliance-Verwaltung mit allen Anforderungen, Controls, Evidence und Risk Management.',
en: 'Comprehensive compliance management with all requirements, controls, evidence and risk management.'
},
features: {
de: ['Anforderungs-Management', 'Control-Verwaltung', 'Evidence-Upload', 'Risk Matrix'],
en: ['Requirement Management', 'Control Management', 'Evidence Upload', 'Risk Matrix']
},
icon: (
<svg className="w-12 h-12" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={1.5} d="M19 11H5m14 0a2 2 0 012 2v6a2 2 0 01-2 2H5a2 2 0 01-2-2v-6a2 2 0 012-2m14 0V9a2 2 0 00-2-2M5 11V9a2 2 0 012-2m0 0V5a2 2 0 012-2h6a2 2 0 012 2v2M7 7h10" />
</svg>
),
href: '/admin/compliance/audit-workspace',
color: 'from-purple-500 to-purple-600',
borderColor: 'border-purple-500'
},
{
id: 'developer',
title: { de: 'Entwickler', en: 'Developer' },
subtitle: { de: 'Technische Details', en: 'Technical Details' },
description: {
de: 'Technische Dokumentation mit Code-Referenzen, API-Spezifikationen und Architektur-Diagrammen.',
en: 'Technical documentation with code references, API specifications and architecture diagrams.'
},
features: {
de: ['API-Dokumentation', 'Code-Referenzen', 'Datenmodell', 'Architektur'],
en: ['API Documentation', 'Code References', 'Data Model', 'Architecture']
},
icon: (
<svg className="w-12 h-12" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={1.5} d="M10 20l4-16m4 4l4 4-4 4M6 16l-4-4 4-4" />
</svg>
),
href: '/admin/compliance?tab=technisch',
color: 'from-orange-500 to-orange-600',
borderColor: 'border-orange-500'
}
]
export default function RoleSelectPage() {
const router = useRouter()
const [language, setLanguage] = useState<Language>('de')
const [hoveredRole, setHoveredRole] = useState<string | null>(null)
const [savedRole, setSavedRole] = useState<string | null>(null)
// Lade gespeicherte Rolle aus localStorage
useEffect(() => {
const stored = localStorage.getItem('compliance_preferred_role')
if (stored) {
setSavedRole(stored)
}
const storedLang = localStorage.getItem('compliance_language') as Language
if (storedLang) {
setLanguage(storedLang)
}
}, [])
const handleRoleSelect = (role: RoleCard, savePreference: boolean = false) => {
if (savePreference) {
localStorage.setItem('compliance_preferred_role', role.id)
setSavedRole(role.id)
}
router.push(role.href)
}
const clearPreference = () => {
localStorage.removeItem('compliance_preferred_role')
setSavedRole(null)
}
return (
<AdminLayout>
<div className="min-h-screen bg-gradient-to-br from-slate-900 via-slate-800 to-slate-900 p-8">
{/* Header */}
<div className="max-w-6xl mx-auto mb-12 text-center">
<h1 className="text-4xl font-bold text-white mb-4">
{language === 'de' ? 'Compliance Portal' : 'Compliance Portal'}
</h1>
<p className="text-xl text-slate-300 mb-6">
{language === 'de'
? 'Waehlen Sie Ihre bevorzugte Ansicht'
: 'Choose your preferred view'}
</p>
{/* Sprach-Toggle */}
<div className="flex justify-center gap-2 mb-4">
<button
onClick={() => {
setLanguage('de')
localStorage.setItem('compliance_language', 'de')
}}
className={`px-4 py-2 rounded-lg transition-colors ${
language === 'de'
? 'bg-blue-600 text-white'
: 'bg-slate-700 text-slate-300 hover:bg-slate-600'
}`}
>
Deutsch
</button>
<button
onClick={() => {
setLanguage('en')
localStorage.setItem('compliance_language', 'en')
}}
className={`px-4 py-2 rounded-lg transition-colors ${
language === 'en'
? 'bg-blue-600 text-white'
: 'bg-slate-700 text-slate-300 hover:bg-slate-600'
}`}
>
English
</button>
</div>
{/* Gespeicherte Praeferenz */}
{savedRole && (
<div className="inline-flex items-center gap-2 bg-slate-700/50 px-4 py-2 rounded-lg text-slate-300 text-sm">
<span>
{language === 'de' ? 'Bevorzugte Rolle:' : 'Preferred role:'}{' '}
<strong className="text-white">
{roles.find(r => r.id === savedRole)?.title[language]}
</strong>
</span>
<button
onClick={clearPreference}
className="text-slate-400 hover:text-white transition-colors"
title={language === 'de' ? 'Praeferenz loeschen' : 'Clear preference'}
>
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
</div>
)}
</div>
{/* Role Cards Grid */}
<div className="max-w-6xl mx-auto grid grid-cols-1 md:grid-cols-2 gap-6">
{roles.map((role) => (
<div
key={role.id}
className={`relative group cursor-pointer transition-all duration-300 ${
hoveredRole === role.id ? 'scale-105 z-10' : 'scale-100'
}`}
onMouseEnter={() => setHoveredRole(role.id)}
onMouseLeave={() => setHoveredRole(null)}
onClick={() => handleRoleSelect(role)}
>
{/* Glow Effect */}
<div className={`absolute inset-0 bg-gradient-to-r ${role.color} opacity-0 group-hover:opacity-20 rounded-2xl blur-xl transition-opacity duration-300`} />
{/* Card */}
<div className={`relative bg-slate-800/80 backdrop-blur-sm border-2 ${
savedRole === role.id ? role.borderColor : 'border-slate-700'
} rounded-2xl p-6 h-full transition-all duration-300 group-hover:border-slate-500`}>
{/* Saved Badge */}
{savedRole === role.id && (
<div className={`absolute -top-2 -right-2 bg-gradient-to-r ${role.color} text-white text-xs px-2 py-1 rounded-full`}>
{language === 'de' ? 'Bevorzugt' : 'Preferred'}
</div>
)}
{/* Icon & Title */}
<div className="flex items-start gap-4 mb-4">
<div className={`p-3 rounded-xl bg-gradient-to-br ${role.color} text-white`}>
{role.icon}
</div>
<div>
<h2 className="text-2xl font-bold text-white">{role.title[language]}</h2>
<p className="text-slate-400">{role.subtitle[language]}</p>
</div>
</div>
{/* Description */}
<p className="text-slate-300 mb-4">
{role.description[language]}
</p>
{/* Features */}
<div className="space-y-2">
{role.features[language].map((feature, idx) => (
<div key={idx} className="flex items-center gap-2 text-slate-400">
<svg className="w-4 h-4 text-green-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M5 13l4 4L19 7" />
</svg>
<span>{feature}</span>
</div>
))}
</div>
{/* Action Buttons */}
<div className="mt-6 flex gap-3">
<button
onClick={(e) => {
e.stopPropagation()
handleRoleSelect(role)
}}
className={`flex-1 py-2 px-4 bg-gradient-to-r ${role.color} text-white rounded-lg font-medium transition-all duration-200 hover:shadow-lg hover:shadow-${role.color.split('-')[1]}-500/25`}
>
{language === 'de' ? 'Oeffnen' : 'Open'}
</button>
<button
onClick={(e) => {
e.stopPropagation()
handleRoleSelect(role, true)
}}
className="py-2 px-4 bg-slate-700 text-slate-300 rounded-lg font-medium transition-all duration-200 hover:bg-slate-600 hover:text-white"
title={language === 'de' ? 'Als Standard speichern' : 'Save as default'}
>
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M5 5a2 2 0 012-2h10a2 2 0 012 2v16l-7-3.5L5 21V5z" />
</svg>
</button>
</div>
</div>
</div>
))}
</div>
{/* Quick Links */}
<div className="max-w-6xl mx-auto mt-12">
<div className="bg-slate-800/50 backdrop-blur-sm rounded-xl p-6 border border-slate-700">
<h3 className="text-lg font-semibold text-white mb-4">
{language === 'de' ? 'Schnellzugriff' : 'Quick Access'}
</h3>
<div className="grid grid-cols-2 md:grid-cols-4 gap-4">
<QuickLink
href="/admin/compliance/controls"
label={language === 'de' ? 'Control Catalogue' : 'Control Catalogue'}
icon={
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 6h16M4 10h16M4 14h16M4 18h16" />
</svg>
}
/>
<QuickLink
href="/admin/compliance/evidence"
label={language === 'de' ? 'Nachweise' : 'Evidence'}
icon={
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" />
</svg>
}
/>
<QuickLink
href="/admin/compliance/risks"
label={language === 'de' ? 'Risk Matrix' : 'Risk Matrix'}
icon={
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" />
</svg>
}
/>
<QuickLink
href="/admin/compliance/scraper"
label={language === 'de' ? 'Regulation Scraper' : 'Regulation Scraper'}
icon={
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4" />
</svg>
}
/>
</div>
</div>
</div>
{/* Footer */}
<div className="max-w-6xl mx-auto mt-8 text-center text-slate-500 text-sm">
<p>
BreakPilot Compliance & Audit Framework v3.0 |
19 {language === 'de' ? 'Verordnungen' : 'Regulations'} |
558 {language === 'de' ? 'Anforderungen' : 'Requirements'} |
44 Controls
</p>
</div>
</div>
</AdminLayout>
)
}
// Quick Link Component
function QuickLink({ href, label, icon }: { href: string; label: string; icon: JSX.Element }) {
const router = useRouter()
return (
<button
onClick={() => router.push(href)}
className="flex items-center gap-3 px-4 py-3 bg-slate-700/50 rounded-lg text-slate-300 hover:bg-slate-700 hover:text-white transition-colors"
>
{icon}
<span className="text-sm font-medium">{label}</span>
</button>
)
}