Vorarbeit fuer die Rollen-Oberflaeche. Eine Checkbox-Liste ueber einem Katalog, der nicht stimmt, waere schlimmer als gar keine. 18 von 50 Rechten bewachten nichts: tariffs:*, cancellation-periods:*, contract-durations:* und email-providers:* standen im Katalog und waren anhakbar - die Routen prueften in Wahrheit providers:*, platforms:* und settings:*. Die Routen gaten jetzt granular; eine rein additive Migration vererbt jedes neue Recht an jede Rolle, die bisher das Sammelrecht hatte. Nachgerechnet: keine Rolle hat etwas verloren. Der Katalog stand dreifach und divergent - seed.ts, sync-roles.ts und, abweichend, factoryReset. Die dritte Kopie kannte weder audit:* noch gdpr:* und legte DSGVO, Audit-Betrieb und Gegenbuch gar nicht an: Nach einem Werksreset konnte niemand mehr eine Auskunft nach Art. 15 ausfuehren, und aufgefallen waere es erst, wenn eine Frist laeuft. Jetzt eine Quelle: src/config/rechte-katalog.ts. Im selben Code: factoryReset setzte das Admin-Kennwort fest auf "admin" mit bcrypt-Cost 10 - genau das, was seed.ts seit Pentest Runde 12 verbietet. Dieselbe Haertung war nur in einer der beiden Kopien angekommen. Jetzt zufaellig, Cost 12, einmalig im Log. Selbst-Erhoehung geschlossen: neues Recht roles:manage, getrennt von users:*, dazu die Teilmengenregel in rechte.service.ts - niemand kann ein Recht weitergeben, das er selbst nicht haelt. Sie greift auf allen vier Wegen: Rolle anlegen, Rolle aendern, Rollen zuweisen und die drei Haken. Der Haken-Weg war der wichtigste: Er brauchte nur users:create, ein zweites Konto mit "Entwicklerzugriff" anlegen und sich damit anmelden - die Developer-Rolle traegt alle Rechte. Geprueft wird der Zuwachs, nicht der Endzustand, damit Entziehen erlaubt bleibt; und die Rechte des Handelnden kommen frisch aus der Datenbank, nicht aus dem bis zu 15 Minuten alten Token. Systemrollen gesperrt (Role.isSystem): Admin liess sich bisher umbenennen oder leeren - und die versteckten Rollen haengen an ihrem Namen. Role.isHidden ersetzt die im Frontend hartkodierte Namensliste, in der "Gegenbuch" fehlte. Rechteaenderung wirkt sofort: updateRole/deleteRole melden alle Traeger ab. Werksreset und Backup-Restore verlangen zusaetzlich roles:manage - beide loeschen alle Rollen und legen ein frisches admin@admin.com an. Rollenpflege war der einzige Eingriff in die Rechtevergabe ohne SecurityEvent, obwohl sie viele Konten auf einmal trifft. Jetzt PERMISSION_CHANGED - ebenso fuer die bisher stummen Haken DSGVO und Entwicklerzugriff. Aussperr-Ausweg: prisma/rolle-zuweisen.ts. Umgeht die Regel bewusst - wer Shell-Zugang hat, hat ohnehin die Datenbank; ein gestohlener Web-Zugang hat ihn nicht. Schreibt ueber die Hash-Kette, nicht roh. Die Startwache nennt den Befehl im Klartext. Geprueft gegen Dev-DB und frische Wegwerf-DB: 7 Eskalationswege alle 403, 2 Gegenproben erlaubt; 6 Sperrtests auf Systemrollen alle 403, eigene Rollen weiter aenderbar; Stammdaten-Lesen unveraendert 200; Rechteaenderung sofort 401; Migration und sync-roles dreimal identisch; db:seed auf bestehender DB ohne Wirkung auf die Rollenmatrix; frische Installation mit allen 8 Systemrollen und ohne Hinweise. Beim Deploy: Die Migration beendet alle Sitzungen einmalig. Noetig, weil die Rechte im Token stehen - sonst liefen bis zu 15 Minuten 403er. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
505 lines
26 KiB
TypeScript
505 lines
26 KiB
TypeScript
import { Link } from 'react-router-dom';
|
||
import { useAuth } from '../context/AuthContext';
|
||
import Card from '../components/ui/Card';
|
||
import { Settings as SettingsIcon, Code, Store, Clock, Calendar, UserCog, ChevronRight, Building2, FileType, Eye, Globe, Mail, Database, Shield, ShieldAlert, ShieldOff, FileText, FileEdit, PackageCheck, Hash, Landmark } from 'lucide-react';
|
||
|
||
export default function Settings() {
|
||
const { hasPermission, developerMode, setDeveloperMode } = useAuth();
|
||
|
||
const settingsCards = [
|
||
{
|
||
to: '/settings/users',
|
||
icon: UserCog,
|
||
title: 'Benutzer',
|
||
description: 'Verwalten Sie Benutzerkonten, Rollen und Berechtigungen.',
|
||
show: hasPermission('users:read'),
|
||
},
|
||
{
|
||
to: '/settings/platforms',
|
||
icon: Store,
|
||
title: 'Vertriebsplattformen',
|
||
description: 'Verwalten Sie die Plattformen, über die Verträge abgeschlossen werden.',
|
||
show: hasPermission('platforms:read'),
|
||
},
|
||
{
|
||
to: '/settings/cancellation-periods',
|
||
icon: Clock,
|
||
title: 'Kündigungsfristen',
|
||
description: 'Konfigurieren Sie die verfügbaren Kündigungsfristen für Verträge.',
|
||
show: hasPermission('cancellation-periods:read'),
|
||
},
|
||
{
|
||
to: '/settings/contract-durations',
|
||
icon: Calendar,
|
||
title: 'Vertragslaufzeiten',
|
||
description: 'Konfigurieren Sie die verfügbaren Laufzeiten für Verträge.',
|
||
show: hasPermission('contract-durations:read'),
|
||
},
|
||
{
|
||
to: '/settings/providers',
|
||
icon: Building2,
|
||
title: 'Anbieter & Tarife',
|
||
description: 'Verwalten Sie Anbieter und deren Tarife für Verträge.',
|
||
show: hasPermission('providers:read') || hasPermission('tariffs:read'),
|
||
},
|
||
{
|
||
to: '/settings/contract-categories',
|
||
icon: FileType,
|
||
title: 'Vertragstypen',
|
||
description: 'Konfigurieren Sie die verfügbaren Vertragstypen (Strom, Gas, Mobilfunk, etc.).',
|
||
show: hasPermission('contract-categories:read'),
|
||
},
|
||
{
|
||
to: '/settings/credit-note-number-range',
|
||
icon: Hash,
|
||
title: 'Nummernkreise (Gutschrift/Lieferschein)',
|
||
description: 'Präfix, Jahr und Zähler für Gutschriften und Lieferscheine (betragslose Sachwerte).',
|
||
show: hasPermission('settings:read'),
|
||
},
|
||
{
|
||
to: '/settings/company-profile',
|
||
icon: Building2,
|
||
title: 'Firmenstammdaten (Absender)',
|
||
description: 'Absenderdaten für Gutschrift-PDF und ZUGFeRD (Name, Anschrift, USt-IdNr, Bank).',
|
||
show: hasPermission('settings:read'),
|
||
},
|
||
];
|
||
|
||
return (
|
||
<div>
|
||
<div className="flex items-center gap-3 mb-6">
|
||
<SettingsIcon className="w-6 h-6" />
|
||
<h1 className="text-2xl font-bold">Einstellungen</h1>
|
||
</div>
|
||
|
||
{/* Stammdaten-Konfiguration */}
|
||
<div className="mb-8">
|
||
<h2 className="text-lg font-semibold mb-4 text-gray-700">Stammdaten</h2>
|
||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||
{settingsCards
|
||
.filter((card) => card.show)
|
||
.map((card) => (
|
||
<Link
|
||
key={card.to}
|
||
to={card.to}
|
||
className="block p-4 bg-white border border-gray-200 rounded-lg shadow-sm hover:shadow-md hover:border-blue-300 transition-all group"
|
||
>
|
||
<div className="flex items-start gap-4">
|
||
<div className="p-2 bg-blue-50 rounded-lg group-hover:bg-blue-100 transition-colors">
|
||
<card.icon className="w-6 h-6 text-blue-600" />
|
||
</div>
|
||
<div className="flex-1">
|
||
<h3 className="font-semibold text-gray-900 group-hover:text-blue-600 transition-colors flex items-center gap-2">
|
||
{card.title}
|
||
<ChevronRight className="w-4 h-4 opacity-0 group-hover:opacity-100 transition-opacity" />
|
||
</h3>
|
||
<p className="text-sm text-gray-500 mt-1">{card.description}</p>
|
||
</div>
|
||
</div>
|
||
</Link>
|
||
))}
|
||
</div>
|
||
</div>
|
||
|
||
{/* System-Einstellungen */}
|
||
{/*
|
||
Outer-Check umfasst BEWUSST `settings:update`, `audit:read` und
|
||
`gdpr:admin`, sonst sieht die DSGVO-Rolle (nur audit/gdpr-Perms, kein
|
||
`settings:update`) die DSGVO-/Audit-Karten gar nicht. Jede Karte
|
||
innerhalb hat ihren eigenen feingranularen Check.
|
||
*/}
|
||
{(hasPermission('settings:update') || hasPermission('audit:read') || hasPermission('gdpr:admin')) && (
|
||
<div className="mb-8">
|
||
<h2 className="text-lg font-semibold mb-4 text-gray-700">System</h2>
|
||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||
<Link
|
||
to="/settings/portal"
|
||
className="block p-4 bg-white border border-gray-200 rounded-lg shadow-sm hover:shadow-md hover:border-blue-300 transition-all group"
|
||
>
|
||
<div className="flex items-start gap-4">
|
||
<div className="p-2 bg-blue-50 rounded-lg group-hover:bg-blue-100 transition-colors">
|
||
<Globe className="w-6 h-6 text-blue-600" />
|
||
</div>
|
||
<div className="flex-1">
|
||
<h3 className="font-semibold text-gray-900 group-hover:text-blue-600 transition-colors flex items-center gap-2">
|
||
Kundenportal
|
||
<ChevronRight className="w-4 h-4 opacity-0 group-hover:opacity-100 transition-opacity" />
|
||
</h3>
|
||
<p className="text-sm text-gray-500 mt-1">Konfigurieren Sie das Kundenportal und Support-Anfragen.</p>
|
||
</div>
|
||
</div>
|
||
</Link>
|
||
<Link
|
||
to="/settings/deadlines"
|
||
className="block p-4 bg-white border border-gray-200 rounded-lg shadow-sm hover:shadow-md hover:border-blue-300 transition-all group"
|
||
>
|
||
<div className="flex items-start gap-4">
|
||
<div className="p-2 bg-blue-50 rounded-lg group-hover:bg-blue-100 transition-colors">
|
||
<Clock className="w-6 h-6 text-blue-600" />
|
||
</div>
|
||
<div className="flex-1">
|
||
<h3 className="font-semibold text-gray-900 group-hover:text-blue-600 transition-colors flex items-center gap-2">
|
||
Fristenschwellen
|
||
<ChevronRight className="w-4 h-4 opacity-0 group-hover:opacity-100 transition-opacity" />
|
||
</h3>
|
||
<p className="text-sm text-gray-500 mt-1">Konfigurieren Sie die Farbkodierung für Vertragsfristen im Cockpit.</p>
|
||
</div>
|
||
</div>
|
||
</Link>
|
||
<Link
|
||
to="/settings/bank-data"
|
||
className="block p-4 bg-white border border-gray-200 rounded-lg shadow-sm hover:shadow-md hover:border-blue-300 transition-all group"
|
||
>
|
||
<div className="flex items-start gap-4">
|
||
<div className="p-2 bg-blue-50 rounded-lg group-hover:bg-blue-100 transition-colors">
|
||
<Landmark className="w-6 h-6 text-blue-600" />
|
||
</div>
|
||
<div className="flex-1">
|
||
<h3 className="font-semibold text-gray-900 group-hover:text-blue-600 transition-colors flex items-center gap-2">
|
||
Bankdaten (BLZ)
|
||
<ChevronRight className="w-4 h-4 opacity-0 group-hover:opacity-100 transition-opacity" />
|
||
</h3>
|
||
<p className="text-sm text-gray-500 mt-1">Datenstand der Bankleitzahlen (BIC/Bank aus IBAN) + Auto-Update-Intervall.</p>
|
||
</div>
|
||
</div>
|
||
</Link>
|
||
<Link
|
||
to="/settings/pdf-templates"
|
||
className="block p-4 bg-white border border-gray-200 rounded-lg shadow-sm hover:shadow-md hover:border-blue-300 transition-all group"
|
||
>
|
||
<div className="flex items-start gap-4">
|
||
<div className="p-2 bg-blue-50 rounded-lg group-hover:bg-blue-100 transition-colors">
|
||
<FileText className="w-6 h-6 text-blue-600" />
|
||
</div>
|
||
<div className="flex-1">
|
||
<h3 className="font-semibold text-gray-900 group-hover:text-blue-600 transition-colors flex items-center gap-2">
|
||
Auftragsvorlagen
|
||
<ChevronRight className="w-4 h-4 opacity-0 group-hover:opacity-100 transition-opacity" />
|
||
</h3>
|
||
<p className="text-sm text-gray-500 mt-1">PDF-Vorlagen für Auftragsformulare hochladen und Felder zuordnen.</p>
|
||
</div>
|
||
</div>
|
||
</Link>
|
||
{hasPermission('email-providers:read') && (
|
||
<Link
|
||
to="/settings/email-providers"
|
||
className="block p-4 bg-white border border-gray-200 rounded-lg shadow-sm hover:shadow-md hover:border-blue-300 transition-all group"
|
||
>
|
||
<div className="flex items-start gap-4">
|
||
<div className="p-2 bg-blue-50 rounded-lg group-hover:bg-blue-100 transition-colors">
|
||
<Mail className="w-6 h-6 text-blue-600" />
|
||
</div>
|
||
<div className="flex-1">
|
||
<h3 className="font-semibold text-gray-900 group-hover:text-blue-600 transition-colors flex items-center gap-2">
|
||
Email-Provisionierung
|
||
<ChevronRight className="w-4 h-4 opacity-0 group-hover:opacity-100 transition-opacity" />
|
||
</h3>
|
||
<p className="text-sm text-gray-500 mt-1">Konfigurieren Sie die automatische E-Mail-Erstellung für Kunden-E-Mail-Adressen.</p>
|
||
</div>
|
||
</div>
|
||
</Link>
|
||
)}
|
||
<Link
|
||
to="/settings/database-backup"
|
||
className="block p-4 bg-white border border-gray-200 rounded-lg shadow-sm hover:shadow-md hover:border-blue-300 transition-all group"
|
||
>
|
||
<div className="flex items-start gap-4">
|
||
<div className="p-2 bg-blue-50 rounded-lg group-hover:bg-blue-100 transition-colors">
|
||
<Database className="w-6 h-6 text-blue-600" />
|
||
</div>
|
||
<div className="flex-1">
|
||
<h3 className="font-semibold text-gray-900 group-hover:text-blue-600 transition-colors flex items-center gap-2">
|
||
Datenbank & Zurücksetzen
|
||
<ChevronRight className="w-4 h-4 opacity-0 group-hover:opacity-100 transition-opacity" />
|
||
</h3>
|
||
<p className="text-sm text-gray-500 mt-1">Backups erstellen, wiederherstellen oder auf Werkseinstellungen zurücksetzen.</p>
|
||
</div>
|
||
</div>
|
||
</Link>
|
||
<Link
|
||
to="/settings/factory-defaults"
|
||
className="block p-4 bg-white border border-gray-200 rounded-lg shadow-sm hover:shadow-md hover:border-blue-300 transition-all group"
|
||
>
|
||
<div className="flex items-start gap-4">
|
||
<div className="p-2 bg-blue-50 rounded-lg group-hover:bg-blue-100 transition-colors">
|
||
<PackageCheck className="w-6 h-6 text-blue-600" />
|
||
</div>
|
||
<div className="flex-1">
|
||
<h3 className="font-semibold text-gray-900 group-hover:text-blue-600 transition-colors flex items-center gap-2">
|
||
Factory-Defaults
|
||
<ChevronRight className="w-4 h-4 opacity-0 group-hover:opacity-100 transition-opacity" />
|
||
</h3>
|
||
<p className="text-sm text-gray-500 mt-1">Stammdaten-Kataloge (Anbieter, Tarife, PDF-Vorlagen) exportieren – ohne Kundendaten.</p>
|
||
</div>
|
||
</div>
|
||
</Link>
|
||
{hasPermission('audit:read') && (
|
||
<Link
|
||
to="/settings/audit-logs"
|
||
className="block p-4 bg-white border border-gray-200 rounded-lg shadow-sm hover:shadow-md hover:border-blue-300 transition-all group"
|
||
>
|
||
<div className="flex items-start gap-4">
|
||
<div className="p-2 bg-blue-50 rounded-lg group-hover:bg-blue-100 transition-colors">
|
||
<FileText className="w-6 h-6 text-blue-600" />
|
||
</div>
|
||
<div className="flex-1">
|
||
<h3 className="font-semibold text-gray-900 group-hover:text-blue-600 transition-colors flex items-center gap-2">
|
||
Audit-Protokoll
|
||
<ChevronRight className="w-4 h-4 opacity-0 group-hover:opacity-100 transition-opacity" />
|
||
</h3>
|
||
<p className="text-sm text-gray-500 mt-1">Protokollierte API-Zugriffe und Änderungen einsehen.</p>
|
||
{hasPermission('developer:access') && (
|
||
<p className="text-xs text-purple-500 mt-1 flex items-center gap-1">
|
||
<Code className="w-3 h-3" />
|
||
Sichtbar durch Entwicklerzugriff
|
||
</p>
|
||
)}
|
||
</div>
|
||
</div>
|
||
</Link>
|
||
)}
|
||
{hasPermission('gdpr:admin') && (
|
||
<Link
|
||
to="/settings/email-logs"
|
||
className="block p-4 bg-white border border-gray-200 rounded-lg shadow-sm hover:shadow-md hover:border-blue-300 transition-all group"
|
||
>
|
||
<div className="flex items-start gap-4">
|
||
<div className="p-2 bg-blue-50 rounded-lg group-hover:bg-blue-100 transition-colors">
|
||
<Mail className="w-6 h-6 text-blue-600" />
|
||
</div>
|
||
<div className="flex-1">
|
||
<h3 className="font-semibold text-gray-900 group-hover:text-blue-600 transition-colors flex items-center gap-2">
|
||
E-Mail-Versandlog
|
||
<ChevronRight className="w-4 h-4 opacity-0 group-hover:opacity-100 transition-opacity" />
|
||
</h3>
|
||
<p className="text-sm text-gray-500 mt-1">Alle gesendeten E-Mails mit SMTP-Details und Status einsehen.</p>
|
||
</div>
|
||
</div>
|
||
</Link>
|
||
)}
|
||
{hasPermission('settings:read') && (
|
||
<Link
|
||
to="/settings/monitoring"
|
||
className="block p-4 bg-white border border-gray-200 rounded-lg shadow-sm hover:shadow-md hover:border-orange-300 transition-all group"
|
||
>
|
||
<div className="flex items-start gap-4">
|
||
<div className="p-2 bg-orange-50 rounded-lg group-hover:bg-orange-100 transition-colors">
|
||
<ShieldAlert className="w-6 h-6 text-orange-600" />
|
||
</div>
|
||
<div className="flex-1">
|
||
<h3 className="font-semibold text-gray-900 group-hover:text-orange-600 transition-colors flex items-center gap-2">
|
||
Sicherheits-Monitoring
|
||
<ChevronRight className="w-4 h-4 opacity-0 group-hover:opacity-100 transition-opacity" />
|
||
</h3>
|
||
<p className="text-sm text-gray-500 mt-1">
|
||
Login-Fehlversuche, IDOR-Abwehr, SSRF-Blocks etc. + Alert-E-Mail-Adresse konfigurieren.
|
||
</p>
|
||
</div>
|
||
</div>
|
||
</Link>
|
||
)}
|
||
{hasPermission('settings:read') && (
|
||
<Link
|
||
to="/settings/rate-limits"
|
||
className="block p-4 bg-white border border-gray-200 rounded-lg shadow-sm hover:shadow-md hover:border-orange-300 transition-all group"
|
||
>
|
||
<div className="flex items-start gap-4">
|
||
<div className="p-2 bg-orange-50 rounded-lg group-hover:bg-orange-100 transition-colors">
|
||
<ShieldOff className="w-6 h-6 text-orange-600" />
|
||
</div>
|
||
<div className="flex-1">
|
||
<h3 className="font-semibold text-gray-900 group-hover:text-orange-600 transition-colors flex items-center gap-2">
|
||
Rate-Limit-Sperren
|
||
<ChevronRight className="w-4 h-4 opacity-0 group-hover:opacity-100 transition-opacity" />
|
||
</h3>
|
||
<p className="text-sm text-gray-500 mt-1">
|
||
Aktuell gesperrte IP-Adressen anzeigen und ggf. wieder freigeben.
|
||
</p>
|
||
</div>
|
||
</div>
|
||
</Link>
|
||
)}
|
||
{hasPermission('gdpr:admin') && (
|
||
<Link
|
||
to="/settings/gdpr"
|
||
className="block p-4 bg-white border border-gray-200 rounded-lg shadow-sm hover:shadow-md hover:border-blue-300 transition-all group"
|
||
>
|
||
<div className="flex items-start gap-4">
|
||
<div className="p-2 bg-blue-50 rounded-lg group-hover:bg-blue-100 transition-colors">
|
||
<Shield className="w-6 h-6 text-blue-600" />
|
||
</div>
|
||
<div className="flex-1">
|
||
<h3 className="font-semibold text-gray-900 group-hover:text-blue-600 transition-colors flex items-center gap-2">
|
||
DSGVO-Dashboard
|
||
<ChevronRight className="w-4 h-4 opacity-0 group-hover:opacity-100 transition-opacity" />
|
||
</h3>
|
||
<p className="text-sm text-gray-500 mt-1">Löschanfragen, Datenexporte und Einwilligungen verwalten.</p>
|
||
{hasPermission('developer:access') && (
|
||
<p className="text-xs text-purple-500 mt-1 flex items-center gap-1">
|
||
<Code className="w-3 h-3" />
|
||
Sichtbar durch Entwicklerzugriff
|
||
</p>
|
||
)}
|
||
</div>
|
||
</div>
|
||
</Link>
|
||
)}
|
||
{hasPermission('gdpr:admin') && (
|
||
<Link
|
||
to="/settings/privacy-policy"
|
||
className="block p-4 bg-white border border-gray-200 rounded-lg shadow-sm hover:shadow-md hover:border-blue-300 transition-all group"
|
||
>
|
||
<div className="flex items-start gap-4">
|
||
<div className="p-2 bg-blue-50 rounded-lg group-hover:bg-blue-100 transition-colors">
|
||
<FileEdit className="w-6 h-6 text-blue-600" />
|
||
</div>
|
||
<div className="flex-1">
|
||
<h3 className="font-semibold text-gray-900 group-hover:text-blue-600 transition-colors flex items-center gap-2">
|
||
Datenschutzerklärung
|
||
<ChevronRight className="w-4 h-4 opacity-0 group-hover:opacity-100 transition-opacity" />
|
||
</h3>
|
||
<p className="text-sm text-gray-500 mt-1">Datenschutzerklärung bearbeiten mit Platzhaltern für Kundendaten.</p>
|
||
{hasPermission('developer:access') && (
|
||
<p className="text-xs text-purple-500 mt-1 flex items-center gap-1">
|
||
<Code className="w-3 h-3" />
|
||
Sichtbar durch Entwicklerzugriff
|
||
</p>
|
||
)}
|
||
</div>
|
||
</div>
|
||
</Link>
|
||
)}
|
||
{hasPermission('gdpr:admin') && (
|
||
<Link
|
||
to="/settings/authorization-template"
|
||
className="block p-4 bg-white border border-gray-200 rounded-lg shadow-sm hover:shadow-md hover:border-blue-300 transition-all group"
|
||
>
|
||
<div className="flex items-start gap-4">
|
||
<div className="p-2 bg-blue-50 rounded-lg group-hover:bg-blue-100 transition-colors">
|
||
<FileEdit className="w-6 h-6 text-blue-600" />
|
||
</div>
|
||
<div className="flex-1">
|
||
<h3 className="font-semibold text-gray-900 group-hover:text-blue-600 transition-colors flex items-center gap-2">
|
||
Vollmacht-Vorlage
|
||
<ChevronRight className="w-4 h-4 opacity-0 group-hover:opacity-100 transition-opacity" />
|
||
</h3>
|
||
<p className="text-sm text-gray-500 mt-1">Vollmacht-Vorlage für Vertreterregelungen bearbeiten.</p>
|
||
</div>
|
||
</div>
|
||
</Link>
|
||
)}
|
||
{hasPermission('gdpr:admin') && (
|
||
<Link
|
||
to="/settings/imprint"
|
||
className="block p-4 bg-white border border-gray-200 rounded-lg shadow-sm hover:shadow-md hover:border-blue-300 transition-all group"
|
||
>
|
||
<div className="flex items-start gap-4">
|
||
<div className="p-2 bg-blue-50 rounded-lg group-hover:bg-blue-100 transition-colors">
|
||
<FileEdit className="w-6 h-6 text-blue-600" />
|
||
</div>
|
||
<div className="flex-1">
|
||
<h3 className="font-semibold text-gray-900 group-hover:text-blue-600 transition-colors flex items-center gap-2">
|
||
Impressum
|
||
<ChevronRight className="w-4 h-4 opacity-0 group-hover:opacity-100 transition-opacity" />
|
||
</h3>
|
||
<p className="text-sm text-gray-500 mt-1">Impressum für das Kundenportal bearbeiten.</p>
|
||
</div>
|
||
</div>
|
||
</Link>
|
||
)}
|
||
{hasPermission('gdpr:admin') && (
|
||
<Link
|
||
to="/settings/website-privacy-policy"
|
||
className="block p-4 bg-white border border-gray-200 rounded-lg shadow-sm hover:shadow-md hover:border-blue-300 transition-all group"
|
||
>
|
||
<div className="flex items-start gap-4">
|
||
<div className="p-2 bg-blue-50 rounded-lg group-hover:bg-blue-100 transition-colors">
|
||
<FileEdit className="w-6 h-6 text-blue-600" />
|
||
</div>
|
||
<div className="flex-1">
|
||
<h3 className="font-semibold text-gray-900 group-hover:text-blue-600 transition-colors flex items-center gap-2">
|
||
Website-Datenschutzerklärung
|
||
<ChevronRight className="w-4 h-4 opacity-0 group-hover:opacity-100 transition-opacity" />
|
||
</h3>
|
||
<p className="text-sm text-gray-500 mt-1">Datenschutzerklärung für das Kundenportal bearbeiten.</p>
|
||
</div>
|
||
</div>
|
||
</Link>
|
||
)}
|
||
</div>
|
||
</div>
|
||
)}
|
||
|
||
{/* Persönliche Einstellungen */}
|
||
<div className="mb-8">
|
||
<h2 className="text-lg font-semibold mb-4 text-gray-700">Persönlich</h2>
|
||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||
<Link
|
||
to="/settings/view"
|
||
className="block p-4 bg-white border border-gray-200 rounded-lg shadow-sm hover:shadow-md hover:border-blue-300 transition-all group"
|
||
>
|
||
<div className="flex items-start gap-4">
|
||
<div className="p-2 bg-blue-50 rounded-lg group-hover:bg-blue-100 transition-colors">
|
||
<Eye className="w-6 h-6 text-blue-600" />
|
||
</div>
|
||
<div className="flex-1">
|
||
<h3 className="font-semibold text-gray-900 group-hover:text-blue-600 transition-colors flex items-center gap-2">
|
||
Ansicht
|
||
<ChevronRight className="w-4 h-4 opacity-0 group-hover:opacity-100 transition-opacity" />
|
||
</h3>
|
||
<p className="text-sm text-gray-500 mt-1">Passen Sie die Darstellung der Anwendung an.</p>
|
||
</div>
|
||
</div>
|
||
</Link>
|
||
</div>
|
||
</div>
|
||
|
||
{hasPermission('developer:access') && (
|
||
<Card title="Entwickleroptionen" className="mb-6">
|
||
<div className="flex items-center justify-between">
|
||
<div className="flex items-center gap-3">
|
||
<Code className="w-5 h-5 text-gray-500" />
|
||
<div>
|
||
<p className="font-medium">Entwicklermodus</p>
|
||
<p className="text-sm text-gray-500">
|
||
Aktiviert erweiterte Funktionen wie direkten Datenbankzugriff
|
||
</p>
|
||
</div>
|
||
</div>
|
||
<label className="relative inline-flex items-center cursor-pointer">
|
||
<input
|
||
type="checkbox"
|
||
checked={developerMode}
|
||
onChange={(e) => setDeveloperMode(e.target.checked)}
|
||
className="sr-only peer"
|
||
/>
|
||
<div className="w-11 h-6 bg-gray-200 peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-blue-300 rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-blue-600"></div>
|
||
</label>
|
||
</div>
|
||
{developerMode && (
|
||
<div className="mt-4 p-3 bg-yellow-50 border border-yellow-200 rounded-lg">
|
||
<p className="text-sm text-yellow-800">
|
||
<strong>Warnung:</strong> Der Entwicklermodus ermöglicht direkten Zugriff auf die Datenbank.
|
||
Unsachgemäße Änderungen können zu Datenverlust oder Inkonsistenzen führen.
|
||
</p>
|
||
</div>
|
||
)}
|
||
</Card>
|
||
)}
|
||
|
||
<Card title="Über">
|
||
<dl className="space-y-3">
|
||
<div>
|
||
<dt className="text-sm text-gray-500">Version</dt>
|
||
<dd>1.0.0</dd>
|
||
</div>
|
||
<div>
|
||
<dt className="text-sm text-gray-500">System</dt>
|
||
<dd>OpenCRM</dd>
|
||
</div>
|
||
</dl>
|
||
</Card>
|
||
</div>
|
||
);
|
||
}
|