Files
breakpilot-lehrer/website/app/admin/unity-bridge/_components/UnitsTab.tsx
Benjamin Admin 0b37c5e692 [split-required] Split website + studio-v2 monoliths (Phase 3 continued)
Website (14 monoliths split):
- compliance/page.tsx (1,519 → 9), docs/audit (1,262 → 20)
- quality (1,231 → 16), alerts (1,203 → 10), docs (1,202 → 11)
- i18n.ts (1,173 → 8 language files)
- unity-bridge (1,094 → 12), backlog (1,087 → 6)
- training (1,066 → 8), rag (1,063 → 8)
- Deleted index_original.ts (4,899 LOC dead backup)

Studio-v2 (5 monoliths split):
- meet/page.tsx (1,481 → 9), messages (1,166 → 9)
- AlertsB2BContext.tsx (1,165 → 5 modules)
- alerts-b2b/page.tsx (1,019 → 6), korrektur/archiv (1,001 → 6)

All existing imports preserved. Zero new TypeScript errors.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-24 17:52:36 +02:00

146 lines
5.6 KiB
TypeScript

'use client'
import type { UnitDefinition } from './types'
export function UnitsTab({
units,
selectedUnit,
isLoadingUnits,
unitsError,
onFetchUnits,
onFetchUnitDetails,
onClearSelection,
}: {
units: UnitDefinition[]
selectedUnit: UnitDefinition | null
isLoadingUnits: boolean
unitsError: string | null
onFetchUnits: () => void
onFetchUnitDetails: (unitId: string) => void
onClearSelection: () => void
}) {
return (
<div className="space-y-6">
{/* Units Header */}
<div className="flex items-center justify-between">
<h2 className="text-lg font-semibold text-gray-900">Unit-Definitionen</h2>
<button
onClick={onFetchUnits}
disabled={isLoadingUnits}
className="px-4 py-2 bg-primary-600 text-white rounded-lg hover:bg-primary-700 disabled:opacity-50 transition-colors"
>
{isLoadingUnits ? 'Laden...' : 'Aktualisieren'}
</button>
</div>
{/* Units Error */}
{unitsError && (
<div className="p-4 bg-red-50 border border-red-200 rounded-lg">
<p className="text-red-800">{unitsError}</p>
<p className="text-sm text-red-600 mt-1">
Backend starten: <code className="bg-red-100 px-1 rounded">cd backend && python main.py</code>
</p>
</div>
)}
{/* Units Grid */}
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
{units.map((unit) => (
<div
key={unit.unit_id}
className={`
p-4 bg-white rounded-lg border-2 cursor-pointer transition-all
${selectedUnit?.unit_id === unit.unit_id
? 'border-primary-500 shadow-md'
: 'border-gray-200 hover:border-gray-300'
}
`}
onClick={() => onFetchUnitDetails(unit.unit_id)}
>
<div className="flex items-start justify-between mb-2">
<h3 className="font-semibold text-gray-900">{unit.unit_id}</h3>
<span className={`
px-2 py-0.5 text-xs rounded-full
${unit.template === 'flight_path' ? 'bg-blue-100 text-blue-700' : 'bg-purple-100 text-purple-700'}
`}>
{unit.template}
</span>
</div>
<p className="text-sm text-gray-600 mb-2">{unit.topic || unit.subject || 'Keine Beschreibung'}</p>
<div className="flex items-center gap-4 text-xs text-gray-500">
<span>{unit.duration_minutes} min</span>
<span>{unit.difficulty}</span>
<span>{unit.grade_band?.join(', ') || '-'}</span>
</div>
</div>
))}
</div>
{/* Empty State */}
{!isLoadingUnits && units.length === 0 && !unitsError && (
<div className="text-center py-12 text-gray-500">
<p>Keine Units gefunden</p>
<p className="text-sm mt-1">Units werden unter <code className="bg-gray-100 px-1 rounded">backend/data/units/</code> gespeichert</p>
</div>
)}
{/* Selected Unit Details */}
{selectedUnit && (
<div className="bg-white rounded-lg border border-gray-200 shadow-sm p-6">
<div className="flex items-center justify-between mb-4">
<h3 className="text-lg font-semibold text-gray-900">{selectedUnit.unit_id}</h3>
<button
onClick={onClearSelection}
className="text-gray-400 hover:text-gray-600"
>
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
</div>
{/* Learning Objectives */}
{selectedUnit.learning_objectives && selectedUnit.learning_objectives.length > 0 && (
<div className="mb-4">
<h4 className="text-sm font-medium text-gray-700 mb-2">Lernziele</h4>
<ul className="list-disc list-inside text-sm text-gray-600 space-y-1">
{selectedUnit.learning_objectives.map((obj, i) => (
<li key={i}>{obj}</li>
))}
</ul>
</div>
)}
{/* Stops */}
{selectedUnit.stops && selectedUnit.stops.length > 0 && (
<div>
<h4 className="text-sm font-medium text-gray-700 mb-2">Stops ({selectedUnit.stops.length})</h4>
<div className="grid grid-cols-1 md:grid-cols-2 gap-2">
{selectedUnit.stops.map((stop) => (
<div key={stop.stop_id} className="flex items-center gap-2 p-2 bg-gray-50 rounded text-sm">
<span className="w-6 h-6 flex items-center justify-center bg-primary-100 text-primary-700 rounded-full text-xs font-medium">
{stop.order + 1}
</span>
<span className="text-gray-900">{stop.label?.['de-DE'] || stop.stop_id}</span>
{stop.interaction && (
<span className="text-xs text-gray-500">({stop.interaction.type})</span>
)}
</div>
))}
</div>
</div>
)}
{/* JSON Preview */}
<details className="mt-4">
<summary className="text-sm font-medium text-gray-700 cursor-pointer">JSON anzeigen</summary>
<pre className="mt-2 p-4 bg-gray-900 text-gray-100 rounded-lg text-xs overflow-x-auto max-h-96">
{JSON.stringify(selectedUnit, null, 2)}
</pre>
</details>
</div>
)}
</div>
)
}