'use client' import React, { useEffect, useState, useCallback, use } from 'react' import { useRouter } from 'next/navigation' import { ClassificationBadge } from '../../_components/ClassificationBadge' interface CRAProject { id: string name: string cra_classification: string | null conformity_path: string | null status: string } type PathId = 'self_assessment' | 'harmonized_standard' | 'eucc' | 'notified_body' interface PathOption { id: PathId modul: string title: string short: string details: string[] available?: boolean // false = rechtlich vorgesehen, aber noch nicht nutzbar note?: string } const PATHS: PathOption[] = [ { id: 'self_assessment', modul: 'Modul A', title: 'Selbstbewertung (interne Kontrolle)', short: 'Hersteller erklaert die Konformitaet selbst', details: [ 'Hersteller fuehrt die Konformitaetsbewertung selbst durch', 'Geringster externer Aufwand, schnelle Umsetzung', 'Nur fuer Standard- und (mit Norm) wichtige Klasse-I-Produkte', 'Technische Dokumentation + Konformitaetserklaerung bleiben Pflicht', ], }, { id: 'harmonized_standard', modul: 'Konformitaetsvermutung', title: 'Harmonisierte Normen', short: 'Vermutungswirkung durch eine harmonisierte EU-Norm', available: false, note: 'Fuer den CRA noch keine harmonisierte Norm veroeffentlicht — Entwuerfe erwartet ~Ende 2026, Listung im Amtsblatt voraussichtlich 2027.', details: [ 'Kein eigenes Modul, sondern Grundlage der Konformitaetsvermutung', 'Wer danach baut, gilt als CRA-konform und darf (Standard/Klasse I) selbst bewerten', 'Bis dahin ggf. ueber gemeinsame Spezifikationen der Kommission (Art. 27)', ], }, { id: 'eucc', modul: 'EUCC', title: 'EU-Cybersicherheitszertifikat', short: 'Zertifizierung nach EUCC-Schema (Common-Criteria-basiert)', details: [ 'EUCC-Zertifikat (in der Regel Stufe „substanziell")', 'Eigener Weg unter dem Cybersecurity Act, keine benannte Stelle noetig', 'Hohe Anerkennung in EU + Drittstaaten, ITSEF-Pruefung', 'Regulaerer Weg fuer wichtige Klasse II und kritische Produkte', ], }, { id: 'notified_body', modul: 'Modul B+C', title: 'Benannte Stelle (Baumusterpruefung)', short: 'Dritte Stelle prueft (EU-Baumusterpruefung + Produktionskontrolle)', details: [ 'EU-Baumusterpruefung (Modul B) durch akkreditierte benannte Stelle', 'gefolgt von Produktionskontrolle (Modul C); alternativ volle QS (Modul H)', 'Pflichtweg fuer wichtige Klasse II und kritische Produkte (Annex IV)', 'Hoechste Auditierbarkeit, hoechste Laufzeit + Kosten', ], }, ] const ALLOWED: Record = { STANDARD: ['self_assessment', 'harmonized_standard', 'eucc', 'notified_body'], IMPORTANT_I: ['self_assessment', 'harmonized_standard', 'eucc', 'notified_body'], // Klasse II darf nicht selbst bewerten; harmonisierte Norm allein genuegt nicht. IMPORTANT_II: ['eucc', 'notified_body'], CRITICAL: ['eucc', 'notified_body'], } const DEFAULT_FOR: Record = { STANDARD: 'self_assessment', IMPORTANT_I: 'self_assessment', IMPORTANT_II: 'notified_body', CRITICAL: 'notified_body', } export default function PathSelectPage({ params, }: { params: Promise<{ projectId: string }> }) { const { projectId } = use(params) const router = useRouter() const [project, setProject] = useState(null) const [selected, setSelected] = useState(null) const [loading, setLoading] = useState(true) const [saving, setSaving] = useState(false) const [error, setError] = useState('') const tenant = '9282a473-5c95-4b3a-bf78-0ecc0ec71d3e' const load = useCallback(async () => { try { const res = await fetch(`/api/sdk/v1/cra/projects/${projectId}`, { headers: { 'X-Tenant-ID': tenant }, }) if (!res.ok) throw new Error(await res.text()) const p: CRAProject = await res.json() setProject(p) if (p.conformity_path) { setSelected(p.conformity_path as PathId) } else if (p.cra_classification && DEFAULT_FOR[p.cra_classification]) { setSelected(DEFAULT_FOR[p.cra_classification]) } } catch (e) { setError(e instanceof Error ? e.message : 'Fehler beim Laden') } finally { setLoading(false) } }, [projectId]) useEffect(() => { load() }, [load]) const submit = async () => { if (!selected) return setSaving(true) setError('') try { const res = await fetch(`/api/sdk/v1/cra/projects/${projectId}/path-select`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-Tenant-ID': tenant }, body: JSON.stringify({ conformity_path: selected }), }) if (!res.ok) throw new Error(await res.text()) router.push(`/sdk/cra/${projectId}`) } catch (e) { setError(e instanceof Error ? e.message : 'Speichern fehlgeschlagen') } finally { setSaving(false) } } if (loading) return

Laedt...

if (!project) return null if (!project.cra_classification) { return (

Bitte erst den Scope-Check ausfuehren. → Zum Scope-Check

) } const allowedPaths = ALLOWED[project.cra_classification] || [] return (
← Zurueck zum Projekt

Konformitaetspfad waehlen

Schritt 3 von 3 — basierend auf der Klassifikation siehst du die zulaessigen Pfade.

Klassifikation:
{error && (
{error}
)}
{PATHS.map(path => { const allowed = allowedPaths.includes(path.id) const available = path.available !== false const selectable = allowed && available const isSelected = selected === path.id return ( ) })}
{selected ? ( <>Ausgewaehlt: {PATHS.find(p => p.id === selected)?.title} ) : ( 'Keine Auswahl getroffen' )}
) }