Standard: 1. Okt. Folgejahr (merkt sich die letzte Wahl).
-
';
return s;
}
@@ -293,7 +296,7 @@ async function renderModules() {
s += '
'+(m.icon||'📚')+' '+m.name+'
';
s += '
'+(m.desc||'')+'
';
s += '
';
- if (isSpielbar) s += '▶ Starten';
+ if (isSpielbar) s += licensed ? '▶ Starten' : '🔑 Lizenz nötig';
s += '📖 Infos';
if (!isComing) s += '📚 Glossar';
if (buchHref) s += '📘 Schulbuch';
@@ -323,6 +326,13 @@ async function renderModules() {
html += '
';
}
+ if (!licensed) {
+ html = '
'
+ + '
🔑
'
+ + '
Noch keine Lizenz
'
+ + '
Deine Lehrperson muss dir noch eine gültige Lizenz zuweisen. Sobald das erledigt ist, kannst du die Simulationen starten.
@@ -2801,6 +2804,7 @@ async function loadClasses() {
if (validTabs[initialTab]) currentTab = initialTab;
loadTab(currentTab);
if (validTabs[initialTab]) switchTab(initialTab);
+ checkLicenseWarning();
window.addEventListener('hashchange', function() {
var t = (location.hash || '').replace('#','');
if (validTabs[t]) switchTab(t);
@@ -2815,6 +2819,26 @@ function onClassChange() {
document.getElementById('class-code').textContent = currentClass?.join_code || '—';
loadTab(currentTab);
startLiveStatusPoll();
+ checkLicenseWarning();
+}
+
+// Rote Cockpit-Warnung: Schüler:innen der Klasse ohne gültige Lizenz.
+async function checkLicenseWarning() {
+ var el = document.getElementById('license-warning');
+ if (!el) return;
+ if (!currentClassId) { el.style.display='none'; return; }
+ try {
+ var r = await api('licenses?class_id=' + currentClassId);
+ var n = (r && r.unlicensed) ? r.unlicensed.length : 0;
+ if (n > 0) {
+ el.innerHTML = '
'
+ + '🔑'
+ + ''+n+' '+(n===1?'Schüler:in hat':'Schüler:innen haben')+' noch keine gültige Lizenz — ohne Lizenz können sie keine Simulationen nutzen.'
+ + ''
+ + '
';
+ el.style.display = 'block';
+ } else { el.style.display='none'; el.innerHTML=''; }
+ } catch(e) { el.style.display='none'; }
}
async function saveClass() {
@@ -5428,6 +5452,25 @@ async function loadLicenses() {
html += '';
html += '
';
+ // Ohne gültige Lizenz — direkt zuweisbar
+ var unlic = r.unlicensed || [];
+ html += '
Ohne gültige Lizenz ('+unlic.length+')
';
+ if (unlic.length > 0) {
+ var freeN = r.free ? r.free.length : 0;
+ html += '
Diese Schüler:innen können noch keine Simulationen nutzen.'+(freeN < unlic.length ? ' Nur '+freeN+' freie Lizenz(en) verfügbar.' : '')+'
';
+ if (freeN > 0) html += '';
+ html += '
Schüler*in
';
+ unlic.forEach(function(s) {
+ html += '
'+esc(s.display_name||s.username)+'
'
+ + (freeN>0 ? '' : 'keine freie Lizenz')
+ + '
';
+ });
+ html += '
';
+ } else {
+ html += '
Alle Schüler:innen haben eine gültige Lizenz. ✓
';
+ }
+ html += '
';
+
// Zugewiesene Lizenzen
html += '
Zugewiesene Lizenzen
';
if (r.assigned && r.assigned.length > 0) {
@@ -5458,6 +5501,24 @@ async function loadLicenses() {
html += '
';
document.getElementById('tab-licenses').innerHTML = html;
+ checkLicenseWarning();
+}
+
+async function assignLicenseToStudent(studentId) {
+ var r = await api('licenses', {action:'auto_assign', studentId:studentId});
+ if (r.error) { alert(r.error); return; }
+ loadLicenses();
+}
+async function assignAllUnlicensed(ids) {
+ if (!ids || !ids.length) return;
+ if (!confirm(ids.length + ' Schüler:innen je eine freie Lizenz zuweisen?')) return;
+ var failed = null;
+ for (var i = 0; i < ids.length; i++) {
+ var r = await api('licenses', {action:'auto_assign', studentId:ids[i]});
+ if (r.error) { failed = r.error; break; }
+ }
+ if (failed) alert('Nicht alle konnten zugewiesen werden: ' + failed);
+ loadLicenses();
}
// === BULK SELECTION ===