This repository has been archived on 2026-02-15. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
breakpilot-pwa/admin-v2/app/(admin)/education/foerderantrag/[applicationId]/page.tsx
BreakPilot Dev 660295e218 fix(admin-v2): Restore complete admin-v2 application
The admin-v2 application was incomplete in the repository. This commit
restores all missing components:

- Admin pages (76 pages): dashboard, ai, compliance, dsgvo, education,
  infrastructure, communication, development, onboarding, rbac
- SDK pages (45 pages): tom, dsfa, vvt, loeschfristen, einwilligungen,
  vendor-compliance, tom-generator, dsr, and more
- Developer portal (25 pages): API docs, SDK guides, frameworks
- All components, lib files, hooks, and types
- Updated package.json with all dependencies

The issue was caused by incomplete initial repository state - the full
admin-v2 codebase existed in backend/admin-v2 and docs-src/admin-v2
but was never fully synced to the main admin-v2 directory.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-08 23:40:15 -08:00

676 lines
30 KiB
TypeScript

'use client'
import { useState, useEffect } from 'react'
import { useParams, useRouter } from 'next/navigation'
import Link from 'next/link'
// Types
interface WizardStep {
number: number
id: string
title: string
subtitle: string
description: string
icon: string
is_required: boolean
is_completed: boolean
}
interface FormData {
[key: string]: any
}
const API_BASE = process.env.NEXT_PUBLIC_SDK_API_URL || 'http://localhost:8080'
// Step icons mapping
const stepIcons: Record<string, React.ReactNode> = {
'document-text': (
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" />
</svg>
),
'academic-cap': (
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 14l9-5-9-5-9 5 9 5z" />
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 14l6.16-3.422a12.083 12.083 0 01.665 6.479A11.952 11.952 0 0012 20.055a11.952 11.952 0 00-6.824-2.998 12.078 12.078 0 01.665-6.479L12 14z" />
</svg>
),
'server': (
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M5 12h14M5 12a2 2 0 01-2-2V6a2 2 0 012-2h14a2 2 0 012 2v4a2 2 0 01-2 2M5 12a2 2 0 00-2 2v4a2 2 0 002 2h14a2 2 0 002-2v-4a2 2 0 00-2-2" />
</svg>
),
'document-report': (
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 17v-2m3 2v-4m3 4v-6m2 10H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" />
</svg>
),
'currency-euro': (
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M14.121 15.536c-1.171 1.952-3.07 1.952-4.242 0-1.172-1.953-1.172-5.119 0-7.072 1.171-1.952 3.07-1.952 4.242 0M8 10.5h4m-4 3h4m9-1.5a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
),
'calculator': (
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 7h6m0 10v-3m-3 3h.01M9 17h.01M9 14h.01M12 14h.01M15 11h.01M12 11h.01M9 11h.01M7 21h10a2 2 0 002-2V5a2 2 0 00-2-2H7a2 2 0 00-2 2v14a2 2 0 002 2z" />
</svg>
),
'calendar': (
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" />
</svg>
),
'document-download': (
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 10v6m0 0l-3-3m3 3l3-3m2 8H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" />
</svg>
),
}
// Default wizard steps
const defaultSteps: WizardStep[] = [
{ number: 1, id: 'foerderprogramm', title: 'Foerderprogramm', subtitle: 'Programm & Grunddaten', description: 'Waehlen Sie das Foerderprogramm', icon: 'document-text', is_required: true, is_completed: false },
{ number: 2, id: 'schulinformationen', title: 'Schulinformationen', subtitle: 'Schule & Traeger', description: 'Angaben zur Schule', icon: 'academic-cap', is_required: true, is_completed: false },
{ number: 3, id: 'bestandsaufnahme', title: 'IT-Bestand', subtitle: 'Aktuelle Infrastruktur', description: 'IT-Bestandsaufnahme', icon: 'server', is_required: true, is_completed: false },
{ number: 4, id: 'projektbeschreibung', title: 'Projektbeschreibung', subtitle: 'Ziele & Didaktik', description: 'Projektziele beschreiben', icon: 'document-report', is_required: true, is_completed: false },
{ number: 5, id: 'investitionen', title: 'Investitionen', subtitle: 'Kostenaufstellung', description: 'Geplante Anschaffungen', icon: 'currency-euro', is_required: true, is_completed: false },
{ number: 6, id: 'finanzierungsplan', title: 'Finanzierung', subtitle: 'Budget & Eigenanteil', description: 'Finanzierungsplan', icon: 'calculator', is_required: true, is_completed: false },
{ number: 7, id: 'zeitplan', title: 'Zeitplan', subtitle: 'Laufzeit & Meilensteine', description: 'Projektlaufzeit planen', icon: 'calendar', is_required: true, is_completed: false },
{ number: 8, id: 'abschluss', title: 'Abschluss', subtitle: 'Dokumente & Pruefung', description: 'Zusammenfassung', icon: 'document-download', is_required: true, is_completed: false },
]
export default function FoerderantragWizardPage() {
const params = useParams()
const router = useRouter()
const applicationId = params.applicationId as string
const [currentStep, setCurrentStep] = useState(1)
const [steps, setSteps] = useState<WizardStep[]>(defaultSteps)
const [formData, setFormData] = useState<FormData>({})
const [isSaving, setIsSaving] = useState(false)
const [showAssistant, setShowAssistant] = useState(false)
const [assistantMessage, setAssistantMessage] = useState('')
const [assistantHistory, setAssistantHistory] = useState<{ role: string; content: string }[]>([])
const [isDemo, setIsDemo] = useState(false)
useEffect(() => {
// Check if this is a demo application
if (applicationId.startsWith('demo-')) {
setIsDemo(true)
}
loadApplication()
}, [applicationId])
const loadApplication = async () => {
// In production, load from API
// For demo, use mock data
}
const handleFieldChange = (fieldId: string, value: any) => {
setFormData(prev => ({
...prev,
[`step_${currentStep}`]: {
...prev[`step_${currentStep}`],
[fieldId]: value,
},
}))
}
const handleSaveStep = async () => {
setIsSaving(true)
try {
// Save step data
// Update step completion status
setSteps(prev => prev.map(s =>
s.number === currentStep ? { ...s, is_completed: true } : s
))
} finally {
setIsSaving(false)
}
}
const handleNextStep = async () => {
await handleSaveStep()
if (currentStep < 8) {
setCurrentStep(prev => prev + 1)
}
}
const handlePrevStep = () => {
if (currentStep > 1) {
setCurrentStep(prev => prev - 1)
}
}
const handleAskAssistant = async () => {
if (!assistantMessage.trim()) return
const userMessage = assistantMessage
setAssistantMessage('')
setAssistantHistory(prev => [...prev, { role: 'user', content: userMessage }])
// Simulate assistant response
setTimeout(() => {
const response = getAssistantResponse(userMessage, currentStep)
setAssistantHistory(prev => [...prev, { role: 'assistant', content: response }])
}, 1000)
}
const getAssistantResponse = (question: string, step: number): string => {
// Simple response logic - in production, this calls the LLM API
if (question.toLowerCase().includes('foerderquote')) {
return 'Die Foerderquote im DigitalPakt 2.0 betraegt in der Regel 90%. Das bedeutet, dass 10% der Kosten als Eigenanteil vom Schultraeger zu tragen sind. In einigen Bundeslaendern gibt es Sonderregelungen fuer finanzschwache Kommunen.'
}
if (question.toLowerCase().includes('mep') || question.toLowerCase().includes('medienentwicklungsplan')) {
return 'Der Medienentwicklungsplan (MEP) ist ein strategisches Dokument, das die paedagogischen und technischen Ziele der Schule fuer die Digitalisierung beschreibt. In den meisten Bundeslaendern ist ein MEP Voraussetzung fuer die Foerderung.'
}
if (question.toLowerCase().includes('foerderfahig')) {
return 'Foerderfahig sind unter anderem: Netzwerkinfrastruktur, WLAN, Praesentationstechnik, Endgeraete (mit Einschraenkungen), Server und lokale KI-Systeme. Nicht foerderfahig sind: Verbrauchsmaterial, laufende Betriebskosten und Cloud-Abonnements ohne lokale Alternative.'
}
return `Ich helfe Ihnen gerne bei Schritt ${step}. Haben Sie eine konkrete Frage zu den Feldern in diesem Abschnitt? Sie koennen mich auch nach Formulierungshilfen oder Erklaerungen zu Fachbegriffen fragen.`
}
const renderStepContent = () => {
const step = steps.find(s => s.number === currentStep)
if (!step) return null
switch (currentStep) {
case 1:
return <Step1Foerderprogramm formData={formData} onChange={handleFieldChange} />
case 2:
return <Step2Schulinformationen formData={formData} onChange={handleFieldChange} />
case 3:
return <Step3Bestandsaufnahme formData={formData} onChange={handleFieldChange} />
case 4:
return <Step4Projektbeschreibung formData={formData} onChange={handleFieldChange} />
case 5:
return <Step5Investitionen formData={formData} onChange={handleFieldChange} />
case 6:
return <Step6Finanzierungsplan formData={formData} onChange={handleFieldChange} />
case 7:
return <Step7Zeitplan formData={formData} onChange={handleFieldChange} />
case 8:
return <Step8Abschluss formData={formData} onChange={handleFieldChange} />
default:
return null
}
}
return (
<div className="min-h-screen bg-slate-50">
{/* Header */}
<div className="bg-white border-b border-slate-200 sticky top-0 z-20">
<div className="px-6 py-4">
<div className="flex items-center justify-between">
<div className="flex items-center gap-4">
<Link
href="/education/foerderantrag"
className="p-2 rounded-lg hover:bg-slate-100 transition-colors"
>
<svg className="w-5 h-5 text-slate-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 19l-7-7 7-7" />
</svg>
</Link>
<div>
<h1 className="font-semibold text-slate-900">Foerderantrag bearbeiten</h1>
<p className="text-sm text-slate-500">
Schritt {currentStep} von {steps.length}: {steps.find(s => s.number === currentStep)?.title}
</p>
</div>
</div>
<div className="flex items-center gap-3">
{isDemo && (
<span className="px-3 py-1 bg-amber-100 text-amber-700 text-sm font-medium rounded-full">
Demo-Modus
</span>
)}
<button
onClick={() => setShowAssistant(!showAssistant)}
className={`p-2 rounded-lg transition-colors ${showAssistant ? 'bg-blue-100 text-blue-600' : 'hover:bg-slate-100 text-slate-600'}`}
title="KI-Assistent"
>
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9.663 17h4.673M12 3v1m6.364 1.636l-.707.707M21 12h-1M4 12H3m3.343-5.657l-.707-.707m2.828 9.9a5 5 0 117.072 0l-.548.547A3.374 3.374 0 0014 18.469V19a2 2 0 11-4 0v-.531c0-.895-.356-1.754-.988-2.386l-.548-.547z" />
</svg>
</button>
<button
onClick={handleSaveStep}
disabled={isSaving}
className="px-4 py-2 bg-slate-100 text-slate-700 rounded-lg font-medium hover:bg-slate-200 disabled:opacity-50 transition-colors"
>
{isSaving ? 'Speichern...' : 'Speichern'}
</button>
</div>
</div>
</div>
{/* Progress Steps */}
<div className="px-6 pb-4 overflow-x-auto">
<div className="flex gap-1 min-w-max">
{steps.map((step) => (
<button
key={step.number}
onClick={() => setCurrentStep(step.number)}
className={`flex items-center gap-2 px-3 py-2 rounded-lg text-sm transition-all ${
currentStep === step.number
? 'bg-blue-600 text-white'
: step.is_completed
? 'bg-green-100 text-green-700 hover:bg-green-200'
: 'bg-slate-100 text-slate-600 hover:bg-slate-200'
}`}
>
<span className={`w-6 h-6 rounded-full flex items-center justify-center text-xs font-bold ${
currentStep === step.number
? 'bg-white/20'
: step.is_completed
? 'bg-green-500 text-white'
: 'bg-slate-300 text-slate-600'
}`}>
{step.is_completed && currentStep !== step.number ? (
<svg className="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={3} d="M5 13l4 4L19 7" />
</svg>
) : (
step.number
)}
</span>
<span className="hidden md:block font-medium">{step.title}</span>
</button>
))}
</div>
</div>
</div>
{/* Main Content */}
<div className="flex">
{/* Form Area */}
<div className={`flex-1 p-6 transition-all ${showAssistant ? 'pr-96' : ''}`}>
<div className="max-w-3xl mx-auto">
{/* Step Header */}
<div className="mb-8">
<div className="flex items-center gap-3 mb-2">
<div className="w-10 h-10 rounded-lg bg-blue-100 text-blue-600 flex items-center justify-center">
{stepIcons[steps.find(s => s.number === currentStep)?.icon || 'document-text']}
</div>
<div>
<h2 className="text-xl font-semibold text-slate-900">
{steps.find(s => s.number === currentStep)?.title}
</h2>
<p className="text-sm text-slate-500">
{steps.find(s => s.number === currentStep)?.description}
</p>
</div>
</div>
</div>
{/* Step Content */}
<div className="bg-white rounded-xl border border-slate-200 p-6">
{renderStepContent()}
</div>
{/* Navigation */}
<div className="flex items-center justify-between mt-6">
<button
onClick={handlePrevStep}
disabled={currentStep === 1}
className="px-6 py-3 text-slate-600 hover:text-slate-900 disabled:opacity-50 disabled:cursor-not-allowed font-medium flex items-center gap-2"
>
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 19l-7-7 7-7" />
</svg>
Zurueck
</button>
<button
onClick={handleNextStep}
className="px-6 py-3 bg-blue-600 text-white rounded-xl font-semibold hover:bg-blue-700 flex items-center gap-2 transition-colors"
>
{currentStep === 8 ? 'Abschliessen' : 'Weiter'}
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 5l7 7-7 7" />
</svg>
</button>
</div>
</div>
</div>
{/* Assistant Sidebar */}
{showAssistant && (
<div className="fixed right-0 top-0 h-full w-96 bg-white border-l border-slate-200 shadow-xl z-30 flex flex-col">
<div className="p-4 border-b border-slate-200 flex items-center justify-between">
<div className="flex items-center gap-2">
<div className="w-8 h-8 rounded-lg bg-gradient-to-br from-blue-500 to-indigo-600 flex items-center justify-center">
<svg className="w-4 h-4 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9.663 17h4.673M12 3v1m6.364 1.636l-.707.707M21 12h-1M4 12H3m3.343-5.657l-.707-.707m2.828 9.9a5 5 0 117.072 0l-.548.547A3.374 3.374 0 0014 18.469V19a2 2 0 11-4 0v-.531c0-.895-.356-1.754-.988-2.386l-.548-.547z" />
</svg>
</div>
<div>
<h3 className="font-semibold text-slate-900">KI-Assistent</h3>
<p className="text-xs text-slate-500">Ich helfe bei Fragen</p>
</div>
</div>
<button
onClick={() => setShowAssistant(false)}
className="p-2 rounded-lg hover:bg-slate-100 transition-colors"
>
<svg className="w-4 h-4 text-slate-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
</div>
{/* Chat History */}
<div className="flex-1 overflow-y-auto p-4 space-y-4">
{assistantHistory.length === 0 && (
<div className="text-center py-8">
<p className="text-slate-500 text-sm">
Stellen Sie mir Fragen zum aktuellen Schritt oder bitten Sie um Formulierungshilfen.
</p>
<div className="mt-4 space-y-2">
{['Was ist foerderfahig?', 'Erklaere die Foerderquote', 'Was ist ein MEP?'].map((q) => (
<button
key={q}
onClick={() => {
setAssistantMessage(q)
setTimeout(handleAskAssistant, 100)
}}
className="block w-full text-left px-3 py-2 bg-slate-100 rounded-lg text-sm text-slate-700 hover:bg-slate-200 transition-colors"
>
{q}
</button>
))}
</div>
</div>
)}
{assistantHistory.map((msg, idx) => (
<div
key={idx}
className={`flex ${msg.role === 'user' ? 'justify-end' : 'justify-start'}`}
>
<div
className={`max-w-[85%] p-3 rounded-xl text-sm ${
msg.role === 'user'
? 'bg-blue-600 text-white'
: 'bg-slate-100 text-slate-700'
}`}
>
{msg.content}
</div>
</div>
))}
</div>
{/* Input */}
<div className="p-4 border-t border-slate-200">
<div className="flex gap-2">
<input
type="text"
value={assistantMessage}
onChange={(e) => setAssistantMessage(e.target.value)}
onKeyDown={(e) => e.key === 'Enter' && handleAskAssistant()}
placeholder="Frage stellen..."
className="flex-1 px-3 py-2 border border-slate-200 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-blue-500"
/>
<button
onClick={handleAskAssistant}
className="p-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors"
>
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 19l9 2-9-18-9 18 9-2zm0 0v-8" />
</svg>
</button>
</div>
</div>
</div>
)}
</div>
</div>
)
}
// Step Components (simplified for now)
function Step1Foerderprogramm({ formData, onChange }: { formData: FormData; onChange: (id: string, value: any) => void }) {
return (
<div className="space-y-6">
<p className="text-slate-600">
Die Grunddaten wurden bereits beim Erstellen des Antrags festgelegt.
Sie koennen diese hier bei Bedarf anpassen.
</p>
<div className="p-4 bg-blue-50 border border-blue-200 rounded-lg">
<p className="text-sm text-blue-700">
Klicken Sie auf "Weiter" um mit den Schulinformationen fortzufahren.
</p>
</div>
</div>
)
}
function Step2Schulinformationen({ formData, onChange }: { formData: FormData; onChange: (id: string, value: any) => void }) {
return (
<div className="space-y-6">
<div>
<label className="block text-sm font-medium text-slate-700 mb-2">Schulname *</label>
<input
type="text"
className="w-full px-4 py-2 border border-slate-200 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
placeholder="z.B. Gymnasium am Beispielweg"
/>
</div>
<div>
<label className="block text-sm font-medium text-slate-700 mb-2">Schulnummer *</label>
<input
type="text"
className="w-full px-4 py-2 border border-slate-200 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
placeholder="z.B. 12345"
/>
</div>
<div className="grid grid-cols-2 gap-4">
<div>
<label className="block text-sm font-medium text-slate-700 mb-2">Anzahl Schueler</label>
<input
type="number"
className="w-full px-4 py-2 border border-slate-200 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
placeholder="z.B. 850"
/>
</div>
<div>
<label className="block text-sm font-medium text-slate-700 mb-2">Anzahl Lehrkraefte</label>
<input
type="number"
className="w-full px-4 py-2 border border-slate-200 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
placeholder="z.B. 65"
/>
</div>
</div>
</div>
)
}
function Step3Bestandsaufnahme({ formData, onChange }: { formData: FormData; onChange: (id: string, value: any) => void }) {
return (
<div className="space-y-6">
<div className="flex items-center gap-3">
<input type="checkbox" id="has_wlan" className="w-4 h-4 rounded border-slate-300" />
<label htmlFor="has_wlan" className="text-sm text-slate-700">WLAN vorhanden</label>
</div>
<div>
<label className="block text-sm font-medium text-slate-700 mb-2">Internet-Bandbreite</label>
<select className="w-full px-4 py-2 border border-slate-200 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500">
<option>Unter 16 Mbit/s</option>
<option>16-50 Mbit/s</option>
<option>50-100 Mbit/s</option>
<option>100-250 Mbit/s</option>
<option>Ueber 250 Mbit/s</option>
</select>
</div>
<div>
<label className="block text-sm font-medium text-slate-700 mb-2">Vorhandene Endgeraete</label>
<input
type="number"
className="w-full px-4 py-2 border border-slate-200 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
placeholder="Anzahl"
/>
</div>
</div>
)
}
function Step4Projektbeschreibung({ formData, onChange }: { formData: FormData; onChange: (id: string, value: any) => void }) {
return (
<div className="space-y-6">
<div>
<label className="block text-sm font-medium text-slate-700 mb-2">Kurzbeschreibung *</label>
<textarea
className="w-full px-4 py-2 border border-slate-200 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
rows={3}
placeholder="Beschreiben Sie Ihr Projekt in 2-3 Saetzen..."
/>
</div>
<div>
<label className="block text-sm font-medium text-slate-700 mb-2">Projektziele *</label>
<textarea
className="w-full px-4 py-2 border border-slate-200 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
rows={4}
placeholder="Welche konkreten Ziele verfolgen Sie?"
/>
</div>
<div>
<label className="block text-sm font-medium text-slate-700 mb-2">Paedagogisches Konzept *</label>
<textarea
className="w-full px-4 py-2 border border-slate-200 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
rows={4}
placeholder="Wie wird die Technik im Unterricht eingesetzt?"
/>
</div>
</div>
)
}
function Step5Investitionen({ formData, onChange }: { formData: FormData; onChange: (id: string, value: any) => void }) {
return (
<div className="space-y-6">
<p className="text-slate-600">
Listen Sie alle geplanten Investitionen auf. Der Wizard berechnet automatisch die Summen.
</p>
<div className="border border-slate-200 rounded-lg overflow-hidden">
<table className="w-full text-sm">
<thead className="bg-slate-50">
<tr>
<th className="px-4 py-2 text-left font-medium text-slate-700">Beschreibung</th>
<th className="px-4 py-2 text-left font-medium text-slate-700">Anzahl</th>
<th className="px-4 py-2 text-left font-medium text-slate-700">Einzelpreis</th>
<th className="px-4 py-2 text-left font-medium text-slate-700">Gesamt</th>
</tr>
</thead>
<tbody>
<tr className="border-t border-slate-200">
<td className="px-4 py-2" colSpan={4}>
<button className="text-blue-600 hover:text-blue-700 font-medium text-sm flex items-center gap-1">
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 4v16m8-8H4" />
</svg>
Position hinzufuegen
</button>
</td>
</tr>
</tbody>
</table>
</div>
</div>
)
}
function Step6Finanzierungsplan({ formData, onChange }: { formData: FormData; onChange: (id: string, value: any) => void }) {
return (
<div className="space-y-6">
<div>
<label className="block text-sm font-medium text-slate-700 mb-2">Foerderquote</label>
<div className="flex items-center gap-4">
<input
type="range"
min="50"
max="100"
defaultValue="90"
className="flex-1"
/>
<span className="text-lg font-semibold text-slate-900">90%</span>
</div>
</div>
<div className="grid grid-cols-2 gap-4">
<div className="p-4 bg-slate-50 rounded-lg">
<div className="text-sm text-slate-500">Gesamtkosten</div>
<div className="text-xl font-bold text-slate-900">0,00 EUR</div>
</div>
<div className="p-4 bg-blue-50 rounded-lg">
<div className="text-sm text-blue-600">Foerderbetrag</div>
<div className="text-xl font-bold text-blue-700">0,00 EUR</div>
</div>
</div>
</div>
)
}
function Step7Zeitplan({ formData, onChange }: { formData: FormData; onChange: (id: string, value: any) => void }) {
return (
<div className="space-y-6">
<div className="grid grid-cols-2 gap-4">
<div>
<label className="block text-sm font-medium text-slate-700 mb-2">Projektbeginn *</label>
<input
type="date"
className="w-full px-4 py-2 border border-slate-200 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
/>
</div>
<div>
<label className="block text-sm font-medium text-slate-700 mb-2">Projektende *</label>
<input
type="date"
className="w-full px-4 py-2 border border-slate-200 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
/>
</div>
</div>
<div>
<label className="block text-sm font-medium text-slate-700 mb-2">Meilensteine</label>
<p className="text-sm text-slate-500">Definieren Sie wichtige Projektmeilensteine</p>
</div>
</div>
)
}
function Step8Abschluss({ formData, onChange }: { formData: FormData; onChange: (id: string, value: any) => void }) {
return (
<div className="space-y-6">
<div className="p-4 bg-green-50 border border-green-200 rounded-lg">
<h3 className="font-semibold text-green-800">Zusammenfassung</h3>
<p className="text-sm text-green-700 mt-1">
Pruefen Sie alle Angaben und laden Sie ggf. zusaetzliche Dokumente hoch.
</p>
</div>
<div>
<label className="block text-sm font-medium text-slate-700 mb-2">Datenschutzkonzept *</label>
<textarea
className="w-full px-4 py-2 border border-slate-200 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
rows={4}
placeholder="Beschreiben Sie die Massnahmen zum Datenschutz..."
/>
</div>
<div className="p-4 bg-amber-50 border border-amber-200 rounded-lg">
<h3 className="font-semibold text-amber-800">Hinweis zur Traegerpruefung</h3>
<p className="text-sm text-amber-700 mt-1">
Der generierte Antrag ist ein antragsfaehiger ENTWURF.
Die finale Pruefung und Einreichung erfolgt durch den Schultraeger.
</p>
</div>
<div className="space-y-3">
<label className="flex items-center gap-3">
<input type="checkbox" className="w-4 h-4 rounded border-slate-300" />
<span className="text-sm text-slate-700">Ich bestaetige, dass alle Angaben nach bestem Wissen gemacht wurden</span>
</label>
<label className="flex items-center gap-3">
<input type="checkbox" className="w-4 h-4 rounded border-slate-300" />
<span className="text-sm text-slate-700">Ich habe verstanden, dass der Antrag vom Schultraeger geprueft werden muss</span>
</label>
</div>
</div>
)
}