Files
breakpilot-lehrer/website/app/admin/sbom/wizard/page.tsx
Benjamin Admin 451365a312 [split-required] Split remaining 500-680 LOC files (final batch)
website (17 pages + 3 components):
- multiplayer/wizard, middleware/wizard+test-wizard, communication
- builds/wizard, staff-search, voice, sbom/wizard
- foerderantrag, mail/tasks, tools/communication, sbom
- compliance/evidence, uni-crawler, brandbook (already done)
- CollectionsTab, IngestionTab, RiskHeatmap

backend-lehrer (5 files):
- letters_api (641 → 2), certificates_api (636 → 2)
- alerts_agent/db/models (636 → 3)
- llm_gateway/communication_service (614 → 2)
- game/database already done in prior batch

klausur-service (2 files):
- hybrid_vocab_extractor (664 → 2)
- klausur-service/frontend: api.ts (620 → 3), EHUploadWizard (591 → 2)

voice-service (3 files):
- bqas/rag_judge (618 → 3), runner (529 → 2)
- enhanced_task_orchestrator (519 → 2)

studio-v2 (6 files):
- korrektur/[klausurId] (578 → 4), fairness (569 → 2)
- AlertsWizard (552 → 2), OnboardingWizard (513 → 2)
- korrektur/api.ts (506 → 3), geo-lernwelt (501 → 2)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-25 08:56:45 +02:00

165 lines
5.2 KiB
TypeScript

'use client'
/**
* SBOM (Software Bill of Materials) - Lern-Wizard
*
* Interaktiver Wizard zum Verstehen der SBOM
*/
import { useState } from 'react'
import Link from 'next/link'
import { INITIAL_STEPS, WizardStep } from './_components/types'
import { WizardStepper, EducationCard } from './_components/WizardComponents'
import { CategoryDemo } from './_components/CategoryDemo'
export default function SBOMWizardPage() {
const [currentStep, setCurrentStep] = useState(0)
const [steps, setSteps] = useState<WizardStep[]>(INITIAL_STEPS)
const currentStepData = steps[currentStep]
const isWelcome = currentStepData?.id === 'welcome'
const isSummary = currentStepData?.id === 'summary'
const goToNext = () => {
if (currentStep < steps.length - 1) {
setSteps(prev => prev.map((step, idx) =>
idx === currentStep && step.status === 'pending'
? { ...step, status: 'completed' }
: step
))
setCurrentStep(prev => prev + 1)
}
}
const goToPrev = () => {
if (currentStep > 0) {
setCurrentStep(prev => prev - 1)
}
}
const handleStepClick = (index: number) => {
setCurrentStep(index)
}
return (
<div className="min-h-screen bg-slate-100 py-8">
<div className="max-w-4xl mx-auto px-4">
{/* Header */}
<div className="bg-white rounded-lg shadow-lg p-6 mb-6">
<div className="flex items-center justify-between">
<div>
<h1 className="text-2xl font-bold text-slate-800">📋 SBOM Lern-Wizard</h1>
<p className="text-slate-600 mt-1">
Software Bill of Materials verstehen
</p>
</div>
<Link
href="/admin/sbom"
className="text-primary-600 hover:text-primary-800 text-sm"
>
Zurueck zur SBOM
</Link>
</div>
</div>
{/* Stepper */}
<div className="bg-white rounded-lg shadow-lg p-6 mb-6">
<WizardStepper
steps={steps}
currentStep={currentStep}
onStepClick={handleStepClick}
/>
</div>
{/* Content */}
<div className="bg-white rounded-lg shadow-lg p-6">
{/* Step Header */}
<div className="flex items-center mb-6">
<span className="text-4xl mr-4">{currentStepData?.icon}</span>
<div>
<h2 className="text-xl font-bold text-slate-800">
Schritt {currentStep + 1}: {currentStepData?.name}
</h2>
<p className="text-slate-500 text-sm">
{currentStep + 1} von {steps.length}
</p>
</div>
</div>
{/* Education Card */}
<EducationCard stepId={currentStepData?.id || ''} />
{/* Category Demo */}
<CategoryDemo stepId={currentStepData?.id || ''} />
{/* Welcome Start Button */}
{isWelcome && (
<div className="text-center py-8">
<button
onClick={goToNext}
className="bg-primary-600 text-white px-8 py-3 rounded-lg font-medium hover:bg-primary-700 transition-colors"
>
🚀 Lern-Tour starten
</button>
</div>
)}
{/* Summary Actions */}
{isSummary && (
<div className="text-center py-6 space-y-4">
<div className="flex justify-center gap-4">
<Link
href="/admin/sbom"
className="px-6 py-3 bg-primary-600 text-white rounded-lg font-medium hover:bg-primary-700 transition-colors"
>
📋 Zur SBOM
</Link>
<button
onClick={() => {
setCurrentStep(0)
setSteps(INITIAL_STEPS.map(s => ({ ...s, status: 'pending' })))
}}
className="px-6 py-3 bg-slate-200 text-slate-700 rounded-lg font-medium hover:bg-slate-300 transition-colors"
>
🔄 Wizard neu starten
</button>
</div>
</div>
)}
{/* Navigation */}
{!isWelcome && (
<div className="flex justify-between mt-8 pt-6 border-t">
<button
onClick={goToPrev}
disabled={currentStep === 0}
className={`px-6 py-2 rounded-lg transition-colors ${
currentStep === 0
? 'bg-slate-200 text-slate-400 cursor-not-allowed'
: 'bg-slate-200 text-slate-700 hover:bg-slate-300'
}`}
>
Zurueck
</button>
{!isSummary && (
<button
onClick={goToNext}
className="bg-primary-600 text-white px-6 py-2 rounded-lg hover:bg-primary-700 transition-colors"
>
Weiter
</button>
)}
</div>
)}
</div>
{/* Footer Info */}
<div className="text-center text-slate-500 text-sm mt-6">
BreakPilot SBOM - 180+ Komponenten dokumentiert
</div>
</div>
</div>
)
}