Files
breakpilot-compliance/admin-compliance/app/sdk/notfallplan/_components/ConfigTab.tsx
Sharang Parnerkar ef8284dff5 refactor(admin): split dsfa/[id] and notfallplan page.tsx into colocated components
dsfa/[id]/page.tsx (1893 LOC -> 350 LOC) split into 9 components:
Section1-5Editor, SDMCoverageOverview, RAGSearchPanel, AddRiskModal,
AddMitigationModal. Page is now a thin orchestrator.

notfallplan/page.tsx (1890 LOC -> 435 LOC) split into 8 modules:
types.ts, ConfigTab, IncidentsTab, TemplatesTab, ExercisesTab, Modals,
ApiSections. All under the 500-line hard cap.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 18:51:54 +02:00

204 lines
8.4 KiB
TypeScript

'use client'
import React from 'react'
import type { NotfallplanConfig } from './types'
export function ConfigTab({
config,
setConfig,
}: {
config: NotfallplanConfig
setConfig: React.Dispatch<React.SetStateAction<NotfallplanConfig>>
}) {
return (
<div className="space-y-8">
{/* Meldewege */}
<section className="bg-white rounded-lg border p-6">
<h3 className="text-lg font-semibold mb-4">Meldewege (intern Aufsichtsbehoerde)</h3>
<p className="text-sm text-gray-500 mb-4">
Definieren Sie die interne Eskalationskette bei einer Datenpanne.
</p>
<div className="space-y-3">
{config.meldewege.map((step, idx) => (
<div key={step.id} className="flex items-center gap-3 p-3 bg-gray-50 rounded-lg">
<span className="flex-shrink-0 w-8 h-8 rounded-full bg-blue-100 text-blue-800 flex items-center justify-center text-sm font-bold">
{step.order}
</span>
<div className="flex-1 grid grid-cols-3 gap-2">
<input
type="text"
value={step.role}
onChange={e => {
const updated = [...config.meldewege]
updated[idx] = { ...updated[idx], role: e.target.value }
setConfig(prev => ({ ...prev, meldewege: updated }))
}}
placeholder="Rolle"
className="text-sm border rounded px-2 py-1"
/>
<input
type="text"
value={step.name}
onChange={e => {
const updated = [...config.meldewege]
updated[idx] = { ...updated[idx], name: e.target.value }
setConfig(prev => ({ ...prev, meldewege: updated }))
}}
placeholder="Name"
className="text-sm border rounded px-2 py-1"
/>
<input
type="text"
value={step.action}
onChange={e => {
const updated = [...config.meldewege]
updated[idx] = { ...updated[idx], action: e.target.value }
setConfig(prev => ({ ...prev, meldewege: updated }))
}}
placeholder="Aktion"
className="text-sm border rounded px-2 py-1"
/>
</div>
<div className="flex-shrink-0 text-xs text-gray-500">
max. {step.maxHours}h
</div>
</div>
))}
</div>
</section>
{/* Zustaendigkeiten */}
<section className="bg-white rounded-lg border p-6">
<h3 className="text-lg font-semibold mb-4">Zustaendigkeiten</h3>
<div className="overflow-x-auto">
<table className="w-full text-sm">
<thead>
<tr className="border-b">
<th className="text-left py-2 pr-4">Rolle</th>
<th className="text-left py-2 pr-4">Name</th>
<th className="text-left py-2 pr-4">E-Mail</th>
<th className="text-left py-2">Telefon</th>
</tr>
</thead>
<tbody>
{config.zustaendigkeiten.map((z, idx) => (
<tr key={z.id} className="border-b last:border-0">
<td className="py-2 pr-4 font-medium">{z.role}</td>
<td className="py-2 pr-4">
<input
type="text"
value={z.name}
onChange={e => {
const updated = [...config.zustaendigkeiten]
updated[idx] = { ...updated[idx], name: e.target.value }
setConfig(prev => ({ ...prev, zustaendigkeiten: updated }))
}}
placeholder="Name eingeben"
className="w-full text-sm border rounded px-2 py-1"
/>
</td>
<td className="py-2 pr-4">
<input
type="email"
value={z.email}
onChange={e => {
const updated = [...config.zustaendigkeiten]
updated[idx] = { ...updated[idx], email: e.target.value }
setConfig(prev => ({ ...prev, zustaendigkeiten: updated }))
}}
placeholder="email@example.com"
className="w-full text-sm border rounded px-2 py-1"
/>
</td>
<td className="py-2">
<input
type="tel"
value={z.phone}
onChange={e => {
const updated = [...config.zustaendigkeiten]
updated[idx] = { ...updated[idx], phone: e.target.value }
setConfig(prev => ({ ...prev, zustaendigkeiten: updated }))
}}
placeholder="+49..."
className="w-full text-sm border rounded px-2 py-1"
/>
</td>
</tr>
))}
</tbody>
</table>
</div>
</section>
{/* Aufsichtsbehoerde */}
<section className="bg-white rounded-lg border p-6">
<h3 className="text-lg font-semibold mb-4">Zustaendige Aufsichtsbehoerde</h3>
<div className="grid grid-cols-2 gap-4">
{(['name', 'state', 'email', 'phone'] as const).map(field => (
<div key={field}>
<label className="block text-sm font-medium text-gray-700 mb-1">
{field === 'name' ? 'Name' : field === 'state' ? 'Bundesland' : field === 'email' ? 'E-Mail' : 'Telefon'}
</label>
<input
type={field === 'email' ? 'email' : field === 'phone' ? 'tel' : 'text'}
value={config.aufsichtsbehoerde[field]}
onChange={e => setConfig(prev => ({
...prev,
aufsichtsbehoerde: { ...prev.aufsichtsbehoerde, [field]: e.target.value },
}))}
placeholder={field === 'name' ? 'z.B. LfD Niedersachsen' :
field === 'state' ? 'z.B. Niedersachsen' :
field === 'email' ? 'poststelle@lfd.niedersachsen.de' : '+49...'}
className="w-full text-sm border rounded px-3 py-2"
/>
</div>
))}
</div>
</section>
{/* Eskalationsstufen */}
<section className="bg-white rounded-lg border p-6">
<h3 className="text-lg font-semibold mb-4">Eskalationsstufen</h3>
<div className="space-y-4">
{config.eskalationsstufen.map((stufe) => (
<div key={stufe.id} className="p-4 bg-gray-50 rounded-lg">
<div className="flex items-center gap-3 mb-2">
<span className={`px-2 py-1 rounded text-xs font-bold ${
stufe.level === 1 ? 'bg-yellow-100 text-yellow-800' :
stufe.level === 2 ? 'bg-orange-100 text-orange-800' :
'bg-red-100 text-red-800'
}`}>
Stufe {stufe.level}
</span>
<span className="font-medium">{stufe.label}</span>
</div>
<p className="text-sm text-gray-600 mb-2">Ausloeser: {stufe.triggerCondition}</p>
<ul className="list-disc list-inside text-sm text-gray-700">
{stufe.actions.map((action, i) => (
<li key={i}>{action}</li>
))}
</ul>
</div>
))}
</div>
</section>
{/* Sofortmassnahmen-Checkliste */}
<section className="bg-white rounded-lg border p-6">
<h3 className="text-lg font-semibold mb-4">Sofortmassnahmen-Checkliste</h3>
<p className="text-sm text-gray-500 mb-4">
Diese Massnahmen sind sofort bei Entdeckung einer Datenpanne durchzufuehren.
</p>
<ul className="space-y-2">
{config.sofortmassnahmen.map((m, idx) => (
<li key={idx} className="flex items-start gap-3 p-2">
<span className="flex-shrink-0 w-6 h-6 rounded border-2 border-gray-300 mt-0.5" />
<span className="text-sm">{m}</span>
</li>
))}
</ul>
</section>
</div>
)
}