Aufgabe: Ab-wann + Bis-wann mit gutem Picker; neue Klasse nur Weltkueche frei

- Modal: "Ab wann" (Sofort/Zeitpunkt) + "Bis wann" (Presets + date/time statt
  datetime-local), Live-Zusammenfassung; zukuenftiger Start => vorbereitet
- assignments.php: startsAt-Param (Default NOW()), T->Space
- modules.php: neue Klasse ohne Eintrag -> nur Weltkueche frei (_defaultMode),
  Rest gesperrt; Freigabe-Matrix bleibt (getrennt von der Aufgabe)
- schueler.html: Hinweis "Deine Lehrperson kann weitere Simulationen freischalten"

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-22 17:39:28 +02:00
parent 7f774c7b2a
commit 405fcc2b69
4 changed files with 87 additions and 30 deletions
+14 -5
View File
@@ -50,7 +50,9 @@ if ($method === 'POST') {
$classId = (int)($body['classId'] ?? 0);
$moduleId = $body['moduleId'] ?? '';
$level = max(1, min(5, (int)($body['level'] ?? 1)));
$endsAt = !empty($body['endsAt']) ? $body['endsAt'] : null;
// datetime-local liefert 'YYYY-MM-DDTHH:MM' → 'T' für MySQL zu Leerzeichen.
$endsAt = !empty($body['endsAt']) ? str_replace('T', ' ', $body['endsAt']) : null;
$startsAt = !empty($body['startsAt']) ? str_replace('T', ' ', $body['startsAt']) : null;
if (!$classId || !$moduleId) Response::error('classId und moduleId erforderlich');
@@ -63,10 +65,17 @@ if ($method === 'POST') {
[$classId, $moduleId]
);
$db->execute(
'INSERT INTO class_assignments (class_id, teacher_id, module_id, level, starts_at, ends_at) VALUES (?, ?, ?, ?, NOW(), ?)',
[$classId, $teacherId, $moduleId, $level, $endsAt]
);
if ($startsAt) {
$db->execute(
'INSERT INTO class_assignments (class_id, teacher_id, module_id, level, starts_at, ends_at) VALUES (?, ?, ?, ?, ?, ?)',
[$classId, $teacherId, $moduleId, $level, $startsAt, $endsAt]
);
} else {
$db->execute(
'INSERT INTO class_assignments (class_id, teacher_id, module_id, level, starts_at, ends_at) VALUES (?, ?, ?, ?, NOW(), ?)',
[$classId, $teacherId, $moduleId, $level, $endsAt]
);
}
Response::ok(['id' => (int)$db->lastInsertId()]);
}
+9 -4
View File
@@ -16,6 +16,11 @@ require_once __DIR__ . '/../lib/Response.php';
$method = $_SERVER['REQUEST_METHOD'];
$db = Database::get();
// Default-Modus für eine Klasse OHNE expliziten Eintrag: eine neue Klasse startet
// mit NUR Weltküche frei (Einstiegs-Sim), alles andere gesperrt. Die Lehrperson
// gibt weitere Module über die Freigabe-Matrix frei.
function _defaultMode($moduleId) { return $moduleId === 'weltkueche' ? 'free' : 'locked'; }
// Modul-Katalog dynamisch aus module_info (Source of Truth)
// Nur aktive + beta + geplante Module anzeigen (keine archivierten)
$ALL_MODULES = $db->fetchAll(
@@ -85,7 +90,7 @@ if ($method === 'GET') {
foreach ($ALL_MODULES as $mod) {
if ($filterId && $mod['id'] !== $filterId) continue;
$cm = $classMap[$mod['id']] ?? null;
$mode = $overrides[$mod['id']] ?? ($cm['mode'] ?? 'locked');
$mode = $overrides[$mod['id']] ?? ($cm['mode'] ?? _defaultMode($mod['id']));
// 'geplant' überschreibt jeden mode-Eintrag — Modul ist nicht spielbar.
if ($mod['status'] === 'geplant') $mode = 'coming_soon';
@@ -172,7 +177,7 @@ if ($method === 'GET') {
'modules' => [],
];
foreach ($ALL_MODULES as $mod) {
$row['modules'][$mod['id']] = $overrides[$s['id']][$mod['id']] ?? $classMap[$mod['id']] ?? 'locked';
$row['modules'][$mod['id']] = $overrides[$s['id']][$mod['id']] ?? $classMap[$mod['id']] ?? _defaultMode($mod['id']);
}
$matrix[] = $row;
}
@@ -189,7 +194,7 @@ if ($method === 'GET') {
'card_image' => $mod['card_image'],
'status' => $mod['status'],
'available_from' => $mod['available_from'],
'classMode' => $classMap[$mod['id']] ?? 'locked',
'classMode' => $classMap[$mod['id']] ?? _defaultMode($mod['id']),
'currentLevel' => $meta ? (int)($meta['current_level'] ?? 1) : 1,
'paused' => $meta ? (bool)($meta['paused'] ?? 0) : false,
'audioInfo' => $meta ? (bool)($meta['audio_info'] ?? 1) : true,
@@ -210,7 +215,7 @@ if ($method === 'GET') {
'desc' => $mod['desc'],
'icon' => $mod['icon'],
'status' => $mod['status'],
'mode' => $classMap[$mod['id']] ?? 'locked',
'mode' => $classMap[$mod['id']] ?? _defaultMode($mod['id']),
];
}
Response::ok($result);