// ----------------------------- // Projektübersicht — Personen-Verwaltung (global pro Abteilung) // ----------------------------- // Diese Datei rendert den Personen-Tab (Tab "Projektbeteiligte" in `Test.html`) // und verwaltet die globale Personenliste pro Abteilung: Anlegen, Bearbeiten, // Löschen, Rollen-Auswahl, Drag-and-Drop-Sortierung sowie Urlaub/Abwesenheiten. // Sie wird von `Test.html` nach `js/board/board.js` (vor `js/projects/projects.js`) geladen // und stellt globale Funktionen wie `addPerson()`, `delPerson()`, // `editPerson()`, `renderPeople()` und `addAbsence()` bereit. Genutzt wird sie // u.a. von `js/board/board.js` (`renderBoard`), `js/gantt.js` und // `js/plan/plan-modals.js`; die Sortier-Hilfe `getDragAfterElement()` liegt in // `js/projects/projects.js`. // addPerson: fügt eine neue Person der globalen Liste hinzu und // synchronisiert sie in die aktuelle Sitzung. function addPerson(){ if(guardWeekLocked()) return; const w = currentWeek(); if(!w) return; const name = document.getElementById('newPersonName').value.trim(); const fullName = document.getElementById('newPersonFullName').value.trim(); const email = document.getElementById('newPersonEmail').value.trim(); if(!name){ alert("Kürzel eingeben."); return; } const roles = [...document.querySelectorAll('input[name="newPersonRoles"]:checked')].map(el=>el.value); if(roles.length===0){ alert("Bitte mindestens eine Rolle auswählen."); return; } const person = {id:personIdForName(name), name, fullName:fullName||name, email:email, role:roles}; // Globale Liste aktualisieren if(!Array.isArray(db.globalPeople[currentDepartment])) db.globalPeople[currentDepartment] = []; const existing = db.globalPeople[currentDepartment].find(p => p.id === person.id); if(existing){ alert('Eine Person mit diesem Kürzel existiert bereits.'); return; } db.globalPeople[currentDepartment].push(person); // Aktuelle Sitzung aktualisieren if(!Array.isArray(w.people)) w.people = []; if(!w.people.find(p => p.id === person.id)){ w.people.push(JSON.parse(JSON.stringify(person))); } document.getElementById('newPersonName').value=''; document.getElementById('newPersonFullName').value=''; document.getElementById('newPersonEmail').value=''; document.querySelectorAll('input[name="newPersonRoles"]').forEach(el=>el.checked=false); save(); renderPeople(); renderBoard(); } // delPerson: entfernt eine Person aus der globalen Liste. Bereits in // historischen Sitzungen verwendete Personen bleiben dort sichtbar, da // jede Sitzung ihre eigene Kopie der Personendaten speichert. function delPerson(id){ if(!confirm("Person global löschen? Sie bleibt in bereits existierenden Sitzungen sichtbar, wird aber in neuen Sitzungen nicht mehr angeboten.")) return; // Aus globaler Liste entfernen if(Array.isArray(db.globalPeople[currentDepartment])){ db.globalPeople[currentDepartment] = db.globalPeople[currentDepartment].filter(p=>p.id!==id); } // Aus aktueller Sitzung entfernen (nur wenn nicht in Zuordnungen genutzt) const w = currentWeek(); if(w){ const inUse = w.projects.some(p => Object.keys(p.assign).some(k => k.startsWith(id + '|'))); if(inUse){ alert('Die Person ist in der aktuellen Sitzung noch Projekten zugeordnet. Bitte zuerst die Zuordnungen entfernen.'); return; } w.people = (w.people || []).filter(p=>p.id!==id); } save(); renderPeople(); renderBoard(); } // editPerson: ändert Name/Vollname/Rolle sowohl global als auch in der // aktuellen Sitzung. Historische Sitzungen bleiben unverändert. // Bei Feld `name` wird die ID migriert (`personIdForName`) und die // Zuordnungen/Anwesenheiten werden umgeschrieben. Parameter: `id` // (Personen-ID), `field` (Feldname), `val` (neuer Wert). Keine Rückgabe. function editPerson(id,field,val){ if(guardWeekLocked()) return; const w = currentWeek(); if(!w) return; // Global aktualisieren const globalPeople = db.globalPeople[currentDepartment] || []; const globalPerson = globalPeople.find(p => p.id === id); if(field === 'name'){ const newName = val.trim(); if(!newName) return; const newId = personIdForName(newName); if(newId !== id && globalPeople.some(p => p.id === newId)){ alert('Dieses Kürzel wird bereits verwendet.'); return; } if(globalPerson){ globalPerson.name = newName; globalPerson.id = newId; } // Aktuelle Sitzung aktualisieren und Zuordnungen migrieren const localPerson = (w.people || []).find(p => p.id === id); if(localPerson){ localPerson.name = newName; localPerson.id = newId; } w.projects.forEach(p => { const newAssign = {}; Object.keys(p.assign).forEach(k => { const [oldId, role] = k.split('|'); if(oldId === id){ newAssign[assignKey(newId, role)] = p.assign[k]; } else { newAssign[k] = p.assign[k]; } }); p.assign = newAssign; if(p.plan && Array.isArray(p.plan.people)){ p.plan.people = p.plan.people.map(pid => pid === id ? newId : pid); } }); if(w.attendance){ if(w.attendance[id]){ w.attendance[newId] = true; delete w.attendance[id]; } } save(); renderPeople(); renderBoard(); return; } if(field === 'role'){ const roles = Array.isArray(val) ? [...new Set(val)] : val ? [val] : []; if(globalPerson) globalPerson.role = roles; const localPerson = (w.people || []).find(p => p.id === id); if(localPerson) localPerson.role = roles; } else { if(globalPerson) globalPerson[field] = val; const localPerson = (w.people || []).find(p => p.id === id); if(localPerson) localPerson[field] = val; } save(); renderPeople(); renderBoard(); } // togglePersonRole: fügt eine Rolle (`role`) zur Person `id` hinzu bzw. entfernt // sie (je nach Checkbox-Zustand `checked`), sowohl global als auch in der // aktuellen Sitzung. Keine Rückgabe. function togglePersonRole(id, role, checked){ if(guardWeekLocked()) return; const w = currentWeek(); if(!w) return; const globalPeople = db.globalPeople[currentDepartment] || []; const globalPerson = globalPeople.find(p => p.id === id); const localPerson = (w.people || []).find(p => p.id === id); function updateRoles(person){ person.role = Array.isArray(person.role) ? [...person.role] : person.role ? [person.role] : []; if(checked){ if(!person.role.includes(role)) person.role.push(role); } else { person.role = person.role.filter(r=>r!==role); } } if(globalPerson) updateRoles(globalPerson); if(localPerson) updateRoles(localPerson); save(); renderPeople(); renderBoard(); } // renderPeople: baut die HTML-Liste der Personen für den Personen-Tab auf // (Karten mit Bearbeitungsfeldern, Rollen-Checkboxen, aufklappbaren // Abwesenheiten und Drag-Handle). Bei gesperrter Sitzung wird das // Abwesenheits-Formular ausgeblendet. Keine Parameter, keine Rückgabe. function renderPeople(){ const people = db.globalPeople[currentDepartment] || []; const locked = isWeekLocked(currentWeek()); let html = `