/* =================================================================== Startseite nach dem Anmelden. Die Seite ist bereits serverseitig geschützt (workspace.js). Dieses Skript holt nur noch, WER angemeldet ist, und regelt das Abmelden. =================================================================== */ (() => { 'use strict'; const ROLLENTEXT = { admin: 'DogFather · Gesamtübersicht und Freigaben', creator: 'Creator · dein eigener Bereich', scout: 'Scout · deine Pipeline und die Creator, die du betreust', }; /* Bereiche aus dem Konzept, mit der Phase aus dem Umsetzungsplan. `rollen` steuert, wem ein Bereich überhaupt angezeigt wird - schon jetzt, damit die Trennung von Anfang an sichtbar ist. */ const BEREICHE = [ { name: 'Dashboard', phase: 1, rollen: ['admin', 'creator', 'scout'] }, { name: 'Personen & Zugänge', phase: 1, rollen: ['admin'], ziel: 'personen.html' }, { name: 'Creator-Profile', phase: 1, rollen: ['admin', 'scout'], ziel: 'profil.html' }, { name: 'Mein Profil', phase: 1, rollen: ['creator'], ziel: 'profil.html' }, { name: 'Start-Check', phase: 1, rollen: ['admin', 'creator', 'scout'], ziel: 'startcheck.html' }, { name: 'Wissens-Bibliothek', phase: 1, rollen: ['admin', 'creator', 'scout'], ziel: 'wissen.html' }, { name: 'Aufgaben', phase: 1, rollen: ['admin', 'creator', 'scout'], ziel: 'aufgaben.html' }, { name: 'Kalender', phase: 1, rollen: ['admin', 'creator', 'scout'], ziel: 'kalender.html' }, { name: 'Dateien', phase: 1, rollen: ['admin', 'creator', 'scout'], ziel: 'dateien.html' }, { name: 'LIVE-Analyse', phase: 2, rollen: ['admin', 'creator', 'scout'], ziel: 'bereich.html?b=live' }, { name: 'Content-Planung', phase: 2, rollen: ['admin', 'creator', 'scout'], ziel: 'bereich.html?b=content' }, { name: 'Technik', phase: 2, rollen: ['admin', 'creator', 'scout'], ziel: 'bereich.html?b=technik' }, { name: 'Community', phase: 2, rollen: ['admin', 'creator', 'scout'], ziel: 'bereich.html?b=community' }, { name: 'Schutz & Regeln', phase: 2, rollen: ['admin', 'creator', 'scout'], ziel: 'bereich.html?b=schutz' }, { name: 'Reports & Review', phase: 2, rollen: ['admin', 'creator', 'scout'], ziel: 'report.html' }, { name: 'Calls & Protokolle', phase: 3, rollen: ['admin', 'creator', 'scout'], ziel: 'calls.html' }, { name: 'Scout-Pipeline', phase: 3, rollen: ['admin', 'scout'], ziel: 'scouting.html' }, { name: 'Automationen', phase: 4, rollen: ['admin'] }, ]; const $ = (id) => document.getElementById(id); async function laden() { let ich; try { const antwort = await fetch('/workspace/api/ich', { credentials: 'same-origin' }); if (!antwort.ok) { location.assign('/workspace/'); return; } ich = await antwort.json(); } catch { location.assign('/workspace/'); return; } $('wer').textContent = `${ich.name} · ${ich.rolle_name || ich.rolle}`; $('gruss').textContent = `Willkommen, ${ich.name}`; $('rollentext').textContent = ROLLENTEXT[ich.rolle] || ich.rolle; const liste = $('bereiche'); for (const b of BEREICHE.filter((b) => b.rollen.includes(ich.rolle))) { const li = document.createElement('li'); li.className = 'bereich'; li.dataset.phase = String(b.phase); if (b.ziel) li.dataset.fertig = 'ja'; const name = document.createElement('span'); name.className = 'bereich__name'; name.textContent = b.name; const stand = document.createElement('span'); stand.className = 'bereich__stand'; stand.textContent = b.ziel ? 'öffnen' : (b.phase === 1 ? 'als Nächstes' : `Phase ${b.phase}`); if (b.ziel) { /* Fertige Bereiche sind echte Verweise -- Tastatur und Rechtsklick funktionieren damit wie gewohnt. */ const a = document.createElement('a'); a.className = 'bereich__link'; a.href = b.ziel; a.append(name, stand); li.append(a); } else { li.append(name, stand); } liste.append(li); } await hinweiseLaden(); await zahlenLaden(); } /* Was ist dran? Erster Baustein der Automationen aus dem Konzept. Fuehrt bewusst keine eigenen Daten -- jeder Hinweis ist nur eine Sicht auf etwas, das schon da ist, und verschwindet von selbst, sobald die Sache erledigt ist. Nichts zu quittieren. */ const EINZAHL = { aufgaben_ueberfaellig: (n) => `${n} ${n === 1 ? 'Aufgabe ist' : 'Aufgaben sind'} überfällig`, aufgaben_heute: (n) => `${n} ${n === 1 ? 'Aufgabe ist' : 'Aufgaben sind'} heute fällig`, aufgaben_review: (n) => `${n} ${n === 1 ? 'Aufgabe wartet' : 'Aufgaben warten'} auf Freigabe`, termine_heute: (n) => `${n} ${n === 1 ? 'Termin steht' : 'Termine stehen'} heute an`, protokoll_fehlt: (n) => `${n} ${n === 1 ? 'Gespräch hat' : 'Gespräche haben'} noch kein Protokoll`, dateien_review: (n) => `${n} ${n === 1 ? 'Datei liegt' : 'Dateien liegen'} im Review`, bereiche_dringend: (n) => `${n} ${n === 1 ? 'dringender Punkt' : 'dringende Punkte'} in den Bereichen`, followup_faellig: (n) => `${n} Follow-up${n === 1 ? '' : 's'} ${n === 1 ? 'ist' : 'sind'} fällig`, uebergabe_offen: (n) => `${n} übergebene${n === 1 ? 'r Lead wartet' : ' Leads warten'} auf das Onboarding`, review_faellig: (n) => `${n} Review-Termin${n === 1 ? ' ist' : 'e sind'} überfällig`, review_bald: (n) => `${n} Review${n === 1 ? ' steht' : 's stehen'} in den nächsten 7 Tagen an`, ohne_betreuung: (n) => `${n} Creator ${n === 1 ? 'hat' : 'haben'} noch keine zuständige Person`, ohne_profil: (n) => `${n} Creator-Profil${n === 1 ? ' ist' : 'e sind'} noch leer`, ohne_startcheck: (n) => `${n} Creator ${n === 1 ? 'hat' : 'haben'} noch keinen Start-Check`, startcheck_handlung: (n) => `${n} ${n === 1 ? 'Punkt im Start-Check braucht' : 'Punkte im Start-Check brauchen'} Handlung`, }; async function hinweiseLaden() { let daten; try { const antwort = await fetch('/workspace/api/hinweise', { credentials: 'same-origin' }); if (!antwort.ok) return; daten = await antwort.json(); } catch { return; } const liste = $('dran'); liste.textContent = ''; if (!daten.hinweise.length) { $('dran-block').hidden = true; return; } for (const h of daten.hinweise) { const li = document.createElement('li'); li.className = 'dran__punkt'; li.dataset.stufe = h.stufe; /* Jeder Hinweis fuehrt irgendwohin -- ein Hinweis ohne Ziel ist nur ein schlechtes Gewissen. */ const a = document.createElement('a'); a.className = 'dran__link'; a.href = h.ziel; const text = document.createElement('span'); text.className = 'dran__text'; text.textContent = (EINZAHL[h.art] || ((n) => `${n} × ${h.text}`))(h.anzahl); const pfeil = document.createElement('span'); pfeil.className = 'dran__pfeil'; pfeil.setAttribute('aria-hidden', 'true'); pfeil.textContent = '→'; a.append(text, pfeil); li.append(a); liste.append(li); } $('dran-block').hidden = false; } /* Die Zahlen kommen aus derselben Quelle wie das Brett und sind bereits serverseitig auf die eigene Rolle eingegrenzt. */ const ZAHLEN = [ { schluessel: 'ueberfaellig', name: 'Überfällig', warn: true }, { schluessel: 'heute', name: 'Heute fällig' }, { schluessel: 'offen', name: 'Offen' }, { schluessel: 'arbeit', name: 'In Arbeit' }, { schluessel: 'review', name: 'Review' }, { schluessel: 'erledigt', name: 'Erledigt' }, ]; async function zahlenLaden() { let daten; try { const antwort = await fetch('/workspace/api/uebersicht', { credentials: 'same-origin' }); if (!antwort.ok) return; daten = await antwort.json(); } catch { return; } const liste = $('zahlen'); liste.textContent = ''; for (const z of ZAHLEN) { const wert = daten[z.schluessel] ?? 0; const li = document.createElement('li'); li.className = 'zahl'; if (z.warn && wert > 0) li.dataset.warn = 'ja'; const n = document.createElement('span'); n.className = 'zahl__wert'; n.textContent = String(wert); const t = document.createElement('span'); t.className = 'zahl__name'; t.textContent = z.name; li.append(n, t); liste.append(li); } } laden(); })();