Files
breakpilot-compliance/admin-compliance/app/sdk/training/_components/AssignmentDetailDrawer.tsx
Sharang Parnerkar b5d20a4c1d
Some checks failed
Build + Deploy / build-admin-compliance (push) Failing after 34s
Build + Deploy / build-developer-portal (push) Successful in 56s
Build + Deploy / build-tts (push) Successful in 1m8s
CI/CD / go-lint (push) Has been skipped
Build + Deploy / trigger-orca (push) Has been skipped
CI/CD / python-lint (push) Has been skipped
CI/CD / nodejs-lint (push) Has been skipped
CI/CD / test-go-ai-compliance (push) Successful in 38s
CI/CD / test-python-backend-compliance (push) Successful in 32s
Build + Deploy / build-backend-compliance (push) Successful in 7s
Build + Deploy / build-ai-sdk (push) Successful in 7s
Build + Deploy / build-document-crawler (push) Successful in 33s
Build + Deploy / build-dsms-gateway (push) Successful in 20s
CI/CD / test-python-dsms-gateway (push) Has been cancelled
CI/CD / validate-canonical-controls (push) Has been cancelled
CI/CD / test-python-document-crawler (push) Has been cancelled
fix: add missing training page components to fix admin-compliance Docker build
All 8 components imported by app/sdk/training/page.tsx were missing.
Docker build was failing with Module not found errors.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-17 10:32:35 +02:00

126 lines
4.9 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
'use client'
import { useState } from 'react'
import { updateAssignment, completeAssignment } from '@/lib/sdk/training/api'
import type { TrainingAssignment } from '@/lib/sdk/training/types'
import { STATUS_LABELS, STATUS_COLORS } from '@/lib/sdk/training/types'
export default function AssignmentDetailDrawer({
assignment,
onClose,
onSaved,
}: {
assignment: TrainingAssignment
onClose: () => void
onSaved: () => void
}) {
const [saving, setSaving] = useState(false)
const [error, setError] = useState<string | null>(null)
const colors = STATUS_COLORS[assignment.status]
async function handleComplete() {
if (!window.confirm('Zuweisung als abgeschlossen markieren?')) return
setSaving(true)
try {
await completeAssignment(assignment.id)
onSaved()
} catch (err) {
setError(err instanceof Error ? err.message : 'Fehler')
} finally {
setSaving(false)
}
}
async function handleExtend(e: React.FormEvent<HTMLFormElement>) {
e.preventDefault()
setSaving(true)
setError(null)
const fd = new FormData(e.currentTarget)
try {
await updateAssignment(assignment.id, { deadline: fd.get('deadline') as string })
onSaved()
} catch (err) {
setError(err instanceof Error ? err.message : 'Fehler beim Aktualisieren')
} finally {
setSaving(false)
}
}
return (
<div className="fixed inset-0 z-50 flex justify-end">
<div className="absolute inset-0 bg-black/30" onClick={onClose} />
<div className="relative bg-white w-full max-w-md shadow-xl flex flex-col overflow-y-auto">
<div className="flex items-center justify-between px-6 py-4 border-b">
<h3 className="text-base font-semibold">Zuweisung</h3>
<button onClick={onClose} className="text-gray-400 hover:text-gray-600 text-xl">×</button>
</div>
<div className="px-6 py-4 space-y-4 flex-1">
{error && (
<div className="text-sm text-red-600 bg-red-50 border border-red-200 rounded p-3">{error}</div>
)}
<div className="space-y-2">
<Row label="Nutzer" value={`${assignment.user_name} (${assignment.user_email})`} />
<Row label="Modul" value={`${assignment.module_code ?? ''} ${assignment.module_title ?? assignment.module_id.slice(0, 8)}`} />
<Row label="Status">
<span className={`text-xs px-2 py-0.5 rounded-full ${colors.bg} ${colors.text}`}>
{STATUS_LABELS[assignment.status]}
</span>
</Row>
<Row label="Fortschritt" value={`${assignment.progress_percent}%`} />
<Row label="Frist" value={new Date(assignment.deadline).toLocaleDateString('de-DE')} />
{assignment.started_at && <Row label="Gestartet" value={new Date(assignment.started_at).toLocaleString('de-DE')} />}
{assignment.completed_at && <Row label="Abgeschlossen" value={new Date(assignment.completed_at).toLocaleString('de-DE')} />}
{assignment.quiz_score != null && (
<Row label="Quiz-Score" value={`${Math.round(assignment.quiz_score)}% (${assignment.quiz_passed ? 'Bestanden' : 'Nicht bestanden'})`} />
)}
<Row label="Quiz-Versuche" value={String(assignment.quiz_attempts)} />
{assignment.escalation_level > 0 && (
<Row label="Eskalationsstufe" value={String(assignment.escalation_level)} />
)}
</div>
{assignment.status !== 'completed' && (
<div className="border rounded-lg p-4 space-y-3">
<h4 className="text-sm font-medium text-gray-700">Frist verlaengern</h4>
<form onSubmit={handleExtend} className="flex gap-2">
<input
name="deadline"
type="date"
defaultValue={assignment.deadline.slice(0, 10)}
className="flex-1 px-3 py-2 text-sm border rounded-lg"
/>
<button type="submit" disabled={saving} className="px-3 py-2 text-sm bg-blue-600 text-white rounded-lg hover:bg-blue-700 disabled:opacity-50">
Speichern
</button>
</form>
</div>
)}
</div>
{assignment.status !== 'completed' && (
<div className="px-6 py-4 border-t">
<button
onClick={handleComplete}
disabled={saving}
className="w-full px-4 py-2 text-sm bg-green-600 text-white rounded-lg hover:bg-green-700 disabled:opacity-50"
>
Als abgeschlossen markieren
</button>
</div>
)}
</div>
</div>
)
}
function Row({ label, value, children }: { label: string; value?: string; children?: React.ReactNode }) {
return (
<div className="flex gap-2 text-sm">
<span className="text-gray-500 w-36 shrink-0">{label}:</span>
{children ?? <span className="text-gray-900">{value}</span>}
</div>
)
}