'use client' import React, { useEffect, useState, useCallback, use } from 'react' import { useRouter } from 'next/navigation' import { ClassificationBadge } from '../_components/ClassificationBadge' import { StatusStepper } from '../_components/StatusStepper' import { SeverityBadge } from '../_components/SeverityBadge' interface CRAProject { id: string name: string description: string cra_classification: string | null classification_rationale: string[] conformity_path: string | null status: string intended_use: string repo_url: string | null primary_language: string | null created_at: string updated_at: string } interface BacklogItem { rank: number req_id: string title: string category: string severity: string effort_days: number priority_score: number } interface BacklogData { days_to_ce_deadline: number deadlines: { date: string; label: string }[] total: number items: BacklogItem[] } const PATH_LABEL: Record = { self_assessment: 'Modul A — Self-Assessment', harmonized_standard: 'Modul B — Harmonized Standard', eucc: 'Modul H — EUCC', notified_body: 'Modul C — Notified Body', } export default function CRAProjectDashboard({ params, }: { params: Promise<{ projectId: string }> }) { const { projectId } = use(params) const router = useRouter() const [project, setProject] = useState(null) const [backlog, setBacklog] = useState(null) const [loading, setLoading] = useState(true) const [error, setError] = useState('') const load = useCallback(async () => { try { const headers = { 'X-Tenant-ID': '00000000-0000-0000-0000-000000000001' } const [projRes, backlogRes] = await Promise.all([ fetch(`/api/sdk/v1/cra/projects/${projectId}`, { headers }), fetch(`/api/sdk/v1/cra/projects/${projectId}/backlog`, { headers }), ]) if (!projRes.ok) throw new Error(await projRes.text()) setProject(await projRes.json()) if (backlogRes.ok) { setBacklog(await backlogRes.json()) } } catch (e) { setError(e instanceof Error ? e.message : 'Fehler beim Laden') } finally { setLoading(false) } }, [projectId]) useEffect(() => { load() }, [load]) if (loading) return

Laedt...

if (error) return

{error}

if (!project) return null const nextStep = project.status === 'draft' ? { href: `/sdk/cra/${projectId}/intake`, label: 'Intake starten' } : project.status === 'scoped' ? { href: `/sdk/cra/${projectId}/scope`, label: 'Scope-Check ausfuehren' } : project.status === 'classified' ? { href: `/sdk/cra/${projectId}/path`, label: 'Konformitaetspfad waehlen' } : project.status === 'path_selected' ? { href: null, label: 'Phase 2 (Requirements) folgt' } : { href: null, label: '' } return (

{project.name}

{project.description && (

{project.description}

)}
{/* KPI Cards */} {backlog && (
i.severity === 'CRITICAL').length} hint={`+ ${backlog.items.filter(i => i.severity === 'HIGH').length} High`} color="red" />
)} {/* Top-10 Backlog-Snippet */} {backlog && backlog.items.length > 0 && (

Top-10 Prioritaeten

Vollstaendiges Backlog →
{backlog.items.slice(0, 10).map(item => ( ))}
# Anforderung Severity Aufwand
{item.rank}
{item.title}
{item.category}
{item.effort_days} PT
)}
Noch nicht erfasst : (
{project.intended_use &&
Use: {project.intended_use}
} {project.primary_language &&
Sprache: {project.primary_language}
} {project.repo_url &&
Repo: {project.repo_url}
}
) } actionHref={`/sdk/cra/${projectId}/intake`} actionLabel={project.status === 'draft' ? 'Erfassen' : 'Bearbeiten'} /> {project.classification_rationale?.length > 0 && (
    {project.classification_rationale.map((r, i) =>
  • {r}
  • )}
)}
) : Scope-Check ausstehend } actionHref={`/sdk/cra/${projectId}/scope`} actionLabel={project.cra_classification ? 'Neu pruefen' : 'Pruefen'} /> {PATH_LABEL[project.conformity_path] || project.conformity_path} : Noch nicht gewaehlt } actionHref={project.cra_classification ? `/sdk/cra/${projectId}/path` : null} actionLabel={project.conformity_path ? 'Aendern' : 'Waehlen'} />
Aktuell: {project.status}
Aktualisiert: {new Date(project.updated_at).toLocaleString('de-DE')}
} actionHref={null} actionLabel="" />
{nextStep.href && (

Naechster Schritt

{nextStep.label}

)} {!nextStep.href && nextStep.label && (
{nextStep.label}
)} ) } function InfoCard({ title, content, actionHref, actionLabel, }: { title: string content: React.ReactNode actionHref: string | null actionLabel: string }) { return (

{title}

{actionHref && actionLabel && ( {actionLabel} )}
{content}
) } function KPICard({ label, value, hint, color, }: { label: string value: string | number hint: string color: 'blue' | 'red' | 'orange' | 'green' | 'gray' }) { const colors = { blue: 'bg-blue-50 border-blue-200 text-blue-700', red: 'bg-red-50 border-red-200 text-red-700', orange: 'bg-orange-50 border-orange-200 text-orange-700', green: 'bg-green-50 border-green-200 text-green-700', gray: 'bg-gray-50 border-gray-200 text-gray-700', } return (

{label}

{value}

{hint}

) }