Hello, I have a problem with my js-code.
Thats the error: Uncaught SyntaxError: expected expression, got ')'main.js:1032:2
And thats the code:
// static/js/main.js
// Stand: Korrigiert, aufgeräumt, korrektes Feedback im Schichtplan
document.addEventListener('DOMContentLoaded', function() {
console.log("########## DOMContentLoaded START ##########");
// === Globales Objekt für Daten aus Templates ===
// Wird einmalig beim Laden der Seite gefüllt
window.schichtplanerData = {};
try {
const empDataElem = document.getElementById('employeeDataJson');
const shiftDictElem = document.getElementById('shiftTypesDataJson'); // Dict mit Objekten
const allShiftsElem = document.getElementById('allShiftTypesJson'); // Dict {id: obj} für Modal
const allGroupsElem = document.getElementById('allMachineGroupsJson'); // Dict {id: obj} für Modal
const qualiLevelsElem = document.getElementById('qualificationLevelsJson');
// Parse JSON data, provide empty objects as fallbacks
window.schichtplanerData.employeeDict = empDataElem ? JSON.parse(empDataElem.textContent || '{}') : {};
window.schichtplanerData.shiftTypesDict = shiftDictElem ? JSON.parse(shiftDictElem.textContent || '{}') : {};
window.schichtplanerData.allShiftTypes = allShiftsElem ? JSON.parse(allShiftsElem.textContent || '{}') : {};
window.schichtplanerData.machineGroupsDict = allGroupsElem ? JSON.parse(allGroupsElem.textContent || '{}') : {};
window.schichtplanerData.qualificationLevelsData = qualiLevelsElem ? JSON.parse(qualiLevelsElem.textContent || '{}') : {};
console.log("Globale Daten geladen:", window.schichtplanerData);
} catch (e) {
console.error("Fehler beim Parsen der globalen JSON-Daten!", e);
// Setze leere Fallbacks
window.schichtplanerData = { employeeDict:{}, shiftTypesDict:{}, allShiftTypes:{}, machineGroupsDict:{}, qualificationLevelsData:{} };
}
// === ENDE Globale Daten ===
// PASTE START 1: Ersetzt den ursprünglichen Modal-Steuerungsblock
// === Modul: Modal Steuerung (ANGEPASST für generisches Öffnen) ===
const commonModalElement = document.getElementById("commonModal");
const commonModalTitle = commonModalElement ? commonModalElement.querySelector("#modalTitle") : null;
const commonModalBody = commonModalElement ? commonModalElement.querySelector("#modalBody") : null;
// const commonCloseModalBtn = commonModalElement ? commonModalElement.querySelector(".close-modal-btn") : null; // Nicht mehr global gebraucht
// Das spezielle Einstellungs-Modal für Schichtarten holen
const settingsModalElement = document.getElementById("shiftTypeSettingsModal");
const settingsModalTitle = settingsModalElement ? settingsModalElement.querySelector("#shiftTypeSettingsModalTitle") : null;
const settingsModalBody = settingsModalElement ? settingsModalElement.querySelector("#shiftTypeSettingsModalBody") : null;
// const settingsCloseModalBtn = settingsModalElement ? settingsModalElement.querySelector(".close-modal-btn") : null; // Nicht mehr global gebraucht
// GENERISCHE Funktion zum Öffnen eines Modals
// targetModalId: ID des Modals, das geöffnet werden soll ('commonModal' oder 'shiftTypeSettingsModal')
// title: Titel für das Modal
// contentSourceId: ID des Containers im HTML, dessen Inhalt kopiert werden soll
// contentType: 'form' (nur erstes Formular kopieren) oder 'full' (gesamten Inhalt kopieren)
function openModalGeneric(targetModalId, title, contentSourceId, contentType = 'form') {
const modalToOpen = document.getElementById(targetModalId);
// IDs für Titel/Body aus dem spezifischen Modal holen
const modalTitleElement = modalToOpen ? modalToOpen.querySelector('h2') : null; // Nimmt die erste H2 im Modal
const modalBodyElement = modalToOpen ? modalToOpen.querySelector('.modal-content > div:last-of-type') : null; // Nimmt das letzte Div im .modal-content
const contentSourceContainer = document.getElementById(contentSourceId);
if (modalToOpen && modalTitleElement && modalBodyElement && contentSourceContainer) {
modalTitleElement.textContent = title || 'Dialog'; // Titel setzen
let contentToInsert = null;
if (contentType === 'full') {
// Kopiere den gesamten *Inhalt* des Quellcontainers
contentToInsert = contentSourceContainer.innerHTML;
console.log(`Modal Content Type 'full' for ${contentSourceId}`);
} else { // Default: 'form'
// Kopiere nur das *erste Formular* aus dem Quellcontainer
const formTemplate = contentSourceContainer.querySelector('form');
if (formTemplate) {
contentToInsert = formTemplate.cloneNode(true); // Klonen, damit Original bleibt
console.log(`Modal Content Type 'form' for ${contentSourceId}`);
} else {
console.error(`Kein Element im Container #${contentSourceId} gefunden für contentType 'form'.`);
modalBodyElement.innerHTML = 'Fehler: Formular konnte nicht geladen werden.';
modalToOpen.style.display = "block"; // Zeige Modal trotzdem an, aber mit Fehlermeldung
return;
}
}
// Inhalt einfügen
if (contentType === 'full') {
modalBodyElement.innerHTML = contentToInsert; // Gesamten HTML-String einfügen
} else if (contentToInsert) {
modalBodyElement.innerHTML = ''; // Alten Inhalt leeren
modalBodyElement.appendChild(contentToInsert); // Geklontes Formular einfügen
}
// Event-Listener für interne Schließen-Buttons im neu eingefügten Inhalt hinzufügen
modalBodyElement.querySelectorAll('.close-modal-btn-internal').forEach(btn => {
btn.addEventListener('click', () => { modalToOpen.style.display = "none"; });
});
modalToOpen.style.display = "block"; // Modal anzeigen
console.log(`Modal #${targetModalId} geöffnet für: ${title} mit Inhalt von #${contentSourceId}`);
} else {
console.error("Modal-Öffnen fehlgeschlagen. Fehlende Elemente:", {
modalToOpen: !!modalToOpen, modalTitleElement: !!modalTitleElement, modalBodyElement: !!modalBodyElement,
contentSourceContainer: !!contentSourceContainer, targetModalId: targetModalId, contentSourceId: contentSourceId
});
}
} // Ende openModalGeneric
// Globale Event Listener für Modal-Schließen (für beide Modals über das X oder Klick daneben)
[commonModalElement, settingsModalElement].forEach(modalElem => {
if (modalElem) {
const closeBtn = modalElem.querySelector(".close-modal-btn"); // Das X oben rechts
if (closeBtn) {
closeBtn.onclick = function() { modalElem.style.display = "none"; }
}
// Schließen bei Klick außerhalb des Inhalts
modalElem.addEventListener('click', function(event) {
if (event.target === modalElem) { // Nur wenn direkt auf den Hintergrund geklickt wird
modalElem.style.display = "none";
}
});
}
});
// Den alten globalen window.onclick entfernen, falls vorhanden, da er jetzt pro Modal gehandhabt wird.
// --- Event Listener für Buttons, die Modals öffnen ---
// Wir nutzen Event Delegation auf dem document, um alle Buttons zu fangen
document.addEventListener('click', function(event) {
const button = event.target.closest('button[data-modal-target]'); // Finde Button mit Attribut
if (button) {
event.preventDefault(); // Verhindere Standardverhalten, falls es ein Submit-Button in einem Formular ist
const contentSourceId = button.dataset.modalTarget;
// Standardmäßig das 'commonModal' verwenden, außer ein anderes ist spezifiziert
const targetModalId = button.dataset.modalId || 'commonModal';
const title = button.dataset.modalTitle || 'Dialog';
// Prüfen, ob es der spezielle Settings-Button ist, der den gesamten Inhalt braucht
const contentType = (targetModalId === 'shiftTypeSettingsModal' && contentSourceId === 'shiftTypeSettingsContainer') ? 'full' : 'form';
console.log(`Button Click -> Opening Modal: targetModalId=${targetModalId}, title=${title}, contentSourceId=${contentSourceId}, contentType=${contentType}`);
openModalGeneric(targetModalId, title, contentSourceId, contentType);
}
});
// === ENDE Modul: Modal Steuerung ===
// PASTE END 1
// --- Modul: Schichtplan Interaktion (Kompakte Zelle + Modal) ---
const scheduleGroupTableBody = document.getElementById('schedule-group-body');
if (scheduleGroupTableBody) {
console.log("Schichtplaner JS: Initialisiere Schichtplan Logik (Gruppenansicht - Modal Edit).");
// Listener für Klicks auf die Zuweisungszellen -> öffnet Modal
scheduleGroupTableBody.addEventListener('click', function(event) {
const cell = event.target.closest('.schedule-assignment-cell');
if (cell) {
event.preventDefault();
const date = cell.dataset.date;
const shiftId = cell.dataset.shiftId;
const groupId = cell.dataset.groupId;
const currentEmployeeIdsStr = cell.dataset.currentEmployees || '';
const currentEmployeeIds = currentEmployeeIdsStr ? currentEmployeeIdsStr.split(',').map(id => id.trim()) : [];
console.log(`Klick auf Zelle: Datum=${date}, Schicht=${shiftId}, Gruppe=${groupId}, Zugewiesen=[${currentEmployeeIds.join(',')}]`);
openAssignmentEditModal(date, shiftId, groupId, currentEmployeeIds); // Spezielle Modal-Funktion
}
});
// Funktion zum Öffnen und Befüllen des Zuweisungs-Modals
function openAssignmentEditModal(date, shiftId, groupId, currentEmployeeIds) {
console.log("Öffne Zuweisungs-Edit-Modal für:", {date, shiftId, groupId, currentEmployeeIds});
if (!modal || !modalTitle || !modalBody) { console.error("Modal Elemente nicht initialisiert!"); return; }
// Titel setzen
const shiftInfo = window.schichtplanerData.shiftTypesDict[shiftId] || { abbreviation: '?' };
const groupInfo = window.schichtplanerData.machineGroupsDict[groupId] || { name: 'Keine', abbreviation: '--' };
modalTitle.textContent = `Zuweisung ändern (${date} / ${shiftInfo.abbreviation} / ${groupInfo.name})`;
// Modal-Inhalt aus Vorlage holen und befüllen
const formTemplateContainer = document.getElementById('assignmentEditModalTemplate');
if (!formTemplateContainer) { console.error("Modal-Vorlage #assignmentEditModalTemplate nicht gefunden!"); return; }
const formTemplate = formTemplateContainer.querySelector('form');
if (!formTemplate) { console.error("Kein in #assignmentEditModalTemplate gefunden!"); return; }
const formClone = formTemplate.cloneNode(true); // Formular klonen
// Mitarbeiter-Select füllen
const employeeSelect = formClone.querySelector('#modal_employee_select');
if (employeeSelect && window.schichtplanerData.employeeDict) {
employeeSelect.innerHTML = ''; // Alte Optionen leeren
for (const empId in window.schichtplanerData.employeeDict) {
const employee = window.schichtplanerData.employeeDict[empId];
const isSelected = currentEmployeeIds.includes(String(empId)); // Als String vergleichen
// TODO: Quali-Check und Option markieren
const option = document.createElement('option');
option.value = empId;
option.textContent = employee.name;
if (isSelected) { option.selected = true; }
employeeSelect.appendChild(option);
}
} else if (!employeeSelect) { console.error("#modal_employee_select nicht im Template gefunden"); }
else { console.error("Mitarbeiterdaten (employeeDict) für Modal nicht verfügbar"); }
// Modal-Body leeren und befülltes Formular einfügen
modalBody.innerHTML = '';
modalBody.appendChild(formClone);
modal.style.display = 'block'; // Modal anzeigen
// Event Listener für das Formular im Modal hinzufügen
const visibleForm = modalBody.querySelector('#assignmentModalForm');
const deleteBtn = modalBody.querySelector('#deleteAssignmentBtn');
if (visibleForm) {
// Daten im Formular speichern für Submit/Delete Handler
visibleForm.dataset.date = date;
visibleForm.dataset.shiftId = shiftId;
visibleForm.dataset.groupId = groupId;
// Listener neu anhängen
visibleForm.replaceWith(visibleForm.cloneNode(true)); // Alten Listener entfernen
modalBody.querySelector('#assignmentModalForm').addEventListener('submit', handleAssignmentModalSubmit);
// Listener für Löschen-Button auch neu anhängen
const newDeleteBtn = modalBody.querySelector('#deleteAssignmentBtn');
if(newDeleteBtn) {
newDeleteBtn.replaceWith(newDeleteBtn.cloneNode(true));
modalBody.querySelector('#deleteAssignmentBtn').addEventListener('click', handleDeleteAssignment);
}
}
// Interne Schließen-Buttons
modalBody.querySelectorAll('.close-modal-btn-internal').forEach(btn => {
btn.addEventListener('click', () => { modal.style.display = "none"; });
});
} // Ende openAssignmentEditModal
// Funktion zum Verarbeiten des Modal-Submits (sendet PUT mit Liste)
function handleAssignmentModalSubmit(event) {
event.preventDefault();
const form = event.target;
const date = form.dataset.date; const shiftId = form.dataset.shiftId; const groupId = form.dataset.groupId;
const selectedEmployees = Array.from(form.querySelector('select[name="selected_employees"]').selectedOptions).map(option => option.value);
console.log("Sende Modal Daten (PUT):", {date, shiftId, groupId, employee_ids: selectedEmployees});
const apiUrl = '/api/assignment'; const dataToSend = { date, shift_id: shiftId, group_id: groupId, employee_ids: selectedEmployees };
const submitButton = form.querySelector('button[type="submit"]'); if(submitButton) submitButton.disabled = true;
fetch(apiUrl, { method: 'PUT', headers: { 'Content-Type': 'application/json', 'Accept': 'application/json' }, body: JSON.stringify(dataToSend) })
.then(response => response.json().then(data => ({ ok: response.ok, data: data })))
.then(result => {
if (result.ok && result.data && result.data.status === 'success') {
console.log("Update erfolgreich:", result.data.message); if(modal) modal.style.display = 'none';
updateScheduleCell(date, shiftId, groupId, result.data.assigned_employee_ids || []);
} else { throw new Error(result.data.message || 'Fehler beim Speichern'); }
})
.catch(error => { console.error("Fehler Modal Submit:", error); alert(`Fehler: ${error.message}`); })
.finally(() => { if(submitButton) submitButton.disabled = false; });
} // Ende handleAssignmentModalSubmit
// Funktion zum Löschen der Zuweisung(en) für diese Zelle (sendet DELETE)
function handleDeleteAssignment(event) {
const form = event.target.closest('form'); const date = form.dataset.date; const shiftId = form.dataset.shiftId; const groupId = form.dataset.groupId;
if (confirm(`Alle Zuweisungen für Schicht ${shiftId} / Gruppe ${groupId || 'Keine'} am ${date} löschen?`)) {
console.log("Lösche Zuweisungen für:", {date, shiftId, groupId});
const apiUrl = '/api/assignment'; const dataToSend = { date: date, shift_id: shiftId, group_id: groupId };
fetch(apiUrl, { method: 'DELETE', headers: { 'Content-Type': 'application/json', 'Accept': 'application/json' }, body: JSON.stringify(dataToSend) })
.then(response => response.json().then(data => ({ ok: response.ok, data: data })))
.then(result => {
if (result.ok && result.data && result.data.status === 'success') { console.log("Löschen erfolgreich:", result.data.message); if(modal) modal.style.display = 'none'; updateScheduleCell(date, shiftId, groupId, []); }
else { throw new Error(result.data.message || 'Fehler beim Löschen'); }
})
.catch(error => { console.error("Fehler beim Löschen:", error); alert(`Fehler: ${error.message}`); });
}
} // Ende handleDeleteAssignment
// Funktion zum Aktualisieren der Zelle im Schichtplan
function updateScheduleCell(date, shiftId, groupId, assignedEmployeeIds) {
const cellSelector = `td[data-date="${date}"][data-shift-id="${shiftId}"][data-group-id="${groupId}"]`;
const cell = scheduleGroupTableBody.querySelector(cellSelector);
if (cell) {
console.log("Aktualisiere Zelle (Kürzel-Ansicht):", cellSelector, "Neue IDs:", assignedEmployeeIds);
cell.innerHTML = ''; // Leere Zelle zuerst
const shiftInfo = window.schichtplanerData.shiftTypesDict[shiftId] || {};
const groupInfo = window.schichtplanerData.machineGroupsDict[groupId] || {}; // Nutze machineGroupsDict für Abk.
const bgColor = shiftInfo?.color || '#ffffff';
const shiftTextColor = shiftInfo?.effective_text_color || '#000000';
const isAbsence = shiftInfo?.is_absence || false;
cell.style.backgroundColor = bgColor;
const contentWrapper = document.createElement('div');
contentWrapper.className = 'schedule-cell-content-simple'; // Verwende die Klasse für das einfache Layout
// Schicht-Kürzel
if (assignedEmployeeIds.length > 0 || isAbsence) { // Zeige Kürzel wenn MA da sind ODER es Abwesenheit ist
const shiftDiv = document.createElement('div');
shiftDiv.className = 'schedule-cell-shift-abbr';
shiftDiv.style.color = shiftTextColor;
shiftDiv.textContent = shiftInfo.abbreviation || '-';
contentWrapper.appendChild(shiftDiv);
}
// Gruppen-Kürzel
if (!isAbsence && groupId && groupInfo.abbreviation && assignedEmployeeIds.length > 0) { // Zeige Gruppe nur wenn MA da und keine Abwesenheit
const groupDiv = document.createElement('div');
groupDiv.className = 'schedule-cell-group-abbr-simple';
groupDiv.style.color = shiftTextColor;
groupDiv.textContent = groupInfo.abbreviation;
contentWrapper.appendChild(groupDiv);
}
// Plus-Zeichen
if (assignedEmployeeIds.length === 0 && !isAbsence) {
const span = document.createElement('span');
span.className = 'text-muted no-assignment-plus';
span.textContent = '+';
contentWrapper.appendChild(span);
}
cell.appendChild(contentWrapper);
// Wichtig: Dataset aktualisieren, damit der nächste Klick die korrekten IDs hat!
cell.dataset.currentEmployees = assignedEmployeeIds.join(',');
} else {
console.error("Konnte Zelle zum Aktualisieren nicht finden:", cellSelector);
}
} // Ende updateScheduleCell (Kürzel-Version)
// --- Modul 2: Qualifikationsmatrix Interaktion ---
const qualiMatrixBody = document.getElementById('quali-matrix-body');
if (qualiMatrixBody) {
console.log("Schichtplaner JS: Initialisiere Quali-Matrix Logik.");
let qualificationLevelsData = {};
try {
const qualiLevelsElement = document.getElementById('qualificationLevelsJson');
if (qualiLevelsElement) { qualificationLevelsData = JSON.parse(qualiLevelsElement.textContent); console.log("Quali Levels Data loaded:", qualificationLevelsData); }
else { throw new Error("JSON script element for levels not found."); }
} catch(e) { console.error("Konnte qualification_levels nicht laden! Verwende Fallback.", e); qualificationLevelsData = { 0: { abbr: '-', color: '#f8f9fa', effective_text_color: '#6c757d', desc: 'Error' }}; }
// Klick auf Zelle -> Edit-Modus
qualiMatrixBody.addEventListener('click', function(event) {
const cell = event.target.closest('td.qual-cell');
if (cell && event.target.tagName !== 'SELECT') {
const isEditing = cell.classList.contains('editing');
qualiMatrixBody.querySelectorAll('td.qual-cell.editing').forEach(otherCell => {
if (otherCell !== cell) { otherCell.classList.remove('editing'); otherCell.querySelector('.qual-level-display').style.display = 'block'; otherCell.querySelector('.qual-level-select').style.display = 'none'; }
});
if (!isEditing) {
cell.classList.add('editing'); cell.querySelector('.qual-level-display').style.display = 'none';
const select = cell.querySelector('.qual-level-select'); select.style.display = 'block';
select.value = cell.dataset.currentLevel; select.focus();
}
}
});
// Änderung im Select -> Speichern via API
qualiMatrixBody.addEventListener('change', function(event) {
const select = event.target;
if (select.classList.contains('qual-level-select')) {
const cell = select.closest('td.qual-cell');
const employeeId = cell.dataset.employeeId; const qualificationId = cell.dataset.qualificationId; const newLevel = select.value;
const displayDiv = cell.querySelector('.qual-level-display');
console.log(`Speichere Quali: emp=${employeeId}, qual=${qualificationId}, level=${newLevel}`);
cell.style.opacity = '0.7';
fetch('/api/qualification_level', { method: 'POST', headers: {'Content-Type': 'application/json', 'Accept': 'application/json'}, body: JSON.stringify({employee_id: employeeId, qualification_id: qualificationId, level: newLevel}) })
.then(response => response.json().then(data => ({ ok: response.ok, status: response.status, data: data })))
.then(result => {
console.log("Quali API Antwort:", result); cell.style.opacity = '1';
if (result.ok && result.data && result.data.status === 'success') {
const info = qualificationLevelsData[newLevel] || qualificationLevelsData[0];
displayDiv.textContent = info.abbr; if(info.effective_text_color) displayDiv.style.color = info.effective_text_color; cell.style.backgroundColor = info.color; cell.title = `${cell.title.split(' - ')[0]} - ${info.desc}`; cell.dataset.currentLevel = newLevel;
select.style.display = 'none'; displayDiv.style.display = 'block'; cell.classList.remove('editing');
cell.style.outline = '2px solid green'; setTimeout(() => cell.style.outline = 'none', 500);
} else { throw new Error(result.data.message || `API Fehler (Status ${result.status})`); }
})
.catch(error => {
console.error('Fehler beim Speichern des Quali-Levels:', error);
select.style.display = 'none'; displayDiv.style.display = 'block'; cell.classList.remove('editing'); select.value = cell.dataset.currentLevel;
cell.style.outline = '2px solid red'; setTimeout(() => cell.style.outline = 'none', 1500);
});
}
});
// Klick außerhalb schließt das aktive Select
document.addEventListener('click', function(event) {
if (!event.target.closest('td.qual-cell.editing')) {
qualiMatrixBody.querySelectorAll('td.qual-cell.editing').forEach(cell => {
cell.classList.remove('editing'); cell.querySelector('.qual-level-display').style.display = 'block'; cell.querySelector('.qual-level-select').style.display = 'none';
});
}
}, true);
} else { console.warn("Schichtplaner JS: Quali-Matrix tbody nicht gefunden."); }
// --- ENDE Modul 2: Quali-Matrix ---
// --- Modul 4: Mitarbeiter Bearbeiten/Löschen ---
const employeeTableBody = document.getElementById('employee-table-body');
const editEmployeeFormTemplate = document.getElementById('editEmployeeFormTemplate');
if (employeeTableBody && editEmployeeFormTemplate) {
console.log("Schichtplaner JS: Initialisiere Mitarbeiter Edit/Delete Logik.");
// Event Listener für Klicks auf Bearbeiten- oder Löschen-Buttons
employeeTableBody.addEventListener('click', function(event) {
const targetButton = event.target.closest('button'); // Finde den geklickten Button
if (!targetButton) return; // Kein Button geklickt
// --- BEARBEITEN ---
if (targetButton.classList.contains('edit-employee-btn')) {
const employeeId = targetButton.dataset.employeeId;
const modalTitle = targetButton.dataset.modalTitle;
console.log(`Bearbeiten geklickt für Mitarbeiter ID: ${employeeId}`);
// 1. Hole Mitarbeiterdaten von der API
fetch(`/api/employee/${employeeId}`)
.then(response => {
if (!response.ok) {
return response.json().then(err => { throw new Error(err.message || `HTTP Fehler ${response.status}`)});
}
return response.json();
})
.then(result => {
if (result.status === 'success' && result.employee) {
const employeeData = result.employee;
console.log("Mitarbeiterdaten geladen:", employeeData);
// 2. Fülle das Bearbeiten-Formular im Modal
// Klone die Vorlage
const formContainerClone = editEmployeeFormTemplate.cloneNode(true);
const editForm = formContainerClone.querySelector('.edit-employee-form');
// Setze die Action-URL dynamisch
editForm.action = `/api/employee/${employeeId}`; // PUT Request wird per JS gemacht
// Fülle die Standardfelder
editForm.querySelector('#emp_name_edit').value = employeeData.name || '';
editForm.querySelector('#emp_type_edit').value = employeeData.employee_type || '';
editForm.querySelector('#emp_entry_date_edit').value = employeeData.entry_date || '';
editForm.querySelector('#emp_birthday_edit').value = employeeData.birthday || '';
// 3. Füge Rollen-Checkboxes hinzu
const rolesContainer = editForm.querySelector('#editEmployeeRolesContainer');
rolesContainer.innerHTML = 'Zugeordnete Rollen:'; // Überschrift wiederherstellen
// Hole ALLE verfügbaren Rollen (müssen wir annehmen oder per API laden - einfacher: aus HTML lesen)
const availableRoles = [];
document.querySelectorAll('.assign-roles-form .form-check-input[name="role_ids"]').forEach(checkbox => {
// Verhindere Duplikate
if (!availableRoles.some(role => role.id == checkbox.value)) {
availableRoles.push({
id: checkbox.value,
name: checkbox.nextElementSibling.textContent.trim() // Hole Namen aus Label
});
}
});
if (availableRoles.length > 0) {
availableRoles.forEach(role => {
const isChecked = employeeData.assigned_role_ids.includes(parseInt(role.id));
const div = document.createElement('div');
div.className = 'form-check form-check-inline';
div.innerHTML = `
${role.name}
`;
rolesContainer.appendChild(div);
});
} else {
rolesContainer.innerHTML += 'Keine Rollen definiert.';
}
// 4. Öffne das Modal mit dem befüllten Formular
if (modal && modalTitle && modalBody) {
modalTitle.textContent = modalTitle || `Mitarbeiter ${employeeId} bearbeiten`;
modalBody.innerHTML = '';
modalBody.appendChild(editForm); // Füge das befüllte Formular ein
modal.style.display = 'block';
// Listener für interne Abbrechen-Buttons hinzufügen
modalBody.querySelectorAll('.close-modal-btn-internal').forEach(btn => {
btn.addEventListener('click', () => { modal.style.display = "none"; });
});
// 5. Event Listener für das Absenden des Bearbeiten-Formulars
editForm.addEventListener('submit', function(submitEvent) {
submitEvent.preventDefault(); // Verhindere Standard-Formular-Submit
handleEditEmployeeSubmit(employeeId, editForm);
});
} else { console.error("Modal-Elemente nicht gefunden!"); }
} else {
throw new Error(result.message || "Fehler beim Laden der Mitarbeiterdaten");
}
})
.catch(error => {
console.error("Fehler beim Abrufen/Vorbereiten der Mitarbeiterdaten:", error);
alert(`Fehler: ${error.message}`);
});
}
// --- LÖSCHEN ---
else if (targetButton.classList.contains('delete-employee-btn')) {
const employeeId = targetButton.dataset.employeeId;
const employeeName = targetButton.dataset.employeeName || 'diesen Mitarbeiter'; // Fallback-Name
// Sicherheitsabfrage
if (confirm(`Möchtest du ${employeeName} wirklich unwiderruflich löschen?`)) {
console.log(`Löschen bestätigt für Mitarbeiter ID: ${employeeId}`);
// API-Aufruf zum Löschen
fetch(`/api/employee/${employeeId}`, {
method: 'DELETE',
headers: { 'Accept': 'application/json' }
})
.then(response => response.json().then(data => ({ ok: response.ok, status: response.status, data: data })))
.then(result => {
console.log("Lösch-API Antwort:", result);
if (result.ok && result.data && result.data.status === 'success') {
console.log("Löschen erfolgreich:", result.data.message);
// Entferne die Zeile aus der Tabelle
const rowToRemove = document.getElementById(`employee-row-${employeeId}`);
if (rowToRemove) {
rowToRemove.style.transition = 'opacity 0.5s ease-out';
rowToRemove.style.opacity = '0';
setTimeout(() => { rowToRemove.remove(); }, 500); // Nach Fade-Out entfernen
}
// Zeige Erfolgsmeldung (optional, da Zeile verschwindet)
// alert(result.data.message);
// Optional: Flash-Nachricht dynamisch hinzufügen (komplexer)
} else {
// Zeige Fehlermeldung von der API
throw new Error(result.data.message || `API Fehler ${result.status}`);
}
})
.catch(error => {
console.error("Fehler beim Löschen des Mitarbeiters:", error);
alert(`Fehler beim Löschen: ${error.message}`);
});
} else {
console.log("Löschen abgebrochen.");
}
}
}); // Ende Klick-Listener
// Funktion zum Verarbeiten des Bearbeiten-Formulars
function handleEditEmployeeSubmit(employeeId, formElement) {
const formData = new FormData(formElement);
const dataToSend = {
name: formData.get('name'),
employee_type: formData.get('employee_type'),
entry_date: formData.get('entry_date'),
birthday: formData.get('birthday'),
assigned_role_ids: formData.getAll('assigned_role_ids') // Holt alle ausgewählten Rollen-IDs
};
console.log("Sende Update für Mitarbeiter:", employeeId, dataToSend);
// Visuelles Feedback im Modal (optional)
const submitButton = formElement.querySelector('button[type="submit"]');
if(submitButton) submitButton.disabled = true; // Button deaktivieren
fetch(`/api/employee/${employeeId}`, {
method: 'PUT',
headers: { 'Content-Type': 'application/json', 'Accept': 'application/json' },
body: JSON.stringify(dataToSend)
})
.then(response => response.json().then(data => ({ ok: response.ok, status: response.status, data: data })))
.then(result => {
console.log("Update API Antwort:", result);
if (result.ok && result.data && result.data.status === 'success') {
console.log("Update erfolgreich:", result.data.message);
if(modal) modal.style.display = "none"; // Modal schließen
// Seite neu laden, um Änderungen in der Tabelle sicher anzuzeigen
// Alternativ: Zeile dynamisch updaten (komplexer)
window.location.reload();
// Zeige Flash-Nachricht (wird nach Reload angezeigt)
} else {
throw new Error(result.data.message || `API Fehler ${result.status}`);
}
})
.catch(error => {
console.error("Fehler beim Mitarbeiter-Update:", error);
alert(`Fehler beim Speichern: ${error.message}`);
if(submitButton) submitButton.disabled = false; // Button wieder aktivieren
});
}
} else {
console.warn("Schichtplaner JS: Mitarbeiter Tabelle Body (tbody#employee-table-body) oder Edit-Vorlage nicht gefunden.");
}
// --- ENDE Modul 4: Mitarbeiter Edit/Delete ---
// ... (Modal Steuerung Modul bleibt unverändert) ...
const qualificationTableBody = document.getElementById('qualification-table-body');
const editQualificationFormTemplate = document.getElementById('editQualificationFormTemplate');
if (qualificationTableBody && editQualificationFormTemplate) {
console.log("Schichtplaner JS: Initialisiere Qualifikationen Edit/Delete Logik.");
qualificationTableBody.addEventListener('click', function(event) {
const targetButton = event.target.closest('button');
if (!targetButton) return;
// --- BEARBEITEN ---
if (targetButton.classList.contains('edit-qualification-btn')) {
const qualificationId = targetButton.dataset.qualificationId;
const modalTitle = targetButton.dataset.modalTitle;
const targetTemplateId = targetButton.dataset.modalTarget; // Hole auch die Template ID
console.log(`Bearbeiten geklickt für Quali ID: ${qualificationId}`);
fetch(`/api/qualification/${qualificationId}`)
.then(response => response.ok ? response.json() : response.json().then(err => Promise.reject(err)))
.then(result => {
if (result.status === 'success' && result.qualification) {
const qData = result.qualification;
console.log("Quali Daten geladen:", qData);
// Öffne das allgemeine Modal mit der Quali-Edit-Vorlage
// Wichtig: openModalGeneric verwenden!
openModalGeneric('commonModal', modalTitle || `Qualifikation bearbeiten`, targetTemplateId, 'form');
// Finde das Formular im JETZT SICHTBAREN #commonModal Body
const visibleEditForm = commonModalBody.querySelector('.edit-qualification-form');
if (visibleEditForm) { // Stelle sicher, dass das Formular gefunden wurde
// Standardfelder füllen
const nameInput = visibleEditForm.querySelector('#qual_name_edit');
const categoryInput = visibleEditForm.querySelector('#qual_category_edit');
const descriptionInput = visibleEditForm.querySelector('#qual_description_edit');
const profileCheckbox = visibleEditForm.querySelector('#qual_has_profile_edit'); // Checkbox finden
if(nameInput) nameInput.value = qData.name || '';
if(categoryInput) categoryInput.value = qData.category || '';
if(descriptionInput) descriptionInput.value = qData.description || '';
// === Checkbox HIER setzen ===
if (profileCheckbox) {
profileCheckbox.checked = qData.has_profile; // Setze Checkbox-Status basierend auf API-Daten
} else {
console.warn("Checkbox 'has_profile' nicht im Quali-Edit-Formular gefunden.");
}
// ============================
// Submit Listener neu binden (wichtig!)
const newForm = visibleEditForm.cloneNode(true);
visibleEditForm.parentNode.replaceChild(newForm, visibleEditForm);
newForm.addEventListener('submit', function(submitEvent) {
submitEvent.preventDefault();
handleEditQualificationSubmit(qualificationId, newForm);
});
} else {
console.error("Konnte .edit-qualification-form im Modal nicht finden nach dem Öffnen.");
}
} else { throw new Error(result.message || "Fehler beim Laden der Quali-Daten"); }
})
.catch(error => { console.error("Fehler:", error); alert(`Fehler: ${error.message}`); });
}
// --- LÖSCHEN --- (Rest bleibt gleich)
else if (targetButton.classList.contains('delete-qualification-btn')) {
// ... (Lösch-Code unverändert) ...
}
// --- LÖSCHEN ---
else if (targetButton.classList.contains('delete-qualification-btn')) {
const qualificationId = targetButton.dataset.qualificationId;
const qualificationName = targetButton.dataset.qualificationName || 'diese Qualifikation';
if (confirm(`Möchtest du die Qualifikation '${qualificationName}' wirklich löschen? Sie darf nicht mehr verwendet werden!`)) {
console.log(`Löschen bestätigt für Quali ID: ${qualificationId}`);
fetch(`/api/qualification/${qualificationId}`, { method: 'DELETE', headers: { 'Accept': 'application/json' } })
.then(response => response.json().then(data => ({ ok: response.ok, status: response.status, data: data })))
.then(result => {
console.log("Lösch-API Antwort:", result);
if (result.ok && result.data && result.data.status === 'success') {
console.log("Löschen erfolgreich:", result.data.message);
const rowToRemove = document.getElementById(`qualification-row-${qualificationId}`);
if (rowToRemove) {
rowToRemove.style.transition = 'opacity 0.5s ease-out';
rowToRemove.style.opacity = '0';
setTimeout(() => { rowToRemove.remove(); }, 500);
}
} else { throw new Error(result.data.message || `API Fehler ${result.status}`); }
})
.catch(error => { console.error("Fehler:", error); alert(`Fehler beim Löschen: ${error.message}`); });
} else { console.log("Löschen abgebrochen."); }
}
}); // Ende Klick-Listener
// Funktion zum Verarbeiten des Bearbeiten-Formulars
function handleEditQualificationSubmit(qualificationId, formElement) {
const formData = new FormData(formElement);
const dataToSend = { // JSON erstellen
name: formData.get('name'),
category: formData.get('category'),
description: formData.get('description'),
// === NEU: Checkbox-Wert holen ===
has_profile: formData.has('has_profile') // true wenn angehakt, false wenn nicht
// =============================
};
console.log("Sende Update für Quali:", qualificationId, dataToSend);
const submitButton = formElement.querySelector('button[type="submit"]');
if(submitButton) submitButton.disabled = true;
fetch(`/api/qualification/${qualificationId}`, {
method: 'PUT',
headers: { 'Content-Type': 'application/json', 'Accept': 'application/json' },
body: JSON.stringify(dataToSend)
})
.then(response => response.json().then(data => ({ ok: response.ok, status: response.status, data: data })))
.then(result => {
console.log("Update API Antwort:", result);
if (result.ok && result.data && result.data.status === 'success') {
console.log("Update erfolgreich:", result.data.message);
// Schließe das #commonModal
if(commonModalElement) commonModalElement.style.display = "none";
// Lade die Seite neu, um Änderungen in der Tabelle zu sehen
window.location.reload();
} else { throw new Error(result.data.message || `API Fehler ${result.status}`); }
})
.catch(error => {
console.error("Fehler beim Quali-Update:", error);
alert(`Fehler beim Speichern: ${error.message}`);
if(submitButton) submitButton.disabled = false;
});
} // Ende handleEditQualificationSubmit
// --- Modul 8: Maschinen & Gruppen Bearbeiten/Löschen ---
const mgmtContainer = document.getElementById('groups-and-machines-list');
const editGroupFormTemplate = document.getElementById('editGroupFormTemplate');
const editMachineFormTemplate = document.getElementById('editMachineFormTemplate');
// Stelle sicher, dass alle Elemente auf der SEITE vorhanden sind UND das Modal existiert
if (mgmtContainer && editGroupFormTemplate && editMachineFormTemplate && modal) {
console.log("Schichtplaner JS: Initialisiere Maschinen/Gruppen Edit/Delete Logik.");
// === Event Listener für Klicks im Verwaltungsbereich ===
mgmtContainer.addEventListener('click', function(event) {
const targetButton = event.target.closest('button'); // Finde den geklickten Button
if (!targetButton) return; // Ignoriere Klicks, die nicht auf Buttons sind
// --- GRUPPE BEARBEITEN ---
if (targetButton.classList.contains('edit-group-btn')) {
event.preventDefault(); // Verhindere Standardverhalten
const groupId = targetButton.dataset.groupId;
const modalTitle = targetButton.dataset.modalTitle;
console.log(`Gruppe Bearbeiten geklickt für ID: ${groupId}`);
// API-Call zum Holen der Gruppendaten
fetch(`/api/group/${groupId}`)
.then(response => response.ok ? response.json() : response.json().then(err => Promise.reject(err)))
.then(result => {
if (result.status === 'success' && result.group) {
const groupData = result.group;
console.log("Gruppendaten geladen:", groupData);
// Öffne das Modal mit der GRUPPEN-Bearbeiten-Vorlage
openModalGeneric('commonModal', modalTitle || `Gruppe bearbeiten`, 'editGroupFormTemplate', 'form');
// Finde das Formular im JETZT SICHTBAREN Modal Body
const visibleEditForm = modalBody.querySelector('.edit-group-form');
if (visibleEditForm) {
// Fülle die Formularfelder mit den Daten
const nameInput = visibleEditForm.querySelector('input[name="name"]');
const abbrInput = visibleEditForm.querySelector('input[name="abbreviation"]');
const colorInput = visibleEditForm.querySelector('input[name="color"]');
if(nameInput) nameInput.value = groupData.name || '';
if(abbrInput) abbrInput.value = groupData.abbreviation || ''; // Abkürzung füllen
if(colorInput) colorInput.value = groupData.color || '#D0D0D0'; // Farbe füllen
// WICHTIG: Alten Submit-Listener entfernen (durch Klonen) und neuen hinzufügen
const newForm = visibleEditForm.cloneNode(true);
visibleEditForm.parentNode.replaceChild(newForm, visibleEditForm);
newForm.addEventListener('submit', (e) => {
e.preventDefault();
handleEditGroupSubmit(groupId, newForm); // Ruft den Submit Handler auf
});
} else { console.error("Konnte .edit-group-form im Modal nicht finden."); }
} else { throw new Error(result.message || "Fehler beim Laden der Gruppendaten"); }
})
.catch(error => { console.error("Fehler:", error); alert(`Fehler: ${error.message}`); });
}
// --- GRUPPE LÖSCHEN ---
else if (targetButton.classList.contains('delete-group-btn')) {
event.preventDefault();
const groupId = targetButton.dataset.groupId;
const groupName = targetButton.dataset.groupName || 'diese Gruppe';
if (confirm(`Gruppe '${groupName}' wirklich löschen? Zugeordnete Maschinen, Personalbedarf und Quali-Anforderungen gehen verloren!`)) {
console.log(`Löschen bestätigt für Gruppe ID: ${groupId}`);
fetch(`/api/group/${groupId}`, { method: 'DELETE', headers: { 'Accept': 'application/json' } })
.then(response => response.json().then(data => ({ ok: response.ok, data: data })))
.then(result => {
if (result.ok && result.data.status === 'success') {
console.log("Gruppen-Löschen erfolgreich:", result.data.message);
const cardToRemove = document.getElementById(`group-card-${groupId}`);
if (cardToRemove) { cardToRemove.remove(); } // Entferne ganze Karte
// Optional: Flash-Nachricht hinzufügen
} else { throw new Error(result.data.message || 'Fehler beim Löschen der Gruppe'); }
})
.catch(error => { console.error("Fehler beim Gruppen-Löschen:", error); alert(`Fehler: ${error.message}`); });
} else { console.log("Löschen der Gruppe abgebrochen."); }
}
// --- MASCHINE BEARBEITEN ---
else if (targetButton.classList.contains('edit-machine-btn')) {
event.preventDefault();
const machineId = targetButton.dataset.machineId;
const modalTitle = targetButton.dataset.modalTitle;
console.log(`Maschine Bearbeiten geklickt für ID: ${machineId}`);
fetch(`/api/machine/${machineId}`) // API holt Maschine UND Gruppenliste
.then(response => response.ok ? response.json() : response.json().then(err => Promise.reject(err)))
.then(result => {
if (result.status === 'success' && result.machine && result.groups !== undefined) {
const machineData = result.machine;
const groupOptions = result.groups;
// Öffne das Modal mit der MASCHINEN-Bearbeiten-Vorlage
openModalGeneric('commonModal', modalTitle || 'Maschine bearbeiten', 'editMachineFormTemplate', 'form');
// Finde das Formular im JETZT SICHTBAREN Modal Body
const visibleEditForm = modalBody.querySelector('.edit-machine-form');
if (visibleEditForm) {
const nameInput = visibleEditForm.querySelector('input[name="name"]');
const groupSelect = visibleEditForm.querySelector('select[name="group_id"]');
// Dynamische IDs setzen (optional aber besser für Labels)
if(nameInput) nameInput.id = `machine_name_edit_${machineId}`;
if(groupSelect) groupSelect.id = `machine_group_edit_${machineId}`;
const nameLabel = nameInput ? nameInput.previousElementSibling : null;
const groupLabel = groupSelect ? groupSelect.previousElementSibling : null;
if (nameLabel && nameInput) nameLabel.setAttribute('for', nameInput.id);
if (groupLabel && groupSelect) groupLabel.setAttribute('for', groupSelect.id);
// Felder füllen
if (nameInput) nameInput.value = machineData.name || '';
if (groupSelect) {
// Alte Optionen löschen, neue hinzufügen
while (groupSelect.options.length > 1) { groupSelect.remove(1); }
groupOptions.forEach(group => { const option = document.createElement('option'); option.value = group.id; option.textContent = group.name; groupSelect.appendChild(option); });
groupSelect.value = machineData.group_id || '0'; // Wert setzen
}
// Alten Listener entfernen, neuen hinzufügen
const newForm = visibleEditForm.cloneNode(true);
visibleEditForm.parentNode.replaceChild(newForm, visibleEditForm);
newForm.addEventListener('submit', (e) => { e.preventDefault(); handleEditMachineSubmit(machineId, newForm); });
} else { console.error("Konnte .edit-machine-form im Modal nicht finden."); }
} else { throw new Error(result.message || "Fehler Laden Maschinendaten/Gruppen"); }
})
.catch(error => { console.error("Fehler:", error); alert(`Fehler: ${error.message}`); });
}
// --- MASCHINE LÖSCHEN ---
else if (targetButton.classList.contains('delete-machine-btn')) {
event.preventDefault();
const machineId = targetButton.dataset.machineId;
const machineName = targetButton.dataset.machineName || 'diese Maschine';
if (confirm(`Maschine '${machineName}' wirklich löschen?`)) {
console.log(`Löschen bestätigt für Maschine ID: ${machineId}`);
fetch(`/api/machine/${machineId}`, { method: 'DELETE', headers: { 'Accept': 'application/json' } })
.then(response => response.json().then(data => ({ ok: response.ok, data: data })))
.then(result => {
if (result.ok && result.data.status === 'success') {
console.log("Maschinen-Löschen erfolgreich:", result.data.message);
const rowToRemove = document.getElementById(`machine-row-${machineId}`);
if (rowToRemove) {
const list = rowToRemove.closest('ul');
rowToRemove.remove();
// Optional: Platzhalter wieder einfügen, wenn Liste leer ist
if (list && !list.querySelector('li')) { const placeholder = document.createElement('li'); placeholder.className = 'list-group-item text-muted small ps-0 py-1 no-machines-placeholder'; placeholder.textContent = 'Keine Maschinen (mehr) in dieser Gruppe.'; list.appendChild(placeholder); }
}
} else { throw new Error(result.data.message || 'Fehler beim Löschen der Maschine'); }
})
.catch(error => { console.error("Fehler beim Maschinen-Löschen:", error); alert(`Fehler: ${error.message}`); });
} else { console.log("Löschen der Maschine abgebrochen."); }
}
}); // Ende Klick-Listener für mgmtContainer
// --- Submit-Handler für Gruppen-Bearbeitung ---
function handleEditGroupSubmit(groupId, formElement) {
const formData = new FormData(formElement);
const dataToSend = {
name: formData.get('name'),
abbreviation: formData.get('abbreviation'), // Holt Abkürzung
color: formData.get('color') // Holt Farbe
};
console.log("Sende Update für Gruppe:", groupId, dataToSend);
const submitButton = formElement.querySelector('button[type="submit"]');
if(submitButton) submitButton.disabled = true;
fetch(`/api/group/${groupId}`, { method: 'PUT', headers: {'Content-Type': 'application/json'}, body: JSON.stringify(dataToSend) })
.then(response => response.ok ? response.json() : response.json().then(err => Promise.reject(err)))
.then(result => { if(result.status === 'success') { if(modal) modal.style.display = 'none'; window.location.reload(); } else { throw new Error(result.message); } })
.catch(error => { alert(`Fehler: ${error.message}`); if(submitButton) submitButton.disabled = false; });
} // Ende handleEditGroupSubmit
// --- Submit-Handler für Maschinen-Bearbeitung ---
function handleEditMachineSubmit(machineId, formElement) {
const formData = new FormData(formElement);
const groupIdValue = formData.get('group_id');
const dataToSend = { name: formData.get('name'), group_id: (groupIdValue && groupIdValue !== '0') ? groupIdValue : null };
console.log("Sende Update für Maschine:", machineId, dataToSend);
const submitButton = formElement.querySelector('button[type="submit"]');
if(submitButton) submitButton.disabled = true;
fetch(`/api/machine/${machineId}`, { method: 'PUT', headers: {'Content-Type': 'application/json'}, body: JSON.stringify(dataToSend) })
.then(response => response.ok ? response.json() : response.json().then(err => Promise.reject(err)))
.then(result => { if(result.status === 'success') { if(modal) modal.style.display = 'none'; window.location.reload(); } else { throw new Error(result.message); } })
.catch(error => { alert(`Fehler: ${error.message}`); if(submitButton) submitButton.disabled = false; });
} // Ende handleEditMachineSubmit
} else {
// Logge, welche Elemente fehlen könnten
console.warn("Schichtplaner JS: Container für Maschinen/Gruppen oder Edit-Vorlagen nicht gefunden.", {mgmtContainer, editGroupFormTemplate, editMachineFormTemplate});
}
// --- ENDE Modul 8: Maschinen & Gruppen ---
// --- Neuer Event-Listener für Interaktionen im Schichtarten-Einstellungs-Modal ---
if (settingsModalElement) { // Prüfe ob das Einstellungs-Modal existiert
console.log("Schichtplaner JS: Initialisiere Edit/Delete Listener für Schichtarten im Einstellungen-Modal.");
// Nutze Event Delegation auf dem Modal-Element selbst
settingsModalElement.addEventListener('click', function(event) {
const targetButton = event.target.closest('button'); // Finde den geklickten Button
if (!targetButton) return; // Ignoriere Klicks, die nicht auf Buttons sind
// --- Schichtart Bearbeiten ---
if (targetButton.classList.contains('edit-shift-type-btn')) {
event.preventDefault(); // Wichtig, falls Button in Formular ist
const shiftTypeId = targetButton.dataset.shiftTypeId;
const modalTitleText = targetButton.dataset.modalTitle; // Titel für das *nächste* (common) Modal
const targetTemplateId = targetButton.dataset.modalTarget; // ID der Edit-Vorlage im HTML
console.log(`Bearbeiten geklickt für Schichtart ID: ${shiftTypeId}`);
// API Call zum Holen der Daten
fetch(`/api/shift_type/${shiftTypeId}`)
.then(response => response.ok ? response.json() : response.json().then(err => Promise.reject(err)))
.then(result => {
if (result.status === 'success' && result.shift_type) {
const stData = result.shift_type;
// Öffne das ALLGEMEINE Modal (#commonModal) mit der Edit-Vorlage für Schichtarten
// Wichtig: targetTemplateId muss die ID der *versteckten* Vorlage sein
openModalGeneric('commonModal', modalTitleText || 'Schichtart bearbeiten', targetTemplateId, 'form');
// Finde das Formular im JETZT geöffneten #commonModal
const visibleEditForm = commonModalBody.querySelector('.edit-shift-type-form');
if(visibleEditForm) {
// Formularfelder füllen (verwende die IDs aus der Vorlage #editShiftTypeFormTemplateModal)
const nameInput = visibleEditForm.querySelector('#st_name_edit_modal');
const abbrInput = visibleEditForm.querySelector('#st_abbr_edit_modal');
const colorInput = visibleEditForm.querySelector('#st_color_edit_modal');
const textColorInput = visibleEditForm.querySelector('#st_textcolor_edit_modal');
const isAbsenceInput = visibleEditForm.querySelector('#st_is_absence_edit_modal');
const hidePrintInput = visibleEditForm.querySelector('#st_hide_on_print_edit_modal');
if(nameInput) nameInput.value = stData.name || '';
if(abbrInput) abbrInput.value = stData.abbreviation || '';
if(colorInput) colorInput.value = stData.color || '#FFFFFF';
if(textColorInput) textColorInput.value = stData.text_color || '#000000';
if(isAbsenceInput) isAbsenceInput.checked = stData.is_absence;
if(hidePrintInput) hidePrintInput.checked = stData.hide_on_print;
// WICHTIG: Submit Listener neu binden (verhindert Mehrfachbindung)
const newForm = visibleEditForm.cloneNode(true);
visibleEditForm.parentNode.replaceChild(newForm, visibleEditForm);
newForm.addEventListener('submit', (e) => {
e.preventDefault();
// Rufe den Submit Handler auf (siehe unten)
handleEditShiftTypeSubmit(shiftTypeId, newForm);
});
} else { console.error("Konnte .edit-shift-type-form im #commonModal nicht finden nach dem Öffnen."); }
} else { throw new Error(result.message || "Fehler Laden Schichtartdaten"); }
})
.catch(error => { console.error("Fehler:", error); alert(`Fehler: ${error.message}`); });
}
// --- Schichtart Löschen ---
else if (targetButton.classList.contains('delete-shift-type-btn')) {
event.preventDefault();
const shiftTypeId = targetButton.dataset.shiftTypeId;
const shiftTypeName = targetButton.dataset.shiftTypeName || 'diese Schichtart';
if (confirm(`Schichtart '${shiftTypeName}' wirklich löschen?`)) {
console.log(`Löschen bestätigt für Schichtart ID: ${shiftTypeId}`);
fetch(`/api/shift_type/${shiftTypeId}`, { method: 'DELETE', headers: { 'Accept': 'application/json' } })
.then(response => response.json().then(data => ({ ok: response.ok, status: response.status, data: data })))
.then(result => {
if (result.ok && result.data && result.data.status === 'success') {
// Entferne Zeile aus der Tabelle im Einstellungs-Modal
const rowToRemove = settingsModalElement.querySelector(`#shift-type-row-modal-${shiftTypeId}`);
if (rowToRemove) {
rowToRemove.remove();
console.log(`Zeile shift-type-row-modal-${shiftTypeId} entfernt.`);
} else {
console.warn(`Zeile shift-type-row-modal-${shiftTypeId} nicht im Modal gefunden.`);
}
} else { throw new Error(result.data.message || `API Fehler ${result.status}`); }
})
.catch(error => { console.error("Fehler:", error); alert(`Fehler beim Löschen: ${error.message}`); });
}
}
// --- HIER KEINE ROLLE MEHR ---
}); // Ende Klick-Listener für Einstellungs-Modal
} else {
console.warn("Schichtplaner JS: Einstellungs-Modal (#shiftTypeSettingsModal) nicht gefunden, kann keine Listener binden.");
}
// --- Submit Handler MÜSSEN außerhalb des if-Blocks definiert sein, ---
// damit sie auch gefunden werden, wenn das Modal geschlossen ist.
// Funktion zum Verarbeiten des Schichtart-Bearbeiten-Formulars
function handleEditShiftTypeSubmit(shiftTypeId, formElement) {
const formData = new FormData(formElement);
const dataToSend = {
name: formData.get('name'),
abbreviation: formData.get('abbreviation'),
color: formData.get('color'),
text_color: formData.get('text_color'),
is_absence: formData.has('is_absence'), // .has prüft ob Checkbox gesendet wurde
hide_on_print: formData.has('hide_on_print')
};
console.log("Sende Update für Schichtart:", shiftTypeId, dataToSend);
const submitButton = formElement.querySelector('button[type="submit"]');
if(submitButton) submitButton.disabled = true;
fetch(`/api/shift_type/${shiftTypeId}`, { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(dataToSend) })
.then(response => response.json().then(data => ({ ok: response.ok, data: data })))
.then(result => {
if (result.ok && result.data.status === 'success') {
// Schließe das Bearbeiten-Modal (#commonModal)
if(commonModalElement) commonModalElement.style.display = "none";
// Gib Hinweis statt Reload
alert("Schichtart erfolgreich gespeichert.\n\nDie Änderungen werden im Einstellungs-Modal erst nach dem erneuten Öffnen sichtbar.");
// Alternativ: Versuche Tabelle im Einstellungs-Modal dynamisch zu aktualisieren (komplexer)
} else { throw new Error(result.data.message || `API Fehler`); }
})
.catch(error => { alert(`Fehler beim Speichern: ${error.message}`); if(submitButton) submitButton.disabled = false; });
}
}); // Ende DOMContentLoaded
Please help me!