Break 838-line page.tsx into _types.ts, _data.ts (templates),
_components/{AddRequirementForm,RequirementCard,LoadingSkeleton}.tsx,
and _hooks/useRequirementsData.ts. page.tsx is now 246 LOC (wiring
only). No behavior changes.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
99 lines
3.9 KiB
TypeScript
99 lines
3.9 KiB
TypeScript
'use client'
|
|
|
|
import { useState } from 'react'
|
|
import { RiskSeverity } from '@/lib/sdk'
|
|
import { AddRequirementData } from '../_types'
|
|
|
|
export function AddRequirementForm({
|
|
onSubmit,
|
|
onCancel,
|
|
}: {
|
|
onSubmit: (data: AddRequirementData) => void
|
|
onCancel: () => void
|
|
}) {
|
|
const [formData, setFormData] = useState<AddRequirementData>({
|
|
regulation: '',
|
|
article: '',
|
|
title: '',
|
|
description: '',
|
|
criticality: 'MEDIUM' as RiskSeverity,
|
|
})
|
|
|
|
return (
|
|
<div className="bg-white rounded-xl border border-gray-200 p-6">
|
|
<h3 className="text-lg font-semibold text-gray-900 mb-4">Neue Anforderung</h3>
|
|
<div className="space-y-4">
|
|
<div className="grid grid-cols-2 gap-4">
|
|
<div>
|
|
<label className="block text-sm font-medium text-gray-700 mb-1">Verordnung *</label>
|
|
<input
|
|
type="text"
|
|
value={formData.regulation}
|
|
onChange={e => setFormData({ ...formData, regulation: e.target.value })}
|
|
placeholder="z.B. DSGVO"
|
|
className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-purple-500 focus:border-transparent"
|
|
/>
|
|
</div>
|
|
<div>
|
|
<label className="block text-sm font-medium text-gray-700 mb-1">Artikel</label>
|
|
<input
|
|
type="text"
|
|
value={formData.article}
|
|
onChange={e => setFormData({ ...formData, article: e.target.value })}
|
|
placeholder="z.B. Art. 6"
|
|
className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-purple-500 focus:border-transparent"
|
|
/>
|
|
</div>
|
|
</div>
|
|
<div>
|
|
<label className="block text-sm font-medium text-gray-700 mb-1">Titel *</label>
|
|
<input
|
|
type="text"
|
|
value={formData.title}
|
|
onChange={e => setFormData({ ...formData, title: e.target.value })}
|
|
placeholder="z.B. Rechtmaessigkeit der Verarbeitung"
|
|
className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-purple-500 focus:border-transparent"
|
|
/>
|
|
</div>
|
|
<div>
|
|
<label className="block text-sm font-medium text-gray-700 mb-1">Beschreibung</label>
|
|
<textarea
|
|
value={formData.description}
|
|
onChange={e => setFormData({ ...formData, description: e.target.value })}
|
|
placeholder="Beschreiben Sie die Anforderung..."
|
|
rows={3}
|
|
className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-purple-500 focus:border-transparent"
|
|
/>
|
|
</div>
|
|
<div>
|
|
<label className="block text-sm font-medium text-gray-700 mb-1">Kritikalitaet</label>
|
|
<select
|
|
value={formData.criticality}
|
|
onChange={e => setFormData({ ...formData, criticality: e.target.value as RiskSeverity })}
|
|
className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-purple-500 focus:border-transparent"
|
|
>
|
|
<option value="LOW">Niedrig</option>
|
|
<option value="MEDIUM">Mittel</option>
|
|
<option value="HIGH">Hoch</option>
|
|
<option value="CRITICAL">Kritisch</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
<div className="mt-6 flex items-center justify-end gap-3">
|
|
<button onClick={onCancel} className="px-4 py-2 text-gray-600 hover:bg-gray-100 rounded-lg transition-colors">
|
|
Abbrechen
|
|
</button>
|
|
<button
|
|
onClick={() => onSubmit(formData)}
|
|
disabled={!formData.title || !formData.regulation}
|
|
className={`px-6 py-2 rounded-lg font-medium transition-colors ${
|
|
formData.title && formData.regulation ? 'bg-purple-600 text-white hover:bg-purple-700' : 'bg-gray-200 text-gray-400 cursor-not-allowed'
|
|
}`}
|
|
>
|
|
Hinzufuegen
|
|
</button>
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|