// ----------------------------- // Projektübersicht — Sitzungs-/Wochen-Verwaltung // ----------------------------- // Diese Datei verwaltet die Sitzungen (Wochen): Auswahl, Anzeige des Datums, // Sperren (Auto-Lock) und Löschen. Sie wird von `Test.html` nach `js/store.js` // geladen und stellt globale Funktionen wie `currentWeek()`, `switchWeek()`, // `applyAutoLock()`, `guardWeekLocked()`, `unlockWeek()` und `deleteWeekById()` // bereit. Genutzt wird // sie u.a. von `js/board/board.js` (`renderBoard`, `isWeekLocked`), `js/store.js` // (`load`) und `js/tabs-auth.js` (Passwort-Aktionen für Entsperren/Löschen). // // Neue Sitzungen entstehen seit dem automatischen Sitzungswechsel NICHT MEHR // hier — `ensureCurrentWeekRollover()` (server.js) legt sie serverseitig an, // sobald der Kalender in eine neue ISO-Woche wechselt, unabhängig davon, ob // irgendjemand die Anwendung gerade geöffnet hat (siehe CLAUDE.md). Die // früheren Funktionen `newWeek()`/`cloneWeek()`/`validateWeekLabel()` sind // deshalb entfallen. // currentWeek: liefert das Woche-Objekt zur aktuellen Auswahl aus `db.weeks`. // Kein Parameter; Rückgabe: das gefundene Woche-Objekt oder undefined. function currentWeek(){ return db.weeks.find(w=>w.id===db.currentWeek); } // switchWeek: setzt die aktuell gewählte Wochen-ID (`id`) und rendert die // Ansicht neu. Es werden keine Daten geändert, daher wird nicht gespeichert // (eine save() würde die Woche nur als dirty markieren und unnötig senden). // Keine Rückgabe. function switchWeek(id){ db.currentWeek = id; renderAll(); } // -------- Sperren (Auto-Lock) und Entsperren -------- // applyAutoLock: sperrt alle Sitzungen bis auf die chronologisch // letzte (aktuellste). Wird beim Laden, Erstellen und Duplizieren verwendet, // damit historische Sitzungen nicht mehr unbeabsichtigt bearbeitet werden. // // Firmenweit abschaltbar (Einstellung 'autoLockAktiv'): In manchen Büros wird // an mehreren Sitzungen parallel gearbeitet, dort steht die automatische // Sperre im Weg. Ist sie aus, wird NICHT nachträglich entsperrt — bereits // gesperrte Sitzungen bleiben es, das Entsperren bleibt eine bewusste // Admin-Handlung (POST /unlock-week). function applyAutoLock(){ if(db.weeks.length === 0) return; if(!Number(APP_SETTINGS.autoLockAktiv)) return; // Die Planung-Sandbox (SANDBOX_WEEK_LABEL) landet nie in db.weeks (siehe // load(), js/store.js) und ist von dieser Schleife also strukturell schon // ausgenommen — dieser Filter ist ein reines Sicherheitsnetz, falls das // je nicht mehr zuträfe: sie darf nie als "späteste Woche" zählen oder // gesperrt werden, sie ist keine echte Sitzung. const echteWochen = db.weeks.filter(w => w.label !== SANDBOX_WEEK_LABEL); if(echteWochen.length === 0) return; const sorted = [...echteWochen].sort((a,b) => weekSortKey(a.label).localeCompare(weekSortKey(b.label))); const latestId = sorted[sorted.length - 1].id; echteWochen.forEach(w => { const wasLocked = !!w.locked; w.locked = (w.id !== latestId); // Nur tatsächlich geänderte Lock-Zustände übertragen (beim bloßen Laden // sind die Werte identisch und es wird nichts gesendet). if(wasLocked !== w.locked) markWeekDirty(w.label); }); } // isWeekLocked: prüft, ob eine Sitzung gesperrt ist. Parameter `w`: Woche-Objekt. // Rückgabe: `true` bei gesperrter bzw. fehlender Woche, sonst `false`. function isWeekLocked(w){ return !!w && !!w.locked; } // guardWeekLocked: zeigt eine Warnung, wenn die aktuelle Sitzung gesperrt ist. // Wird von Bearbeitungsfunktionen verwendet, um versehentliche Änderungen an // historischen Sitzungen zu verhindern. Rückgabe: `true` bei Sperre (Abbruch), // sonst `false`. function guardWeekLocked(){ const w = currentWeek(); if(isWeekLocked(w)){ alert('Diese Sitzung ist gesperrt. Bitte entsperren Sie sie zuerst.'); return true; } return false; } // unlockWeek: entsperrt EINE Sitzung serverseitig (POST /unlock-week, // admin-only) und übernimmt bei Erfolg den Sperr-Zustand sowie die neue // Revision (`updatedAt`) lokal. // // Verallgemeinert gegenüber der früheren Fassung, die nur `currentWeek()` // kannte: Seit die Sitzungsauswahl aus dem Menüband entfernt wurde // (Sitzungen dienen nur noch der Speicherung und dem Verlauf), muss sich // auch eine ANDERE als die gerade offene Sitzung entsperren lassen — die // Sitzungsliste im Admin-Bereich (renderAdminSitzungen(), js/admin/admin.js) // braucht genau das. // Parameter: w (Woche-Objekt aus db.weeks), nachRender (optionale Funktion // statt renderAll() — die Admin-Liste soll nur sich selbst neu zeichnen, // nicht die ganze Seite, die ohnehin die entsperrte Sitzung nicht zeigt). // Keine Rückgabe. function unlockWeek(w, nachRender){ if(!w || !w.locked) return; fetch(baseUrl() + '/unlock-week', { method: 'POST', headers: {'Content-Type':'application/json'}, body: JSON.stringify({ label: w.label }) }).then(r => { if(r.status === 403){ alert('Nur Administratoren dürfen Sitzungen entsperren.'); return null; } return r.json().then(json => ({ status: r.status, json })); }).then(result => { if(!result) return; const { status, json } = result; if(status === 200 && json && json.ok){ w.locked = false; if(json.updatedAt) w.updatedAt = json.updatedAt; (nachRender || renderAll)(); } else { alert('Entsperren fehlgeschlagen: ' + (json && json.error ? json.error : 'unbekannter Fehler')); } }).catch(err => { alert('Entsperren fehlgeschlagen: ' + (err.message || err)); }); } // unlockCurrentWeek: entsperrt die gerade offene Sitzung. Aufrufer ist // ausschließlich der Sperr-Hinweis auf dem Board/Wochenbericht // (renderBoard()/renderWochenbericht()), der nur erscheint, wenn // `currentWeek()` selbst gesperrt ist — im Normalbetrieb mit aktiver // Auto-Sperre kommt das praktisch nicht vor, da immer nur die jüngste // Sitzung offen bleibt. Dünner Wrapper um `unlockWeek()`. function unlockCurrentWeek(){ unlockWeek(currentWeek()); } // deleteWeekById: löscht EINE Sitzung (nicht zwingend die aktuell offene) // mitsamt allen Projekten, Zuordnungen und Plänen dieser Sitzung auf dem // Server (admin-only, POST /delete-week). Mindestens eine Sitzung muss // bestehen bleiben. Die lokale Woche wird erst nach erfolgreicher // Server-Antwort entfernt (sonst würde sie bei fehlender Berechtigung // lokal verschwinden, obwohl sie auf dem Server weiterhin existiert). // // Ersetzt die frühere `deleteWeek()`, die stillschweigend "die im Menüband // gewählte Sitzung" meinte — ohne diese Auswahl im Menüband ist eine // explizite Ziel-Sitzung nötig; Aufrufer ist jetzt ausschließlich die // Sitzungsliste im Admin-Bereich. // Parameter: weekId, nachDelete (optionale Zusatzfunktion, die NACH dem // üblichen renderAll() zusätzlich läuft — die Admin-Liste zeichnet sich // darüber selbst neu, weil renderAll() sie nicht kennt). Keine Rückgabe. function deleteWeekById(weekId, nachDelete){ if(db.weeks.length<=1){ alert("Mindestens eine Sitzung muss bestehen bleiben."); return; } const w = db.weeks.find(x => x.id === weekId); if(!w) return; if(!confirm('Sitzung "' + w.label + '" wirklich löschen?')) return; console.log('Lösche Woche auf Server:', w.label); deleteWeekFromServer(w.label).then(res=>{ if(!(res && res.ok)){ alert('Wochen-Löschung fehlgeschlagen: ' + (res && res.error ? res.error : 'unbekannter Fehler')); return; } console.log('Woche gelöscht:', w.label); const warAktuell = (weekId === db.currentWeek); db.weeks = db.weeks.filter(x=>x.id!==weekId); db.weeks.sort((a,b) => weekSortKey(a.label).localeCompare(weekSortKey(b.label))); // Zeigte die Oberfläche gerade die gelöschte Sitzung (oder zeigt sie aus // irgendeinem Grund gar keine mehr existierende), auf die jüngste // verbleibende wechseln — sonst verwiese db.currentWeek ins Leere. if(warAktuell || !db.weeks.some(x => x.id === db.currentWeek)){ db.currentWeek = db.weeks[db.weeks.length - 1].id; } applyAutoLock(); save(); renderAll(); if(typeof nachDelete === 'function') nachDelete(); }).catch(err=>{ if(err && err.status === 403){ alert('Nur Administratoren dürfen Sitzungen löschen.'); return; } alert('Wochen-Löschung fehlgeschlagen: ' + (err.message || err)); }); }