Files
breakpilot-lehrer/admin-lehrer/components/companion/companion-mode/EventsCard.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

174 lines
4.9 KiB
TypeScript

'use client'
import { Calendar, FileQuestion, Users, Clock, ChevronRight } from 'lucide-react'
import { UpcomingEvent, EventType } from '@/lib/companion/types'
import { EVENT_TYPE_CONFIG } from '@/lib/companion/constants'
interface EventsCardProps {
events: UpcomingEvent[]
onEventClick?: (event: UpcomingEvent) => void
loading?: boolean
maxItems?: number
}
const iconMap: Record<string, React.ComponentType<{ className?: string }>> = {
FileQuestion,
Users,
Clock,
Calendar,
}
function getEventIcon(type: EventType) {
const config = EVENT_TYPE_CONFIG[type]
const Icon = iconMap[config.icon] || Calendar
return { Icon, ...config }
}
function formatEventDate(dateStr: string, inDays: number): string {
if (inDays === 0) return 'Heute'
if (inDays === 1) return 'Morgen'
if (inDays < 7) return `In ${inDays} Tagen`
const date = new Date(dateStr)
return date.toLocaleDateString('de-DE', {
weekday: 'short',
day: 'numeric',
month: 'short',
})
}
interface EventItemProps {
event: UpcomingEvent
onClick?: () => void
}
function EventItem({ event, onClick }: EventItemProps) {
const { Icon, color, bg } = getEventIcon(event.type)
const isUrgent = event.inDays <= 2
return (
<button
onClick={onClick}
className={`
w-full flex items-center gap-3 p-3 rounded-lg
transition-all duration-200
hover:bg-slate-50
${isUrgent ? 'bg-red-50/50' : ''}
`}
>
<div className={`p-2 rounded-lg ${bg}`}>
<Icon className={`w-4 h-4 ${color}`} />
</div>
<div className="flex-1 text-left min-w-0">
<p className="font-medium text-slate-900 truncate">{event.title}</p>
<p className={`text-sm ${isUrgent ? 'text-red-600 font-medium' : 'text-slate-500'}`}>
{formatEventDate(event.date, event.inDays)}
</p>
</div>
<ChevronRight className="w-4 h-4 text-slate-400 flex-shrink-0" />
</button>
)
}
export function EventsCard({
events,
onEventClick,
loading,
maxItems = 5,
}: EventsCardProps) {
const displayEvents = events.slice(0, maxItems)
if (loading) {
return (
<div className="bg-white border border-slate-200 rounded-xl p-6">
<div className="flex items-center gap-2 mb-4">
<Calendar className="w-5 h-5 text-blue-500" />
<h3 className="font-semibold text-slate-900">Termine</h3>
</div>
<div className="space-y-2">
{[1, 2, 3].map((i) => (
<div key={i} className="h-14 bg-slate-100 rounded-lg animate-pulse" />
))}
</div>
</div>
)
}
if (events.length === 0) {
return (
<div className="bg-white border border-slate-200 rounded-xl p-6">
<div className="flex items-center gap-2 mb-4">
<Calendar className="w-5 h-5 text-blue-500" />
<h3 className="font-semibold text-slate-900">Termine</h3>
</div>
<div className="text-center py-6">
<Calendar className="w-10 h-10 text-slate-300 mx-auto mb-2" />
<p className="text-sm text-slate-500">Keine anstehenden Termine</p>
</div>
</div>
)
}
return (
<div className="bg-white border border-slate-200 rounded-xl p-6">
<div className="flex items-center justify-between mb-4">
<div className="flex items-center gap-2">
<Calendar className="w-5 h-5 text-blue-500" />
<h3 className="font-semibold text-slate-900">Termine</h3>
</div>
<span className="text-sm text-slate-500">
{events.length} Termin{events.length !== 1 ? 'e' : ''}
</span>
</div>
<div className="space-y-1">
{displayEvents.map((event) => (
<EventItem
key={event.id}
event={event}
onClick={() => onEventClick?.(event)}
/>
))}
</div>
{events.length > maxItems && (
<button className="w-full mt-3 py-2 text-sm text-slate-600 hover:text-slate-900 hover:bg-slate-50 rounded-lg transition-colors">
Alle {events.length} anzeigen
</button>
)}
</div>
)
}
/**
* Compact inline version for header/toolbar
*/
export function EventsInline({ events }: { events: UpcomingEvent[] }) {
const nextEvent = events[0]
if (!nextEvent) {
return (
<div className="flex items-center gap-2 text-sm text-slate-500">
<Calendar className="w-4 h-4" />
<span>Keine Termine</span>
</div>
)
}
const { Icon, color } = getEventIcon(nextEvent.type)
const isUrgent = nextEvent.inDays <= 2
return (
<div className={`flex items-center gap-2 text-sm ${isUrgent ? 'text-red-600' : 'text-slate-600'}`}>
<Icon className={`w-4 h-4 ${color}`} />
<span className="truncate max-w-[150px]">{nextEvent.title}</span>
<span className="text-slate-400">-</span>
<span className={isUrgent ? 'font-medium' : ''}>
{formatEventDate(nextEvent.date, nextEvent.inDays)}
</span>
</div>
)
}