Files
projektuebersicht/public/js/weeks.js
T

169 lines
8.2 KiB
JavaScript

// -----------------------------
// 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));
});
}