'use client' import { useState, useEffect, useCallback } from 'react' import { useParams } from 'next/navigation' type Clarification = { id: string question: string source: string category: 'manufacturer' | 'pattern_norm' | string norm_references?: string[] affected_hazard_ids: string[] affected_hazard_names: string[] status: 'open' | 'in_progress' | 'answered' | 'not_relevant' answer?: 'ja' | 'nein' | 'teilweise' | '' reasoning?: string answered_by?: string answered_at?: string } type ListResponse = { clarifications: Clarification[] open_count: number answered_count: number total: number } const CATEGORY_LABEL: Record = { manufacturer: 'Hersteller', pattern_norm: 'Norm / Pattern', } const STATUS_LABEL: Record = { open: 'Offen', in_progress: 'In Klärung', answered: 'Beantwortet', not_relevant: 'Nicht relevant', } const STATUS_COLOR: Record = { open: 'bg-orange-100 text-orange-800', in_progress: 'bg-yellow-100 text-yellow-800', answered: 'bg-green-100 text-green-800', not_relevant: 'bg-gray-100 text-gray-700', } export default function ClarificationsPage() { const params = useParams() const projectId = params.projectId as string const [data, setData] = useState(null) const [loading, setLoading] = useState(true) const [error, setError] = useState(null) const [editing, setEditing] = useState(null) const [filter, setFilter] = useState<'all' | 'open' | 'answered'>('open') const [searchQuery, setSearchQuery] = useState('') const load = useCallback(async () => { setLoading(true) setError(null) try { const r = await fetch(`/api/sdk/v1/iace/projects/${projectId}/clarifications`) if (!r.ok) throw new Error(`HTTP ${r.status}`) const json: ListResponse = await r.json() setData(json) } catch (e) { setError(e instanceof Error ? e.message : String(e)) } finally { setLoading(false) } }, [projectId]) useEffect(() => { load() }, [load]) const filtered = (data?.clarifications ?? []).filter(c => { if (filter === 'open' && (c.status === 'answered' || c.status === 'not_relevant')) return false if (filter === 'answered' && c.status !== 'answered' && c.status !== 'not_relevant') return false if (searchQuery) { const q = searchQuery.toLowerCase() if (!c.question.toLowerCase().includes(q) && !c.source.toLowerCase().includes(q)) return false } return true }) const groupedBySource: Record = {} for (const c of filtered) { const key = c.source if (!groupedBySource[key]) groupedBySource[key] = [] groupedBySource[key].push(c) } return (

Klärungen mit dem Anlagenbauer

Standardisierte Prüffragen aus Norm- und Herstellerwissen. Eine Antwort gilt für alle referenzierten Gefährdungen.

{data && (
)}
{(['open', 'answered', 'all'] as const).map(f => ( ))}
setSearchQuery(e.target.value)} className="flex-1 max-w-sm border rounded px-3 py-1.5 text-sm" />
{loading &&
Lade Klärungen…
} {error &&
Fehler: {error}
} {!loading && data && Object.keys(groupedBySource).length === 0 && (
Keine Klärungen für die aktuelle Auswahl.
)} {!loading && data && Object.entries(groupedBySource).map(([source, items]) => (

{CATEGORY_LABEL[items[0].category] || items[0].category} {source}

{items.map(c => (
{c.question}
Betrifft {c.affected_hazard_ids.length} Gefährdung {c.affected_hazard_ids.length !== 1 ? 'en' : ''} {c.affected_hazard_names.length > 0 && ( — {c.affected_hazard_names.slice(0, 2).join('; ')}{c.affected_hazard_names.length > 2 ? `, +${c.affected_hazard_names.length - 2} weitere` : ''} )}
{c.norm_references && c.norm_references.length > 0 && (
Norm: {c.norm_references.join(' | ')}
)} {c.status === 'answered' && c.reasoning && (
Antwort ({c.answer}): {c.reasoning} {c.answered_by && ( — {c.answered_by}, {c.answered_at?.slice(0, 10)} )}
)}
{STATUS_LABEL[c.status]}
))}
))} {editing && ( setEditing(null)} onSaved={() => { setEditing(null) load() }} /> )}
) } function Badge({ color, label }: { color: string; label: string }) { return {label} } function AnswerModal({ clarification, projectId, onClose, onSaved, }: { clarification: Clarification projectId: string onClose: () => void onSaved: () => void }) { const [status, setStatus] = useState(clarification.status) const [answer, setAnswer] = useState<'ja' | 'nein' | 'teilweise' | ''>( (clarification.answer as 'ja' | 'nein' | 'teilweise' | '') || '' ) const [reasoning, setReasoning] = useState(clarification.reasoning || '') const [answeredBy, setAnsweredBy] = useState(clarification.answered_by || '') const [saving, setSaving] = useState(false) const [error, setError] = useState(null) const save = async () => { setSaving(true) setError(null) try { const r = await fetch( `/api/sdk/v1/iace/projects/${projectId}/clarifications/${encodeURIComponent(clarification.id)}/answer`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ status, answer, reasoning, answered_by: answeredBy }), } ) if (!r.ok) throw new Error(`HTTP ${r.status}`) onSaved() } catch (e) { setError(e instanceof Error ? e.message : String(e)) } finally { setSaving(false) } } return (
e.stopPropagation()}>
{clarification.source}
{clarification.question}
{(['open', 'in_progress', 'answered', 'not_relevant'] as const).map(s => ( ))}
{(status === 'answered' || status === 'in_progress') && ( <>
{(['ja', 'teilweise', 'nein'] as const).map(a => ( ))}
)}