'use client' import { useState, useEffect } from 'react' import { useParams, useRouter } from 'next/navigation' interface ChecklistItem { requirement_id: string title: string article?: string status: string auditor_notes: string signed_off_by: string | null signed_off_at: string | null } interface SessionDetail { id: string name: string description?: string auditor_name: string auditor_email?: string auditor_organization?: string status: string total_items: number completed_items: number compliant_count: number non_compliant_count: number completion_percentage: number created_at: string started_at?: string completed_at?: string } export default function AuditReportDetailPage() { const params = useParams() const router = useRouter() const sessionId = params.sessionId as string const [session, setSession] = useState(null) const [items, setItems] = useState([]) const [loading, setLoading] = useState(true) const [error, setError] = useState(null) const [pdfLanguage, setPdfLanguage] = useState<'de' | 'en'>('de') const [generatingPdf, setGeneratingPdf] = useState(false) useEffect(() => { const fetchData = async () => { try { setLoading(true) // Fetch session details const sessRes = await fetch(`/api/sdk/v1/compliance/audit/sessions`) if (sessRes.ok) { const data = await sessRes.json() const sessions = data.sessions || [] const found = sessions.find((s: SessionDetail) => s.id === sessionId) if (found) setSession(found) } // Fetch checklist items const checkRes = await fetch(`/api/sdk/v1/compliance/audit/checklist/${sessionId}`) if (checkRes.ok) { const data = await checkRes.json() const checklistItems = data.items || data.checklist || data if (Array.isArray(checklistItems)) { setItems(checklistItems) } } } catch (err) { setError(err instanceof Error ? err.message : 'Laden fehlgeschlagen') } finally { setLoading(false) } } if (sessionId) fetchData() }, [sessionId]) const handleSignOff = async (requirementId: string, status: string, notes: string) => { try { const res = await fetch( `/api/sdk/v1/compliance/audit/checklist/${sessionId}/items/${requirementId}/sign-off`, { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ status, auditor_notes: notes }), } ) if (res.ok) { setItems(prev => prev.map(item => item.requirement_id === requirementId ? { ...item, status, auditor_notes: notes, signed_off_by: 'Aktueller Benutzer', signed_off_at: new Date().toISOString() } : item ) ) } } catch { // Silently fail } } const handlePdfDownload = async () => { setGeneratingPdf(true) setError(null) try { const res = await fetch(`/api/sdk/v1/compliance/audit/sessions/${sessionId}/report/pdf?language=${pdfLanguage}`) if (!res.ok) throw new Error('PDF-Generierung fehlgeschlagen') const blob = await res.blob() const url = window.URL.createObjectURL(blob) const a = document.createElement('a') a.href = url a.download = `audit-report-${sessionId}.pdf` document.body.appendChild(a) a.click() window.URL.revokeObjectURL(url) document.body.removeChild(a) } catch (err) { setError(err instanceof Error ? err.message : 'PDF-Download fehlgeschlagen') } finally { setGeneratingPdf(false) } } const statusBadgeStyles: Record = { draft: 'bg-slate-100 text-slate-700', in_progress: 'bg-blue-100 text-blue-700', completed: 'bg-green-100 text-green-700', archived: 'bg-purple-100 text-purple-700', } const statusLabels: Record = { draft: 'Entwurf', in_progress: 'In Bearbeitung', completed: 'Abgeschlossen', archived: 'Archiviert', } const compliantCount = items.filter(i => i.status === 'compliant').length const nonCompliantCount = items.filter(i => i.status === 'non_compliant' || i.status === 'non-compliant').length const pendingCount = items.filter(i => !i.status || i.status === 'not_assessed' || i.status === 'pending').length if (loading) { return (
{[1, 2, 3].map(i => (
))}
) } return (
{/* Back Button + Title */}

{session?.name || 'Audit Report'}

{session && ( {statusLabels[session.status] || session.status} )}
{session && (
Auditor: {session.auditor_name} {session.auditor_organization && | {session.auditor_organization}} | Erstellt: {new Date(session.created_at).toLocaleDateString('de-DE')}
)}
{/* Error */} {error && (
{error}
)} {/* Progress */} {session && (

Fortschritt

= 80 ? 'text-green-600' : session.completion_percentage >= 50 ? 'text-yellow-600' : 'text-red-600' }`}> {session.completion_percentage}%
= 80 ? 'bg-green-500' : session.completion_percentage >= 50 ? 'bg-yellow-500' : 'bg-red-500' }`} style={{ width: `${session.completion_percentage}%` }} />
{compliantCount}
Konform
{nonCompliantCount}
Nicht konform
{pendingCount}
Ausstehend
)} {/* Checklist Items */}

Pruefpunkte ({items.length})

{items.map((item) => ( ))}
{items.length === 0 && !loading && (

Keine Pruefpunkte

Diese Session hat noch keine Checklist-Items.

)}
) } function ChecklistItemRow({ item, onSignOff, readOnly, }: { item: ChecklistItem onSignOff: (requirementId: string, status: string, notes: string) => void readOnly: boolean }) { const [editing, setEditing] = useState(false) const [notes, setNotes] = useState(item.auditor_notes || '') const statusColors: Record = { compliant: 'border-green-200 bg-green-50', non_compliant: 'border-red-200 bg-red-50', 'non-compliant': 'border-red-200 bg-red-50', partially_compliant: 'border-yellow-200 bg-yellow-50', not_assessed: 'border-gray-200 bg-gray-50', pending: 'border-gray-200 bg-gray-50', } const statusLabels: Record = { compliant: 'Konform', non_compliant: 'Nicht konform', 'non-compliant': 'Nicht konform', partially_compliant: 'Teilweise', not_assessed: 'Nicht geprueft', pending: 'Ausstehend', } return (
{item.article && ( {item.article} )} {statusLabels[item.status] || item.status}

{item.title}

{item.auditor_notes && !editing && (

{item.auditor_notes}

)} {item.signed_off_by && (

Geprueft von {item.signed_off_by} {item.signed_off_at && ` am ${new Date(item.signed_off_at).toLocaleDateString('de-DE')}`}

)}
{!readOnly && (
)}
{editing && (