Files
breakpilot-lehrer/studio-v2/components/companion/CompanionDashboard.tsx
Benjamin Boenisch 5a31f52310 Initial commit: breakpilot-lehrer - Lehrer KI Platform
Services: Admin-Lehrer, Backend-Lehrer, Studio v2, Website,
Klausur-Service, School-Service, Voice-Service, Geo-Service,
BreakPilot Drive, Agent-Core

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-11 23:47:26 +01:00

223 lines
6.4 KiB
TypeScript

'use client'
import { useState, useEffect, useCallback } from 'react'
import { Settings, MessageSquare, HelpCircle, Timer } from 'lucide-react'
import { TeacherSettings, FeedbackType } from '@/lib/companion/types'
import { DEFAULT_TEACHER_SETTINGS, STORAGE_KEYS } from '@/lib/companion/constants'
// Components
import { LessonStartForm } from './lesson-mode/LessonStartForm'
import { LessonActiveView } from './lesson-mode/LessonActiveView'
import { LessonEndedView } from './lesson-mode/LessonEndedView'
import { SettingsModal } from './modals/SettingsModal'
import { FeedbackModal } from './modals/FeedbackModal'
import { OnboardingModal } from './modals/OnboardingModal'
// Hooks
import { useLessonSession } from '@/hooks/companion/useLessonSession'
import { useKeyboardShortcuts } from '@/hooks/companion/useKeyboardShortcuts'
export function CompanionDashboard() {
// Modal states
const [showSettings, setShowSettings] = useState(false)
const [showFeedback, setShowFeedback] = useState(false)
const [showOnboarding, setShowOnboarding] = useState(false)
// Settings
const [settings, setSettings] = useState<TeacherSettings>(DEFAULT_TEACHER_SETTINGS)
// Load settings from localStorage
useEffect(() => {
const stored = localStorage.getItem(STORAGE_KEYS.SETTINGS)
if (stored) {
try {
const parsed = JSON.parse(stored)
setSettings({ ...DEFAULT_TEACHER_SETTINGS, ...parsed })
} catch {
// Invalid stored settings
}
}
// Check if onboarding needed
const onboardingStored = localStorage.getItem(STORAGE_KEYS.ONBOARDING_STATE)
if (!onboardingStored) {
setShowOnboarding(true)
}
}, [])
// Lesson session hook
const {
session,
startLesson,
endLesson,
clearSession,
pauseLesson,
resumeLesson,
extendTime,
skipPhase,
saveReflection,
addHomework,
removeHomework,
isPaused,
} = useLessonSession({
onOvertimeStart: () => {
if (settings.soundNotifications) {
// TODO: Play notification sound
}
},
})
// Handle pause/resume toggle
const handlePauseToggle = useCallback(() => {
if (isPaused) {
resumeLesson()
} else {
pauseLesson()
}
}, [isPaused, pauseLesson, resumeLesson])
// Keyboard shortcuts
useKeyboardShortcuts({
onPauseResume: session ? handlePauseToggle : undefined,
onExtend: session && !isPaused ? () => extendTime(5) : undefined,
onNextPhase: session && !isPaused ? skipPhase : undefined,
onCloseModal: () => {
setShowSettings(false)
setShowFeedback(false)
setShowOnboarding(false)
},
enabled: settings.showKeyboardShortcuts,
})
// Handle settings save
const handleSaveSettings = (newSettings: TeacherSettings) => {
setSettings(newSettings)
localStorage.setItem(STORAGE_KEYS.SETTINGS, JSON.stringify(newSettings))
}
// Handle feedback submit
const handleFeedbackSubmit = async (type: FeedbackType, title: string, description: string) => {
const response = await fetch('/api/companion/feedback', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
type,
title,
description,
sessionId: session?.sessionId,
}),
})
if (!response.ok) {
throw new Error('Failed to submit feedback')
}
}
// Handle onboarding complete
const handleOnboardingComplete = (data: { state?: string; schoolType?: string }) => {
localStorage.setItem(STORAGE_KEYS.ONBOARDING_STATE, JSON.stringify({
...data,
completed: true,
completedAt: new Date().toISOString(),
}))
setShowOnboarding(false)
setSettings({ ...settings, onboardingCompleted: true })
}
// Determine current view based on session status
const renderContent = () => {
if (!session) {
return <LessonStartForm onStart={startLesson} />
}
if (session.status === 'completed') {
return (
<LessonEndedView
session={session}
onSaveReflection={saveReflection}
onAddHomework={addHomework}
onRemoveHomework={removeHomework}
onStartNew={clearSession}
/>
)
}
// in_progress or paused
return (
<LessonActiveView
session={session}
onPauseToggle={handlePauseToggle}
onExtendTime={extendTime}
onSkipPhase={skipPhase}
onEndLesson={endLesson}
/>
)
}
return (
<div className={`min-h-[calc(100vh-200px)] ${settings.highContrastMode ? 'high-contrast' : ''}`}>
{/* Header */}
<div className="flex items-center justify-between mb-6">
<div className="flex items-center gap-3">
<div className="p-2 bg-blue-100 rounded-lg">
<Timer className="w-5 h-5 text-blue-600" />
</div>
<h2 className="text-lg font-semibold text-slate-900">Unterrichtsstunde</h2>
</div>
<div className="flex items-center gap-2">
{/* Feedback Button */}
<button
onClick={() => setShowFeedback(true)}
className="p-2 text-slate-500 hover:text-slate-700 hover:bg-slate-100 rounded-lg transition-colors"
title="Feedback"
>
<MessageSquare className="w-5 h-5" />
</button>
{/* Settings Button */}
<button
onClick={() => setShowSettings(true)}
className="p-2 text-slate-500 hover:text-slate-700 hover:bg-slate-100 rounded-lg transition-colors"
title="Einstellungen"
>
<Settings className="w-5 h-5" />
</button>
{/* Help Button */}
<button
onClick={() => setShowOnboarding(true)}
className="p-2 text-slate-500 hover:text-slate-700 hover:bg-slate-100 rounded-lg transition-colors"
title="Hilfe"
>
<HelpCircle className="w-5 h-5" />
</button>
</div>
</div>
{/* Main Content */}
{renderContent()}
{/* Modals */}
<SettingsModal
isOpen={showSettings}
onClose={() => setShowSettings(false)}
settings={settings}
onSave={handleSaveSettings}
/>
<FeedbackModal
isOpen={showFeedback}
onClose={() => setShowFeedback(false)}
onSubmit={handleFeedbackSubmit}
/>
<OnboardingModal
isOpen={showOnboarding}
onClose={() => setShowOnboarding(false)}
onComplete={handleOnboardingComplete}
/>
</div>
)
}