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/studio-v2/components/companion/lesson-mode/LessonEndedView.tsx
BreakPilot Dev 754a812d4b feat(companion): Migrate Companion from admin-v2 to studio-v2 as pure lesson tool
Remove Companion module entirely from admin-v2. Rebuild in studio-v2 as a
focused lesson timer (no dashboard mode). Direct flow: start → active → ended.
Fix timer bug where lastTickRef reset prevented countdown. Add companion link
to Sidebar and i18n translations.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-09 23:50:20 +01:00

210 lines
8.1 KiB
TypeScript

'use client'
import { useState } from 'react'
import { CheckCircle, Clock, BarChart3, Plus, RefreshCw } from 'lucide-react'
import { LessonSession } from '@/lib/companion/types'
import { HomeworkSection } from './HomeworkSection'
import { ReflectionSection } from './ReflectionSection'
import {
PHASE_COLORS,
PHASE_DISPLAY_NAMES,
formatTime,
formatMinutes,
} from '@/lib/companion/constants'
interface LessonEndedViewProps {
session: LessonSession
onSaveReflection: (rating: number, notes: string, nextSteps: string) => void
onAddHomework: (title: string, dueDate: string) => void
onRemoveHomework: (id: string) => void
onStartNew: () => void
}
export function LessonEndedView({
session,
onSaveReflection,
onAddHomework,
onRemoveHomework,
onStartNew,
}: LessonEndedViewProps) {
const [activeTab, setActiveTab] = useState<'summary' | 'homework' | 'reflection'>('summary')
// Calculate analytics
const totalPlannedSeconds = session.totalPlannedDuration * 60
const totalActualSeconds = session.elapsedTime
const timeDiff = totalActualSeconds - totalPlannedSeconds
const timeDiffMinutes = Math.round(timeDiff / 60)
const startTime = new Date(session.startTime)
const endTime = session.endTime ? new Date(session.endTime) : new Date()
return (
<div className="space-y-6">
{/* Success Header */}
<div className="bg-gradient-to-r from-green-500 to-green-600 rounded-xl p-6 text-white">
<div className="flex items-center gap-4">
<div className="p-3 bg-white/20 rounded-full">
<CheckCircle className="w-8 h-8" />
</div>
<div>
<h2 className="text-2xl font-bold">Stunde beendet!</h2>
<p className="text-green-100">
{session.className} - {session.subject}
{session.topic && ` - ${session.topic}`}
</p>
</div>
</div>
</div>
{/* Tab Navigation */}
<div className="bg-white border border-slate-200 rounded-xl p-1 flex">
{[
{ id: 'summary', label: 'Zusammenfassung', icon: BarChart3 },
{ id: 'homework', label: 'Hausaufgaben', icon: Plus },
{ id: 'reflection', label: 'Reflexion', icon: RefreshCw },
].map((tab) => (
<button
key={tab.id}
onClick={() => setActiveTab(tab.id as typeof activeTab)}
className={`
flex-1 flex items-center justify-center gap-2 py-3 px-4 rounded-lg
font-medium transition-all duration-200
${activeTab === tab.id
? 'bg-slate-900 text-white'
: 'text-slate-600 hover:bg-slate-100'
}
`}
>
<tab.icon className="w-4 h-4" />
{tab.label}
</button>
))}
</div>
{/* Tab Content */}
{activeTab === 'summary' && (
<div className="space-y-6">
{/* Time Overview */}
<div className="bg-white border border-slate-200 rounded-xl p-6">
<h3 className="font-semibold text-slate-900 mb-4 flex items-center gap-2">
<Clock className="w-5 h-5 text-slate-400" />
Zeitauswertung
</h3>
<div className="grid grid-cols-3 gap-4 mb-6">
<div className="text-center p-4 bg-slate-50 rounded-xl">
<div className="text-2xl font-bold text-slate-900">
{formatTime(totalActualSeconds)}
</div>
<div className="text-sm text-slate-500">Tatsaechlich</div>
</div>
<div className="text-center p-4 bg-slate-50 rounded-xl">
<div className="text-2xl font-bold text-slate-900">
{formatMinutes(session.totalPlannedDuration)}
</div>
<div className="text-sm text-slate-500">Geplant</div>
</div>
<div className={`text-center p-4 rounded-xl ${timeDiff > 0 ? 'bg-amber-50' : 'bg-green-50'}`}>
<div className={`text-2xl font-bold ${timeDiff > 0 ? 'text-amber-600' : 'text-green-600'}`}>
{timeDiffMinutes > 0 ? '+' : ''}{timeDiffMinutes} Min
</div>
<div className={`text-sm ${timeDiff > 0 ? 'text-amber-500' : 'text-green-500'}`}>
Differenz
</div>
</div>
</div>
{/* Session Times */}
<div className="flex items-center justify-between text-sm text-slate-500 border-t border-slate-100 pt-4">
<span>Start: {startTime.toLocaleTimeString('de-DE', { hour: '2-digit', minute: '2-digit' })}</span>
<span>Ende: {endTime.toLocaleTimeString('de-DE', { hour: '2-digit', minute: '2-digit' })}</span>
</div>
</div>
{/* Phase Breakdown */}
<div className="bg-white border border-slate-200 rounded-xl p-6">
<h3 className="font-semibold text-slate-900 mb-4 flex items-center gap-2">
<BarChart3 className="w-5 h-5 text-slate-400" />
Phasen-Analyse
</h3>
<div className="space-y-4">
{session.phases.map((phase) => {
const plannedSeconds = phase.duration * 60
const actualSeconds = phase.actualTime
const diff = actualSeconds - plannedSeconds
const diffMinutes = Math.round(diff / 60)
const percentage = Math.min((actualSeconds / plannedSeconds) * 100, 150)
return (
<div key={phase.phase} className="space-y-2">
<div className="flex items-center justify-between text-sm">
<div className="flex items-center gap-2">
<div
className="w-3 h-3 rounded-full"
style={{ backgroundColor: PHASE_COLORS[phase.phase].hex }}
/>
<span className="font-medium text-slate-700">
{PHASE_DISPLAY_NAMES[phase.phase]}
</span>
</div>
<div className="flex items-center gap-3 text-slate-500">
<span>{Math.round(actualSeconds / 60)} / {phase.duration} Min</span>
<span className={`
px-2 py-0.5 rounded text-xs font-medium
${diff > 60 ? 'bg-amber-100 text-amber-700' : diff < -60 ? 'bg-blue-100 text-blue-700' : 'bg-green-100 text-green-700'}
`}>
{diffMinutes > 0 ? '+' : ''}{diffMinutes} Min
</span>
</div>
</div>
{/* Progress Bar */}
<div className="h-3 bg-slate-100 rounded-full overflow-hidden">
<div
className="h-full rounded-full transition-all duration-500"
style={{
width: `${Math.min(percentage, 100)}%`,
backgroundColor: percentage > 100
? '#f59e0b' // amber for overtime
: PHASE_COLORS[phase.phase].hex,
}}
/>
</div>
</div>
)
})}
</div>
</div>
</div>
)}
{activeTab === 'homework' && (
<HomeworkSection
homeworkList={session.homeworkList}
onAdd={onAddHomework}
onRemove={onRemoveHomework}
/>
)}
{activeTab === 'reflection' && (
<ReflectionSection
reflection={session.reflection}
onSave={onSaveReflection}
/>
)}
{/* Start New Lesson Button */}
<div className="pt-4">
<button
onClick={onStartNew}
className="w-full py-4 px-6 bg-slate-900 text-white rounded-xl font-semibold hover:bg-slate-800 transition-colors flex items-center justify-center gap-2"
>
<RefreshCw className="w-5 h-5" />
Neue Stunde starten
</button>
</div>
</div>
)
}