diff --git a/admin-compliance/app/sdk/iace/[projectId]/_components/VariantPanel.tsx b/admin-compliance/app/sdk/iace/[projectId]/_components/VariantPanel.tsx new file mode 100644 index 0000000..6db00e1 --- /dev/null +++ b/admin-compliance/app/sdk/iace/[projectId]/_components/VariantPanel.tsx @@ -0,0 +1,253 @@ +'use client' + +import { useState, useEffect, useCallback } from 'react' +import Link from 'next/link' + +interface VariantProject { + id: string + machine_name: string + description?: string + status: string + hazard_count?: number + parent_project_id?: string +} + +interface VariantGapResponse { + base_project: { id: string; name: string; hazard_count: number; measure_count: number } + variant: { id: string; name: string; hazard_count: number; measure_count: number } + gap: { additional_hazards: number; additional_measures: number; categories_affected: string[] } +} + +interface Props { + projectId: string + parentProjectId?: string | null + parentProjectName?: string +} + +export function VariantPanel({ projectId, parentProjectId, parentProjectName }: Props) { + const [variants, setVariants] = useState([]) + const [gapMap, setGapMap] = useState>({}) + const [loading, setLoading] = useState(true) + const [showCreate, setShowCreate] = useState(false) + const [creating, setCreating] = useState(false) + const [name, setName] = useState('') + const [description, setDescription] = useState('') + + const fetchVariants = useCallback(async () => { + try { + const res = await fetch(`/api/sdk/v1/iace/projects/${projectId}/variants`) + if (!res.ok) { + setVariants([]) + return + } + const json = await res.json() + const list: VariantProject[] = json.variants || json.projects || [] + setVariants(list) + + // Fetch gap analysis for this project + const gapRes = await fetch(`/api/sdk/v1/iace/projects/${projectId}/variant-gap`) + if (gapRes.ok) { + const gapJson = await gapRes.json() + const gaps: Record = {} + // Could be a single gap or array — handle both + if (Array.isArray(gapJson)) { + for (const g of gapJson) { + gaps[g.variant?.id] = g + } + } else if (gapJson.variant) { + gaps[gapJson.variant.id] = gapJson + } + setGapMap(gaps) + } + } catch { + setVariants([]) + } finally { + setLoading(false) + } + }, [projectId]) + + useEffect(() => { + fetchVariants() + }, [fetchVariants]) + + async function handleCreate() { + if (!name.trim()) return + setCreating(true) + try { + const res = await fetch(`/api/sdk/v1/iace/projects/${projectId}/variants`, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + machine_name: name.trim(), + description: description.trim(), + }), + }) + if (res.ok) { + setName('') + setDescription('') + setShowCreate(false) + fetchVariants() + } + } catch { + // silently handle + } finally { + setCreating(false) + } + } + + // If this project IS a variant, show link to base project + if (parentProjectId) { + return ( +
+
+
+ + + +
+
+

Variante

+

+ Dieses Projekt ist eine Variante des Basis-Projekts +

+
+ + {parentProjectName || 'Basis-Projekt'} + + + + +
+
+ ) + } + + if (loading) return null + if (variants.length === 0 && !showCreate) { + return ( +
+
+
+
+ + + +
+
+

Keine Varianten

+

Erstellen Sie Varianten fuer verschiedene Betriebsarten

+
+
+ +
+ {renderCreateDialog()} +
+ ) + } + + function renderCreateDialog() { + if (!showCreate) return null + return ( +
+

Neue Variante erstellen

+ setName(e.target.value)} + className="w-full px-3 py-2 text-sm border border-gray-300 rounded-lg bg-white dark:bg-gray-800 dark:border-gray-600 dark:text-white focus:ring-2 focus:ring-purple-500 focus:border-transparent" + /> +