/* ===================================================================== DIE LAGE DES TEAMS -- eine Seite fuer die, die sie sehen duerfen. Wunsch Filipe (10.09.2026): eine Stelle, an der er und VanVan alles sehen und behandeln koennen. SIE ZAEHLT NUR, SIE BEWERTET NICHT. Bewertet wird dort, wo die Punkte stehen -- je Bereich fuehrt ein Verweis dorthin, mit der Person schon vorausgewaehlt. Eine zweite Stelle zum Bewerten waere eine zweite Stelle, an der es auseinanderlaeuft. KEINE NEUEN CSS-KLASSEN. Fuer genau diese Art Karte gibt es sie schon (`tperson`, `tz`, `schritt` -- benutzt von team.html). Elf neue haetten in mehreren Stilvorlagen gepflegt werden muessen, fuer ein Aussehen, das es bereits gibt. Zwei Bauarten fuer dieselbe Sache sind ausserdem zwei Dinge zum Lernen statt einem. IN DIESER DATEI STEHT KEIN ROLLENNAME. Sie wird wie jede Datei unter /workspace an JEDEN ausgeliefert, der die Seite oeffnet. Wer sie bekommt, entscheiden der Server (404 fuer alle anderen) und die Kachel, die ebenfalls vom Server kommt. ===================================================================== */ (() => { const $ = (id) => document.getElementById(id); const el = (tag, klasse, text) => { const k = document.createElement(tag); if (klasse) k.className = klasse; if (text !== undefined) k.textContent = text; return k; }; const melde = (t) => { const f = $('fehler'); if (f) f.textContent = t || ''; }; async function hole(pfad, optionen = {}) { const a = await fetch(pfad, { credentials: 'same-origin', ...optionen }); if (a.status === 401) { location.assign('/workspace/'); throw new Error('abgemeldet'); } if (a.status === 404) { location.assign('/workspace/start.html'); throw new Error('nicht erlaubt'); } return a; } const tageHer = (iso) => { if (!iso) return null; const d = new Date(iso); if (Number.isNaN(d.getTime())) return null; return Math.floor((Date.now() - d.getTime()) / 86400000); }; /* Die drei Bereiche in derselben Reihenfolge wie auf der Startseite. Die Namen stehen hier, weil die Seite sonst eine zweite Abfrage braeuchte, nur um drei Woerter zu holen. */ const BEREICHE = [ { schluessel: 'live', name: 'Live-Ablauf' }, { schluessel: 'community', name: 'Community' }, { schluessel: 'technik', name: 'Technik' }, ]; function zahl(wert, schild) { const k = el('div', 'tz'); k.append(el('strong', 'tz__wert', String(wert))); k.append(el('span', 'tz__schild', schild)); return k; } function karte(m) { const k = el('article', 'tperson'); const kopf = el('div', 'tperson__kopf'); const zeichen = el('span', 'tperson__zeichen'); if (m.bild) { const b = document.createElement('img'); b.src = m.bild; b.alt = ''; b.loading = 'lazy'; zeichen.append(b); } else { zeichen.textContent = (m.name || '?').trim().charAt(0).toUpperCase(); } kopf.append(zeichen); const text = el('div', 'tperson__text'); text.append(el('p', 'tperson__namen', m.name)); /* WANN ZULETZT DA -- als Tatsache, nicht als Vorwurf. Wer zwei Wochen nicht da war, hat vielleicht Urlaub; die Zahl sagt nur, dass man nachfragen koennte. */ const her = tageHer(m.letzter_login); text.append(el('span', 'tperson__zuletzt', her === null ? 'war noch nie angemeldet' : her === 0 ? 'heute da gewesen' : her === 1 ? 'gestern da gewesen' : `vor ${her} Tagen da gewesen`)); kopf.append(text); k.append(kopf); const zahlen = el('div', 'tperson__zahlen'); zahlen.append(zahl(m.aufgaben.offen, 'Aufgaben offen')); zahlen.append(zahl(m.aufgaben.ueberfaellig, 'überfällig')); zahlen.append(zahl(m.ideen, 'Ideen')); zahlen.append(zahl(m.nachrichten, 'Rückmeldungen')); for (const b of BEREICHE) { const z = m.bereiche[b.schluessel]; if (z) zahlen.append(zahl(z.offen, `${b.name}: offen`)); } k.append(zahlen); /* UND HIER WIRD BEHANDELT. Ein Verweis je Bereich, der die Person mitnimmt -- ohne sie muesste man dort noch einmal auswaehlen, und beim zweiten Mal weiss man nicht mehr, warum man hier war. */ const wege = el('div', 'tpipe__reihe'); for (const b of BEREICHE) { const z = m.bereiche[b.schluessel]; if (!z) continue; const a = el('a', 'schritt', `${b.name} ansehen (${z.gut} gut · ${z.verbessern} verbessern)`); a.href = `bereich.html?b=${b.schluessel}&creator_id=${m.id}`; wege.append(a); } k.append(wege); return k; } async function laden() { const ziel = $('lage'); try { const a = await hole('/workspace/api/teamlage'); if (!a.ok) { melde('Die Lage konnte nicht geladen werden.'); return; } const daten = await a.json(); ziel.textContent = ''; ziel.setAttribute('aria-busy', 'false'); const leute = daten.modis || []; const offenGesamt = leute.reduce((s, m) => s + Object.values(m.bereiche).reduce((x, b) => x + b.offen, 0), 0); /* Eine leere Seite ohne Erklaerung sieht aus wie ein Fehler -- deshalb steht hier auch, was zu tun waere. */ $('kopf-unter').textContent = leute.length ? `${leute.length} ${leute.length === 1 ? 'Person' : 'Personen'} · ` + `${offenGesamt} Punkte noch nicht besprochen` : 'Noch niemand im Team. Zugänge legst du unter „Personen & Zugänge“ an.'; for (const m of leute) ziel.append(karte(m)); } catch { /* umgeleitet */ } } (async () => { try { const a = await hole('/workspace/api/ich'); if (!a.ok) { location.assign('/workspace/'); return; } window.werZeigen?.(await a.json()); } catch { return; } $('abmelden')?.addEventListener('click', async () => { try { await fetch('/workspace/api/abmelden', { method: 'POST', credentials: 'same-origin' }); } catch { /* egal */ } location.assign('/workspace/'); }); await laden(); })(); })();