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>
55 lines
2.1 KiB
TypeScript
55 lines
2.1 KiB
TypeScript
'use client'
|
|
|
|
import type { StudentWork } from '../../types'
|
|
import { STATUS_COLORS, STATUS_LABELS, getGradeLabel } from '../../types'
|
|
import { GlassCard } from './GlassCard'
|
|
|
|
interface StudentCardProps {
|
|
student: StudentWork
|
|
index: number
|
|
onClick: () => void
|
|
delay?: number
|
|
isDark?: boolean
|
|
}
|
|
|
|
export function StudentCard({ student, index, onClick, delay = 0, isDark = true }: StudentCardProps) {
|
|
const statusColor = STATUS_COLORS[student.status] || '#6b7280'
|
|
const statusLabel = STATUS_LABELS[student.status] || student.status
|
|
|
|
const hasGrade = student.status === 'COMPLETED' || student.status === 'FIRST_EXAMINER' || student.status === 'SECOND_EXAMINER'
|
|
|
|
return (
|
|
<GlassCard onClick={onClick} delay={delay} size="sm" isDark={isDark}>
|
|
<div className="flex items-center gap-4">
|
|
{/* Index/Number */}
|
|
<div className={`w-10 h-10 rounded-xl flex items-center justify-center font-medium ${isDark ? 'bg-white/10 text-white/60' : 'bg-slate-200 text-slate-600'}`}>
|
|
{index + 1}
|
|
</div>
|
|
|
|
{/* Info */}
|
|
<div className="flex-1 min-w-0">
|
|
<p className={`font-medium truncate ${isDark ? 'text-white' : 'text-slate-900'}`}>{student.anonym_id}</p>
|
|
<div className="flex items-center gap-2 mt-1">
|
|
<span
|
|
className="px-2 py-0.5 rounded-full text-xs font-medium"
|
|
style={{ backgroundColor: `${statusColor}20`, color: statusColor }}
|
|
>
|
|
{statusLabel}
|
|
</span>
|
|
{hasGrade && student.grade_points > 0 && (
|
|
<span className={`text-sm ${isDark ? 'text-white/60' : 'text-slate-500'}`}>
|
|
{student.grade_points} P ({getGradeLabel(student.grade_points)})
|
|
</span>
|
|
)}
|
|
</div>
|
|
</div>
|
|
|
|
{/* Arrow */}
|
|
<svg className={`w-5 h-5 ${isDark ? 'text-white/40' : 'text-slate-400'}`} fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 5l7 7-7 7" />
|
|
</svg>
|
|
</div>
|
|
</GlassCard>
|
|
)
|
|
}
|