Files
breakpilot-compliance/admin-compliance/app/sdk/evidence/_components/RejectModal.tsx
Sharang Parnerkar 1fcd8244b1 refactor(admin): split evidence, process-tasks, iace/hazards pages
Extract components and hooks into _components/ and _hooks/ subdirectories
to reduce each page.tsx to under 500 LOC (was 1545/1383/1316).

Final line counts: evidence=213, process-tasks=304, hazards=157.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-16 17:12:15 +02:00

77 lines
3.3 KiB
TypeScript

'use client'
import { useState } from 'react'
import type { DisplayEvidence } from './EvidenceTypes'
export function RejectModal({ evidence, onClose, onSuccess }: {
evidence: DisplayEvidence
onClose: () => void
onSuccess: () => void
}) {
const [reviewedBy, setReviewedBy] = useState('')
const [rejectionReason, setRejectionReason] = useState('')
const [submitting, setSubmitting] = useState(false)
const [error, setError] = useState<string | null>(null)
const handleSubmit = async () => {
if (!reviewedBy.trim()) { setError('Bitte E-Mail-Adresse angeben'); return }
if (!rejectionReason.trim()) { setError('Bitte Ablehnungsgrund angeben'); return }
setSubmitting(true)
setError(null)
try {
const res = await fetch(`/api/sdk/v1/compliance/evidence/${evidence.id}/reject`, {
method: 'PATCH',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ reviewed_by: reviewedBy, rejection_reason: rejectionReason }),
})
if (!res.ok) {
const err = await res.json().catch(() => ({ detail: 'Ablehnung fehlgeschlagen' }))
throw new Error(typeof err.detail === 'string' ? err.detail : JSON.stringify(err.detail))
}
onSuccess()
} catch (err) {
setError(err instanceof Error ? err.message : 'Unbekannter Fehler')
} finally {
setSubmitting(false)
}
}
return (
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black/50" onClick={onClose}>
<div className="bg-white rounded-2xl shadow-xl w-full max-w-lg mx-4 p-6" onClick={e => e.stopPropagation()}>
<h2 className="text-xl font-bold text-gray-900 mb-4">Evidence Ablehnen</h2>
<p className="text-sm text-gray-500 mb-4">{evidence.name}</p>
<div className="mb-4">
<label className="block text-sm font-medium text-gray-700 mb-1">Reviewer (E-Mail)</label>
<input type="email" value={reviewedBy} onChange={e => setReviewedBy(e.target.value)}
placeholder="reviewer@unternehmen.de"
className="w-full border border-gray-300 rounded-lg px-3 py-2 text-sm focus:ring-2 focus:ring-red-500 focus:border-transparent" />
</div>
<div className="mb-4">
<label className="block text-sm font-medium text-gray-700 mb-1">Ablehnungsgrund</label>
<textarea value={rejectionReason} onChange={e => setRejectionReason(e.target.value)}
placeholder="Bitte beschreiben Sie den Grund fuer die Ablehnung..."
rows={4}
className="w-full border border-gray-300 rounded-lg px-3 py-2 text-sm focus:ring-2 focus:ring-red-500 focus:border-transparent resize-none" />
</div>
{error && (
<div className="mb-4 p-3 bg-red-50 border border-red-200 rounded-lg text-sm text-red-700">{error}</div>
)}
<div className="flex justify-end gap-3">
<button onClick={onClose} className="px-4 py-2 text-sm text-gray-600 hover:bg-gray-100 rounded-lg transition-colors">
Abbrechen
</button>
<button onClick={handleSubmit} disabled={submitting}
className="px-4 py-2 text-sm bg-red-600 text-white rounded-lg hover:bg-red-700 transition-colors disabled:opacity-50">
{submitting ? 'Wird abgelehnt...' : 'Ablehnen'}
</button>
</div>
</div>
</div>
)
}