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>
385 lines
16 KiB
TypeScript
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>
|
|
)
|
|
}
|