Files
breakpilot-lehrer/studio-v2/components/AlertsWizard.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

102 lines
6.3 KiB
TypeScript

'use client'
import { useState } from 'react'
import { useTheme } from '@/lib/ThemeContext'
import { useAlerts, lehrerThemen, AlertImportance } from '@/lib/AlertsContext'
import { Step1TopicSelection, Step2Instructions, Step3Forwarding, Step4Settings } from './alerts-wizard/AlertsWizardSteps'
interface AlertsWizardProps {
onComplete: () => void
onSkip?: () => void
}
export function AlertsWizard({ onComplete, onSkip }: AlertsWizardProps) {
const { isDark } = useTheme()
const { addTopic, updateSettings } = useAlerts()
const [step, setStep] = useState(1)
const [selectedTopics, setSelectedTopics] = useState<string[]>([])
const [customTopic, setCustomTopic] = useState({ name: '', keywords: '' })
const [rssFeedUrl, setRssFeedUrl] = useState('')
const [notificationFrequency, setNotificationFrequency] = useState<'realtime' | 'hourly' | 'daily'>('daily')
const [minImportance, setMinImportance] = useState<AlertImportance>('PRUEFEN')
const totalSteps = 4
const handleNext = () => { if (step < totalSteps) setStep(step + 1); else completeWizard() }
const handleBack = () => { if (step > 1) setStep(step - 1) }
const completeWizard = () => {
selectedTopics.forEach(topicId => {
const topic = lehrerThemen.find(t => t.name === topicId)
if (topic) {
addTopic({ id: `topic-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`, name: topic.name, keywords: topic.keywords, icon: topic.icon, isActive: true, rssFeedUrl: rssFeedUrl || undefined })
}
})
if (customTopic.name.trim()) {
addTopic({ id: `topic-${Date.now()}-custom`, name: customTopic.name, keywords: customTopic.keywords.split(',').map(k => k.trim()).filter(k => k), icon: '📌', isActive: true, rssFeedUrl: rssFeedUrl || undefined })
}
updateSettings({ notificationFrequency, minImportance, wizardCompleted: true })
onComplete()
}
const toggleTopic = (topicName: string) => {
setSelectedTopics(prev => prev.includes(topicName) ? prev.filter(t => t !== topicName) : [...prev, topicName])
}
const canProceed = () => {
if (step === 1) return selectedTopics.length > 0 || customTopic.name.trim().length > 0
return true
}
return (
<div className={`min-h-screen flex flex-col ${isDark ? 'bg-gradient-to-br from-indigo-900 via-purple-900 to-pink-800' : 'bg-gradient-to-br from-slate-100 via-blue-50 to-indigo-100'}`}>
<div className="absolute inset-0 overflow-hidden pointer-events-none">
<div className={`absolute -top-40 -right-40 w-80 h-80 rounded-full mix-blend-multiply filter blur-3xl animate-pulse ${isDark ? 'bg-amber-500 opacity-50' : 'bg-amber-300 opacity-30'}`} />
<div className={`absolute -bottom-40 -left-40 w-80 h-80 rounded-full mix-blend-multiply filter blur-3xl animate-pulse ${isDark ? 'bg-orange-500 opacity-50' : 'bg-orange-300 opacity-30'}`} style={{ animationDelay: '1s' }} />
</div>
<div className="relative z-10 flex-1 flex flex-col items-center justify-center p-8">
<div className="text-center mb-8">
<div className="flex items-center justify-center gap-3 mb-4">
<div className="w-14 h-14 rounded-2xl bg-gradient-to-br from-amber-400 to-orange-500 flex items-center justify-center text-3xl shadow-lg">🔔</div>
<div className="text-left">
<h1 className={`text-2xl font-bold ${isDark ? 'text-white' : 'text-slate-900'}`}>Google Alerts einrichten</h1>
<p className={`text-sm ${isDark ? 'text-white/60' : 'text-slate-500'}`}>Bleiben Sie informiert ueber Bildungsthemen</p>
</div>
</div>
</div>
<div className="w-full max-w-2xl mb-8">
<div className="flex items-center justify-between mb-2">
{[1, 2, 3, 4].map((s) => (
<div key={s} className={`w-10 h-10 rounded-full flex items-center justify-center font-medium transition-all ${s === step ? 'bg-gradient-to-br from-amber-400 to-orange-500 text-white scale-110 shadow-lg' : s < step ? (isDark ? 'bg-green-500/30 text-green-300' : 'bg-green-100 text-green-700') : (isDark ? 'bg-white/10 text-white/40' : 'bg-slate-200 text-slate-400')}`}>
{s < step ? '✓' : s}
</div>
))}
</div>
<div className={`h-2 rounded-full overflow-hidden ${isDark ? 'bg-white/10' : 'bg-slate-200'}`}>
<div className="h-full bg-gradient-to-r from-amber-400 to-orange-500 transition-all duration-500" style={{ width: `${((step - 1) / (totalSteps - 1)) * 100}%` }} />
</div>
</div>
<div className={`w-full max-w-2xl backdrop-blur-xl border rounded-3xl p-8 ${isDark ? 'bg-white/10 border-white/20' : 'bg-white/80 border-black/10 shadow-xl'}`}>
{step === 1 && <Step1TopicSelection selectedTopics={selectedTopics} onToggleTopic={toggleTopic} customTopic={customTopic} onCustomTopicChange={setCustomTopic} isDark={isDark} />}
{step === 2 && <Step2Instructions selectedTopics={selectedTopics} isDark={isDark} />}
{step === 3 && <Step3Forwarding rssFeedUrl={rssFeedUrl} onRssFeedUrlChange={setRssFeedUrl} isDark={isDark} />}
{step === 4 && <Step4Settings notificationFrequency={notificationFrequency} onFrequencyChange={setNotificationFrequency} minImportance={minImportance} onMinImportanceChange={setMinImportance} selectedTopics={selectedTopics} customTopic={customTopic} rssFeedUrl={rssFeedUrl} isDark={isDark} />}
</div>
<div className="flex items-center gap-4 mt-8">
{step > 1 && (<button onClick={handleBack} className={`px-6 py-3 rounded-xl font-medium transition-all ${isDark ? 'bg-white/10 text-white hover:bg-white/20' : 'bg-slate-200 text-slate-700 hover:bg-slate-300'}`}> Zurueck</button>)}
<button onClick={handleNext} disabled={!canProceed()} className={`px-8 py-3 rounded-xl font-medium transition-all ${canProceed() ? 'bg-gradient-to-r from-amber-400 to-orange-500 text-white hover:shadow-xl hover:shadow-orange-500/30 hover:scale-105' : isDark ? 'bg-white/10 text-white/30 cursor-not-allowed' : 'bg-slate-200 text-slate-400 cursor-not-allowed'}`}>
{step === totalSteps ? 'Fertig! →' : 'Weiter →'}
</button>
</div>
{onSkip && (<button onClick={onSkip} className={`mt-4 text-sm ${isDark ? 'text-white/40 hover:text-white/60' : 'text-slate-400 hover:text-slate-600'}`}>Ueberspringen (spaeter einrichten)</button>)}
</div>
</div>
)
}