Files
breakpilot-lehrer/website/components/klausur-korrektur/WorkflowActions.tsx
Benjamin Admin 6811264756 [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>
2026-04-24 23:17:30 +02:00

166 lines
6.8 KiB
TypeScript

'use client'
/**
* Workflow-aware action buttons for the criteria panel.
* Handles Erstkorrektur, Zweitkorrektur, Einigung, and completed states.
*/
import type { ExaminerWorkflow } from './workspace-types'
import { GRADE_LABELS } from './workspace-types'
interface WorkflowActionsProps {
workflow: ExaminerWorkflow | null
gutachten: string
generatingGutachten: boolean
submittingWorkflow: boolean
totals: { gradePoints: number }
onGenerateGutachten: () => void
onSubmitErstkorrektur: () => void
onStartZweitkorrektur: (id: string) => void
onSubmitZweitkorrektur: () => void
onShowEinigungModal: () => void
}
export default function WorkflowActions({
workflow, gutachten, generatingGutachten, submittingWorkflow, totals,
onGenerateGutachten, onSubmitErstkorrektur, onStartZweitkorrektur,
onSubmitZweitkorrektur, onShowEinigungModal,
}: WorkflowActionsProps) {
return (
<div className="space-y-2">
{/* Generate Gutachten button */}
<button
onClick={onGenerateGutachten}
disabled={generatingGutachten}
className="w-full py-2 bg-slate-100 text-slate-700 rounded-lg hover:bg-slate-200 disabled:opacity-50 flex items-center justify-center gap-2 text-sm"
>
{generatingGutachten ? (
<>
<div className="animate-spin rounded-full h-4 w-4 border-b-2 border-slate-700"></div>
Generiere Gutachten...
</>
) : (
<>
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" />
</svg>
Gutachten generieren
</>
)}
</button>
{/* Erstkorrektur */}
{(!workflow || workflow.workflow_status === 'not_started' || workflow.workflow_status === 'ek_in_progress') && (
<button
onClick={onSubmitErstkorrektur}
disabled={submittingWorkflow || !gutachten}
className="w-full py-3 bg-blue-600 text-white rounded-lg hover:bg-blue-700 disabled:opacity-50 flex items-center justify-center gap-2"
>
{submittingWorkflow ? (
<>
<div className="animate-spin rounded-full h-4 w-4 border-b-2 border-white"></div>
Wird abgeschlossen...
</>
) : (
<>
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M5 13l4 4L19 7" />
</svg>
Erstkorrektur abschliessen
</>
)}
</button>
)}
{/* Start Zweitkorrektur */}
{workflow?.workflow_status === 'ek_completed' && workflow.user_role === 'ek' && (
<button
onClick={() => {
const zkId = prompt('Zweitkorrektor-ID eingeben:')
if (zkId) onStartZweitkorrektur(zkId)
}}
disabled={submittingWorkflow}
className="w-full py-3 bg-amber-600 text-white rounded-lg hover:bg-amber-700 disabled:opacity-50 flex items-center justify-center gap-2"
>
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M17 8l4 4m0 0l-4 4m4-4H3" />
</svg>
Zur Zweitkorrektur weiterleiten
</button>
)}
{/* Submit Zweitkorrektur */}
{(workflow?.workflow_status === 'zk_assigned' || workflow?.workflow_status === 'zk_in_progress') &&
workflow?.user_role === 'zk' && (
<button
onClick={onSubmitZweitkorrektur}
disabled={submittingWorkflow || !gutachten}
className="w-full py-3 bg-amber-600 text-white rounded-lg hover:bg-amber-700 disabled:opacity-50 flex items-center justify-center gap-2"
>
{submittingWorkflow ? (
<>
<div className="animate-spin rounded-full h-4 w-4 border-b-2 border-white"></div>
Wird abgeschlossen...
</>
) : (
<>
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M5 13l4 4L19 7" />
</svg>
Zweitkorrektur abschliessen
</>
)}
</button>
)}
{/* Einigung */}
{workflow?.workflow_status === 'einigung_required' && (
<button
onClick={onShowEinigungModal}
className="w-full py-3 bg-orange-600 text-white rounded-lg hover:bg-orange-700 flex items-center justify-center gap-2"
>
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z" />
</svg>
Einigung starten
</button>
)}
{/* Completed */}
{workflow?.workflow_status === 'completed' && (
<div className="bg-green-100 text-green-800 p-4 rounded-lg text-center">
<div className="text-2xl font-bold">
Endnote: {workflow.final_grade} Punkte
</div>
<div className="text-sm mt-1">
({GRADE_LABELS[workflow.final_grade || 0]}) - {workflow.consensus_type === 'auto' ? 'Auto-Konsens' : workflow.consensus_type === 'drittkorrektur' ? 'Drittkorrektur' : 'Einigung'}
</div>
</div>
)}
{/* EK/ZK comparison */}
{workflow?.first_result && workflow?.second_result && workflow?.workflow_status !== 'completed' && (
<div className="bg-slate-50 rounded-lg p-3 mt-2">
<div className="text-xs text-slate-500 mb-2">Notenvergleich</div>
<div className="flex justify-between">
<div className="text-center">
<div className="text-sm text-slate-500">EK</div>
<div className="font-bold text-blue-600">{workflow.first_result.grade_points}P</div>
</div>
<div className="text-center">
<div className="text-sm text-slate-500">ZK</div>
<div className="font-bold text-amber-600">{workflow.second_result.grade_points}P</div>
</div>
<div className="text-center">
<div className="text-sm text-slate-500">Diff</div>
<div className={`font-bold ${(workflow.grade_difference || 0) >= 4 ? 'text-red-600' : 'text-slate-700'}`}>
{workflow.grade_difference}P
</div>
</div>
</div>
</div>
)}
</div>
)
}