/* =================================================================== Startseite nach dem Anmelden. Sie war eine Wand aus siebzehn gleichen Rechtecken, auf denen jeweils "ÖFFNEN" stand. Wenn alles gleich aussieht, ist alles gleich wichtig -- also nichts. Und "ÖFFNEN" ist keine Information, das weiss man von einer Kachel ohnehin. Drei Dinge machen daraus etwas Brauchbares: 1. GRUPPEN. Was man täglich braucht, was zu einem Creator gehört, was den Laden am Laufen hält -- das sind drei verschiedene Absichten und nicht eine Liste. 2. ZAHLEN STATT "ÖFFNEN". Auf der Kachel steht, wo Arbeit liegt. Dieselben Quellen wie die Hinweise darüber, kein zweiter Zähler. Eine Kachel, die "3" sagt, ist zehnmal mehr wert als eine, die "öffnen" sagt. 3. ZEICHEN UND FARBE. Ein eigenes Zeichen je Bereich und ein eigener Farbton -- man findet sie nach kurzer Zeit blind. Die Seite ist bereits serverseitig geschützt (workspace.js). Dieses Skript holt nur noch, WER angemeldet ist. =================================================================== */ (() => { 'use strict'; const ROLLENTEXT = { spicy: 'Spicy Media · Überblick über alle, ohne Automationen', admin: 'DogFather · Gesamtübersicht und Freigaben', /* Der Satz stimmte bis zum 07.09.2026. Seither legen Manager Creator an -- und ein Rollentext, der etwas anderes verspricht als die Oberflaeche kann, ist schlimmer als gar keiner. */ manager: 'Manager · dieselben Rechte, ohne Personenverwaltung – legt Creator an', creator: 'Creator · dein eigener Bereich', scout: 'Scout · deine Pipeline und die Creator, die du betreust', }; /* Zeichen und Bereiche kommen aus assets/js/bereiche.js -- derselben Quelle, aus der auch die Kopfleisten der Unterseiten ihr Zeichen und ihre Farbe nehmen. Zwei Listen wären der sichere Weg dazu, dass ein Bereich hier gelb und dort grün ist. */ const { ZEICHEN, GRUPPEN, zeichenBauen } = window.Bereiche; /* Welcher Hinweis gehört auf welche Kachel. Die Zahl auf der Kachel ist damit KEIN neuer Zähler, sondern dieselbe Quelle wie die Liste darüber -- sonst stünden irgendwann zwei verschiedene Wahrheiten übereinander auf einem Bildschirm. */ const HINWEIS_ZU_KACHEL = { aufgaben_ueberfaellig: 'Aufgaben', aufgaben_heute: 'Aufgaben', aufgaben_review: 'Aufgaben', termine_heute: 'Kalender', protokoll_fehlt: 'Calls & Protokolle', dateien_review: 'Dateien', bereiche_dringend: 'LIVE-Analyse', startcheck_handlung: 'Start-Check', ohne_startcheck: 'Start-Check', followup_faellig: 'Scout-Pipeline', uebergabe_offen: 'Scout-Pipeline', review_faellig: 'Reports & Review', review_bald: 'Reports & Review', ohne_betreuung: 'Personen & Zugänge', ohne_profil: 'Creator-Profile', markiert_live: 'LIVE-Analyse', markiert_content: 'Content-Ideen', markiert_community: 'Community', markiert_technik: 'Technik', }; /* Diese Hinweise bekommen zusätzlich das Merkzeichen auf die Kachel. Sie sind etwas anderes als "3 Aufgaben offen": Da hat jemand persönlich etwas markiert und wartet auf eine Reaktion. Eine Zahl allein macht diesen Unterschied nicht sichtbar. */ const MIT_MERKZEICHEN = new Set([ 'markiert_live', 'markiert_content', 'markiert_community', 'markiert_technik', ]); /* Findet einen Bereich über seinen Namen -- damit Hinweis und Kachel dasselbe Zeichen und denselben Farbton benutzen, ohne dass die Zuordnung ein zweites Mal irgendwo stünde. */ const bereichZu = (name) => { if (!name) return null; for (const g of GRUPPEN) { const b = g.bereiche.find((x) => x.name === name); if (b) return b; } return null; }; 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; }; let ich = null; /* WESSEN ARBEITSPLATZ WIRD GEZEIGT (02.09.2026). `ich` ist, WER ANGEMELDET ist -- das bleibt so und gilt fuer alles, was schreibt oder Rechte hat. `zeigt` ist, WESSEN Arbeitsplatz auf dem Bildschirm steht. Im Normalfall dasselbe. Vorher gab es nur `ich`, und die Folge war ein halb gebauter Umschalter: Die Listen kamen bereits von der gewaehlten Person, Kacheln, Rolle und Begruessung aber weiterhin von DogFather. Er sah einen Creator-Arbeitsplatz in seiner eigenen Verkleidung -- gemeldet mit "ich seh immer noch die Seite genau wie meine". */ let zeigt = null; let hinweise = []; /* ---------- Aufbau ------------------------------------------------------- */ function bereicheBauen() { const ziel = $('bereiche'); ziel.textContent = ''; /* Zahlen je Kachel aus den Hinweisen zusammenzählen. Warnstufe schlägt durch: Eine Kachel mit etwas Überfälligem ist rot, auch wenn daneben Harmloses mitgezählt wird. */ const zahlen = new Map(); for (const h of hinweise) { const kachel = HINWEIS_ZU_KACHEL[h.art]; if (!kachel) continue; const bisher = zahlen.get(kachel) || { n: 0, warn: false, merk: 0 }; bisher.n += h.anzahl; if (h.stufe === 'warnung') bisher.warn = true; if (MIT_MERKZEICHEN.has(h.art)) bisher.merk += h.anzahl; zahlen.set(kachel, bisher); } /* ================================================================= WELCHE KACHELN DIESE PERSON SIEHT (10.09.2026) ZWEI QUELLEN, und die Reihenfolge ist die Aussage: 1. Schickt der Server eine Liste, gilt sie. Das ist der Weg fuer Rollen, die in bereiche.js gar nicht vorkommen duerfen -- diese Datei bekommt jeder ausgeliefert, der die Seite oeffnet, und ein Rollenname darin waere mit einem Blick in den Quelltext gefunden. 2. Sonst wie bisher: die Rollenliste an der Kachel selbst. Nach der ANGESEHENEN Rolle, nicht der eigenen -- sonst stuenden bei der Sicht auf einen Creator weiterhin "Personen & Zugaenge" und "Automationen" da, die er gar nicht hat. Genau daran war zu sehen, dass die Sicht nicht greift. Der Server richtet sich beim Bauen seiner Liste nach derselben Person. `null` heisst "nimm deine eigene Liste", eine LEERE Liste hiesse "keine Kacheln". Die beiden auseinanderzuhalten ist kein Feinschliff: Verwechselte man sie, haetten die fuenf bekannten Rollen ab sofort eine leere Startseite. */ /* Ist die Seite hinter diesem Ziel fuer mich offen? Ohne Auskunft vom Server: ja -- siehe oben. */ function seiteOffen(ziel) { const offen = ich?.seiten; if (!Array.isArray(offen) || !offen.length) return true; const z2 = String(ziel || ""); if (!z2) return true; return offen.includes('/workspace/' + z2.split('?')[0]); } function eigeneGruppen(wer) { const vomServer = ich && ich.bereiche; if (Array.isArray(vomServer)) { /* Nach Gruppen buendeln, in der Reihenfolge, in der sie kommen -- eine Map behaelt sie, ein Objekt sortierte Zahlenschluessel um. Hier sind es Woerter, aber darauf zu bauen waere die Art Annahme, die spaeter jemanden Zeit kostet. */ const nach = new Map(); for (const b of vomServer) { if (!nach.has(b.gruppe)) { nach.set(b.gruppe, { name: b.gruppe, unter: b.gruppeUnter || '', bereiche: [] }); } nach.get(b.gruppe).bereiche.push(b); } return [...nach.values()]; } /* KACHELN, DIE DAZUKOMMEN (10.09.2026). Anders als `ich.bereiche` (das die Liste ERSETZT) haengen diese sich an eine vorhandene Gruppe an. Gebraucht wird das fuer Kacheln, die nur eine einzige Rolle bekommt: In dieser Datei duerften sie nicht stehen -- sie wird an jeden ausgeliefert, und eine Kachel, die nur bei einem erscheint, wirft die Frage auf, fuer wen sie ist. Findet sich die genannte Gruppe nicht, wird eine eigene angelegt. Sonst faellt die Kachel lautlos weg, sobald jemand eine Gruppe umbenennt -- und niemand merkt es, weil nichts kaputtgeht. */ const zusatz = Array.isArray(ich?.bereiche_zusatz) ? ich.bereiche_zusatz : []; const gruppen = GRUPPEN /* UND GEGEN DIE RECHTETAFEL (11.09.2026). `rollen` an der Kachel ist die Liste in dieser Datei -- sie wird von Hand gepflegt und kennt nichts davon, dass DogFather eine Seite umgestellt hat. `ich.seiten` kommt vom Server und ist dieselbe Auskunft, aus der auch die Schranke ihre Entscheidung holt. BEIDES UND NICHT NUR EINES: Die Liste hier entscheidet, was ueberhaupt angeboten wird; die Tafel, ob es noch offen ist. Faellt `ich.seiten` aus (alte Fassung im Zwischenspeicher), bleibt es beim alten Verhalten -- eine Kachel zu viel ist aergerlich, eine fehlende sieht aus wie ein Fehler. */ .map((g) => ({ ...g, bereiche: g.bereiche.filter((b) => b.rollen.includes(wer.rolle) && seiteOffen(b.ziel)) })) .filter((g) => g.bereiche.length); for (const b of zusatz) { const g = gruppen.find((x) => x.name === b.gruppe); if (g) { g.bereiche = [...g.bereiche, b]; continue; } /* EINE NEUE GRUPPE DARF SAGEN, WO SIE HINGEHOERT (10.09.2026). Bis hierhin wurde sie hinten angehaengt. Filipe: "ich will dass die kacheln ... eine eigene kategorie haben. damit ich nicht zwischen den kacheln suchen muss." Ganz unten waere zwar eine eigene Kategorie -- aber immer noch Scrollen. `gruppeNach` nennt die Gruppe, HINTER der sie stehen soll. Findet sie sich nicht (umbenannt, fuer diese Rolle nicht dabei), bleibt es beim Anhaengen: Eine Kachel, die wegen einer Reihenfolge verschwindet, waere der schlechtere Tausch. */ const neuGruppe = { name: b.gruppe, unter: b.gruppeUnter || '', bereiche: [b] }; const nach = b.gruppeNach ? gruppen.findIndex((x) => x.name === b.gruppeNach) : -1; if (nach >= 0) gruppen.splice(nach + 1, 0, neuGruppe); else gruppen.push(neuGruppe); } return gruppen; } let laufNr = 0; for (const gruppe of eigeneGruppen(zeigt)) { const meine = gruppe.bereiche; if (!meine.length) continue; const abschnitt = el('section', 'gruppe'); /* Manche Gruppen heißen für einen Creator anders -- siehe GRUPPEN. */ const istCreator = zeigt.rolle === 'creator'; /* =============================================================== JEDE GRUPPE LAESST SICH ZUKLAPPEN (07.09.2026) Wunsch Filipe: "diese kategorien soll man auch zu und aufmachen koennen so wie es einem lieb ist gerade." DER KOPF IST DER SCHALTER, nicht ein Knopf daneben. Eine Ueberschrift, neben der ein kleines Dreieck sitzt, laedt zum Zielen ein; eine Ueberschrift, die SELBST der Schalter ist, trifft man immer. Deshalb