[split-required] Split final batch of monoliths >1000 LOC
Python (6 files in klausur-service): - rbac.py (1,132 → 4), admin_api.py (1,012 → 4) - routes/eh.py (1,111 → 4), ocr_pipeline_geometry.py (1,105 → 5) Python (2 files in backend-lehrer): - unit_api.py (1,226 → 6), game_api.py (1,129 → 5) Website (6 page files): - 4x klausur-korrektur pages (1,249-1,328 LOC each) → shared components in website/components/klausur-korrektur/ (17 shared files) - companion (1,057 → 10), magic-help (1,017 → 8) All re-export barrels preserve backward compatibility. Zero import errors verified. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
108
website/components/klausur-korrektur/WorkspaceTopBar.tsx
Normal file
108
website/components/klausur-korrektur/WorkspaceTopBar.tsx
Normal file
@@ -0,0 +1,108 @@
|
||||
'use client'
|
||||
|
||||
/**
|
||||
* Top navigation bar for the Korrektur-Workspace.
|
||||
* Shows back link, student navigation, workflow status, and grade.
|
||||
*/
|
||||
|
||||
import Link from 'next/link'
|
||||
import type { ExaminerWorkflow } from './workspace-types'
|
||||
import { WORKFLOW_STATUS_LABELS, ROLE_LABELS, GRADE_LABELS } from './workspace-types'
|
||||
|
||||
interface WorkspaceTopBarProps {
|
||||
klausurId: string
|
||||
backPath: string
|
||||
currentIndex: number
|
||||
studentCount: number
|
||||
workflow: ExaminerWorkflow | null
|
||||
saving: boolean
|
||||
totals: { gradePoints: number; weighted: number }
|
||||
onGoToStudent: (direction: 'prev' | 'next') => void
|
||||
}
|
||||
|
||||
export default function WorkspaceTopBar({
|
||||
klausurId, backPath, currentIndex, studentCount,
|
||||
workflow, saving, totals, onGoToStudent,
|
||||
}: WorkspaceTopBarProps) {
|
||||
return (
|
||||
<div className="bg-white border-b border-slate-200 -mx-6 -mt-6 px-6 py-3 mb-4 flex items-center justify-between sticky top-0 z-10">
|
||||
{/* Back link */}
|
||||
<Link
|
||||
href={backPath}
|
||||
className="text-primary-600 hover:text-primary-800 flex items-center gap-1 text-sm"
|
||||
>
|
||||
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 19l-7-7 7-7" />
|
||||
</svg>
|
||||
Zurueck
|
||||
</Link>
|
||||
|
||||
{/* Student navigation */}
|
||||
<div className="flex items-center gap-4">
|
||||
<button
|
||||
onClick={() => onGoToStudent('prev')}
|
||||
disabled={currentIndex <= 0}
|
||||
className="p-2 rounded-lg hover:bg-slate-100 disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
>
|
||||
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 19l-7-7 7-7" />
|
||||
</svg>
|
||||
</button>
|
||||
<span className="text-sm font-medium">
|
||||
{currentIndex + 1} / {studentCount}
|
||||
</span>
|
||||
<button
|
||||
onClick={() => onGoToStudent('next')}
|
||||
disabled={currentIndex >= studentCount - 1}
|
||||
className="p-2 rounded-lg hover:bg-slate-100 disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
>
|
||||
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 5l7 7-7 7" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Workflow status and role */}
|
||||
<div className="flex items-center gap-3">
|
||||
{workflow && (
|
||||
<div className="flex items-center gap-2">
|
||||
<span
|
||||
className={`px-2 py-1 text-xs font-medium rounded-full text-white ${
|
||||
ROLE_LABELS[workflow.user_role]?.color || 'bg-slate-500'
|
||||
}`}
|
||||
>
|
||||
{ROLE_LABELS[workflow.user_role]?.label || workflow.user_role}
|
||||
</span>
|
||||
<span
|
||||
className={`px-2 py-1 text-xs font-medium rounded-full ${
|
||||
WORKFLOW_STATUS_LABELS[workflow.workflow_status]?.color || 'bg-slate-100'
|
||||
}`}
|
||||
>
|
||||
{WORKFLOW_STATUS_LABELS[workflow.workflow_status]?.label || workflow.workflow_status}
|
||||
</span>
|
||||
{workflow.user_role === 'zk' && workflow.visibility_mode !== 'full' && (
|
||||
<span className="px-2 py-1 text-xs bg-purple-100 text-purple-700 rounded-full">
|
||||
{workflow.visibility_mode === 'blind' ? 'Blind-Modus' : 'Semi-Blind'}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{saving && (
|
||||
<span className="text-sm text-slate-500 flex items-center gap-1">
|
||||
<div className="animate-spin rounded-full h-3 w-3 border-b-2 border-primary-600"></div>
|
||||
Speichern...
|
||||
</span>
|
||||
)}
|
||||
<div className="text-right">
|
||||
<div className="text-lg font-bold text-slate-800">
|
||||
{totals.gradePoints} Punkte
|
||||
</div>
|
||||
<div className="text-sm text-slate-500">
|
||||
Note: {GRADE_LABELS[totals.gradePoints] || '-'}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user