// -----------------------------
// Einführung — geführter Rundgang
// -----------------------------
// Eriks Wunsch: Jeder Nutzer, auch bestehende, macht einmal einen geführten
// Rundgang durch die Anwendung; unter Einstellungen → Mein Konto lässt er
// sich jederzeit neu starten. Der Rundgang hebt den jeweiligen Eintrag der
// Seitenleiste hervor (Aussparung in einer abgedunkelten Ebene), wechselt in
// den Bereich und erklärt ihn in einer Sprechblase.
//
// Gezeigt wird nur, was die Rolle darf (hatRecht(), Rollen & Rechte) — ein
// Konto ohne „Anwendung nutzen“ (Wandtafel) bekommt keinen Rundgang.
// Abgeschlossen oder übersprungen → POST /einfuehrung (users.einfuehrung_am),
// danach startet er nicht mehr von selbst. Esc bzw. „Später“ schließt nur
// für diesen Seitenaufruf (sessionStorage) — beim nächsten Laden kommt er
// wieder.
//
// Ein Schritt: { id, recht?, wenn?(), tab?, ziel? (CSS-Selektor), titel,
// text (HTML, aus festen Texten) }. Ohne ziel steht die Blase in der Mitte.
const EINFUEHRUNG_SCHRITTE = [
{ id: 'start', titel: 'Willkommen in der Projektübersicht',
text: () => `Hallo ${esc((currentUser && (currentUser.displayName || '').split(' ')[0]) || '')}! In gut zwei Minuten zeigen wir dir, wo du was findest. Mit den Pfeiltasten oder „Weiter“ geht es durch, „Später“ schließt den Rundgang für jetzt.` },
{ id: 'dashboard', recht: 'app', tab: 'dashboard', ziel: '.sidebar-nav [data-tab="dashboard"]', titel: 'Dashboard',
text: () => 'Deine Startseite: die Aufgaben, die dir zugewiesen sind, die nächsten Termine deiner Projekte und ein Kalender mit Meilensteinen und Abwesenheiten. Überfälliges steht oben.' },
{ id: 'glocke', recht: 'app', ziel: '#glockeBtn', titel: 'Benachrichtigungen',
text: () => 'Die Glocke zeigt, wenn dir jemand eine neue Aufgabe zugewiesen hat. Ein Klick springt direkt in die Aufgaben des Projekts.' },
{ id: 'projekte', recht: 'app', tab: 'board', ziel: '.sidebar-nav [data-tab="board"]', titel: 'Projekte',
text: () => 'Alle Projekte der laufenden Sitzung, nach Gruppen.' + (hatRecht('proj.anlegen') ? ' Über „+ Projekt“ legst du ein neues an — ein Assistent fragt Gewerke, Auftrag, Team und Terminplan ab.' : '') },
{ id: 'projektbereich', recht: 'app', tab: 'board', ziel: '#board .board-name', titel: 'Der Projektbereich',
text: () => 'Ein Klick auf den Projektnamen öffnet den Bereich des Projekts. Oben stehen die Reiter: Dashboard, Terminplan, Leistungsphasen, Aufgaben, Leistung, Dateien, Protokolle und Einstellungen.' },
{ id: 'terminplan', recht: 'proj.plan', tab: 'board', titel: 'Terminplan und Vorlagen',
text: () => 'Im Reiter Terminplan legst du über „+ Neu“ Leistungsphasen, Aufgaben und Meilensteine an. „+ Vorlage“ fügt die Grundleistungen der HOAI für dein Gewerk ein — die Dauer verteilt sich nach den Siemon-Anteilen über den Phasenbalken. Gib Aufgaben einen Aufwand in Stunden, dann zählen sie in der Auslastung.' },
{ id: 'wochenbericht', recht: 'app', tab: 'wochenbericht', ziel: '.sidebar-nav [data-tab="wochenbericht"]', titel: 'Wochenbericht',
text: () => 'Die Tagesordnung der wöchentlichen Besprechung, je Gewerk. Links die Projekte, rechts das gewählte.' + (hatRecht('wb.kommentar') ? ' Hier schreibst du den Kommentar der Woche und den Fortschritt der Leistungsphasen; „Besprochen & weiter“ führt zum nächsten Projekt.' : '') + ' „Als PDF ablegen“ speichert den Bericht.' },
{ id: 'auslastung', recht: 'app', tab: 'load', ziel: '.sidebar-nav [data-tab="load"]', titel: 'Auslastung',
text: () => 'Wie voll die nächsten zwölf Wochen für jede Person sind. Die Stunden kommen aus den Aufgaben mit Aufwand — eine Aufgabe für zwei Personen zählt für jede zur Hälfte.' },
{ id: 'abwesenheiten', wenn: () => typeof darfIrgendeineAbwesenheit === 'function' && darfIrgendeineAbwesenheit(), tab: 'abwesenheit', ziel: '.sidebar-nav [data-tab="abwesenheit"]', titel: 'Abwesenheiten',
text: () => 'Hier trägst du Urlaub, Krankheit und Fortbildung ein. Unten siehst du das Team im Monat — wer außerhalb deines Bereichs liegt, erscheint nur als „abwesend“.' + (hatRecht('team.abwAlle') || hatRecht('team.abwGewerk') || hatRecht('team.abwProjekte') ? ' Ein Klick auf einen Tag in der Zeile einer Person trägt für sie ein.' : '') },
{ id: 'planung', recht: 'wz.planung', tab: 'planung', ziel: '.sidebar-nav [data-tab="planung"]', titel: 'Planung → Terminplan',
text: () => 'Terminpläne ohne echtes Projekt — zum Ausprobieren, für Angebote oder um Kapazität abzuschätzen. Aus einem Honorar errechnet oder frei angelegt.' },
{ id: 'planchecker', recht: 'wz.checker', tab: 'planchecker', ziel: '.sidebar-nav [data-tab="planchecker"]', titel: 'Plan Checker',
text: () => 'Lädt einen Plan als PDF hoch und lässt ihn von einer KI gegen eine Liste von Merkmalen prüfen. Dafür brauchst du einen eigenen KI-Schlüssel unter Einstellungen.' },
{ id: 'einstellungen', tab: 'settings', ziel: '.sidebar-nav [data-tab="settings"]', titel: 'Einstellungen',
text: () => 'Dein Konto: Passwort, E-Mail-Adresse, deine KI-Schlüssel und die Darstellung. Hier kannst du diesen Rundgang jederzeit neu starten.' },
{ id: 'admin', wenn: () => typeof hatAdminRecht === 'function' && hatAdminRecht(), ziel: '#adminAccordionToggle', titel: 'Admin',
text: () => 'Du darfst Teile der Verwaltung pflegen: ' + esc(typeof ADMIN_SECTIONS !== 'undefined' ? ADMIN_SECTIONS.filter(adminAbschnittErlaubt).map(s => s.title).join(', ') : '') + '.' },
{ id: 'ende', tab: 'dashboard', titel: 'Rundgang abgeschlossen',
text: () => {
const hinweise = [];
if(currentUser && !currentUser.personId){
hinweise.push('Dein Konto ist noch keiner Person zugeordnet — „Meine Aufgaben“ bleibt deshalb leer. Bitte einen Administrator, das in der Benutzerverwaltung nachzutragen.');
}
return 'Das war der Überblick. Bei Fragen hilft dir ein Kollege — oder du startest den Rundgang unter Einstellungen noch einmal.'
+ (hinweise.length ? '
' + hinweise.map(h => '
' + h + '
').join('') + '
' : '');
} },
];
let tourSchritte = [];
let tourIndex = 0;
let tourAktiv = false;
let tourVorTab = null;
// einfuehrungBeiBedarf: startet den Rundgang, wenn er für dieses Konto noch
// aussteht — sobald die Daten geladen sind und kein Dialog (Passwort) offen
// ist. Von afterAuthenticated() und nach dem Pflicht-Passwortwechsel gerufen.
function einfuehrungBeiBedarf(){
if(!currentUser || !currentUser.einfuehrungFaellig || !hatRecht('app')) return;
try { if(sessionStorage.getItem('projuebersicht-tour-spaeter')) return; } catch(e){}
let versuche = 0;
const pruefen = () => {
if(tourAktiv) return;
const geladen = typeof currentWeek === 'function' && currentWeek();
const dialogOffen = [...document.querySelectorAll('.modal-bg')].some(m => m.style.display && m.style.display !== 'none');
const login = document.getElementById('loginOverlay');
const loginOffen = login && login.style.display !== 'none' && !login.hidden && login.offsetParent !== null;
if(geladen && !dialogOffen && !loginOffen) return einfuehrungStarten();
if(++versuche < 120) setTimeout(pruefen, 500);
};
setTimeout(pruefen, 600);
}
// einfuehrungStarten: Rundgang von vorn (auch aus Einstellungen).
function einfuehrungStarten(){
tourSchritte = EINFUEHRUNG_SCHRITTE.filter(s => (!s.recht || hatRecht(s.recht)) && (!s.wenn || s.wenn()));
tourIndex = 0;
tourAktiv = true;
tourVorTab = typeof currentTab !== 'undefined' ? currentTab : null;
let el = document.getElementById('tourEbene');
if(!el){
el = document.createElement('div');
el.id = 'tourEbene';
el.className = 'tour';
el.innerHTML = '';
document.body.appendChild(el);
window.addEventListener('resize', () => { if(tourAktiv) tourPositionieren(); });
document.addEventListener('keydown', tourTaste, true);
}
el.hidden = false;
tourZeigen();
}
function tourTaste(e){
if(!tourAktiv) return;
if(e.key === 'Escape'){ e.preventDefault(); e.stopPropagation(); tourSpaeter(); }
else if(e.key === 'ArrowRight' || (e.key === 'Enter' && !e.target.closest('button'))){ e.preventDefault(); tourWeiter(); }
else if(e.key === 'ArrowLeft'){ e.preventDefault(); tourZurueck(); }
}
// tourZeigen: aktuellen Schritt aufbauen (Bereich wechseln, Blase füllen,
// danach Aussparung und Blase an das Ziel legen).
function tourZeigen(){
const s = tourSchritte[tourIndex];
if(!s) return tourBeenden(true);
if(s.tab && typeof showTab === 'function' && currentTab !== s.tab) showTab(s.tab);
const blase = document.querySelector('#tourEbene .tour-blase');
const letzter = tourIndex === tourSchritte.length - 1;
blase.innerHTML = `