(function () { const dialog = document.getElementById("completeDialog"); const dialogForm = document.getElementById("completeDialogForm"); const dialogChoice = document.getElementById("completeDialogChoice"); const dialogText = document.getElementById("completeDialogText"); const dialogChoices = document.getElementById("completeDialogChoices"); const closeButton = document.getElementById("completeDialogClose"); const quickTaskDialog = document.getElementById("quickTaskDialog"); const quickTaskOpen = document.getElementById("quickTaskOpen"); const quickTaskClose = document.getElementById("quickTaskClose"); const quickWinsSubmit = document.getElementById("quickWinsSubmit"); const quickWinInputs = document.querySelectorAll("[data-quick-win-input]"); const quickWinCustomToggle = document.querySelector("[data-quick-win-custom-toggle]"); const quickWinCustomFields = document.getElementById("quickWinCustomFields"); const quickWinTitle = document.getElementById("quick-title"); const quickWinEffort = document.getElementById("quick-effort"); const currentUserId = document.body.dataset.currentUserId; const currentUserName = document.body.dataset.currentUserName; const quickWinSortList = document.querySelector("[data-quick-win-sort-list]"); const quickWinSortToken = document.getElementById("quickWinSortToken"); const quickWinSortSave = document.getElementById("quickWinSortSave"); const quickWinToggleButtons = document.querySelectorAll("[data-quick-win-toggle]"); let draggedQuickWin = null; let quickWinSortDirty = false; function buildCompletionOptions(button) { const options = []; const assignedPairs = [ [button.dataset.assignedPrimaryId, button.dataset.assignedPrimaryName], [button.dataset.assignedSecondaryId, button.dataset.assignedSecondaryName], ]; assignedPairs.forEach(([id, label]) => { if (id && label && !options.some((option) => option.value === id)) { options.push({ value: id, label }); } }); if (currentUserId && currentUserName && !options.some((option) => option.value === currentUserId)) { options.push({ value: currentUserId, label: "Ich" }); } return options; } document.querySelectorAll("[data-complete-action]").forEach((button) => { button.addEventListener("click", () => { if (!dialog || !dialogForm || !dialogChoice || !dialogText || !dialogChoices) { return; } dialogForm.action = button.dataset.completeAction; dialogText.textContent = `Die Aufgabe "${button.dataset.completeTitle}" war ${button.dataset.completeAssigned} zugewiesen. Wer hat sie erledigt?`; dialogChoices.innerHTML = ""; buildCompletionOptions(button).forEach((option, index) => { const choiceButton = document.createElement("button"); choiceButton.type = "button"; choiceButton.className = index === 0 ? "button button--secondary" : "button"; choiceButton.dataset.completeChoice = option.value; choiceButton.textContent = option.label; choiceButton.addEventListener("click", () => { dialogChoice.value = option.value; dialog.close(); dialogForm.submit(); }); dialogChoices.appendChild(choiceButton); }); dialog.showModal(); }); }); if (closeButton && dialog) { closeButton.addEventListener("click", () => dialog.close()); } if (quickTaskOpen && quickTaskDialog) { quickTaskOpen.addEventListener("click", () => quickTaskDialog.showModal()); } if (quickTaskClose && quickTaskDialog) { quickTaskClose.addEventListener("click", () => quickTaskDialog.close()); } function updateQuickWinsState() { const selectedPresetCount = [...quickWinInputs].filter((input) => input.checked).length; const customSelected = quickWinCustomToggle?.checked === true; const totalCount = selectedPresetCount + (customSelected ? 1 : 0); if (quickWinCustomFields) { quickWinCustomFields.hidden = !customSelected; } if (quickWinTitle) { quickWinTitle.disabled = !customSelected; quickWinTitle.required = customSelected; } if (quickWinEffort) { quickWinEffort.disabled = !customSelected; quickWinEffort.required = customSelected; } if (quickWinsSubmit) { quickWinsSubmit.disabled = totalCount === 0; quickWinsSubmit.textContent = totalCount <= 1 ? "Quick-Win sichern" : "Quick Wins sichern"; } } quickWinInputs.forEach((input) => input.addEventListener("change", updateQuickWinsState)); if (quickWinCustomToggle) { quickWinCustomToggle.addEventListener("change", updateQuickWinsState); } updateQuickWinsState(); if (quickTaskDialog) { quickTaskDialog.addEventListener("close", () => { const quickWinsForm = document.getElementById("quickWinsForm"); if (!quickWinsForm) { return; } quickWinsForm.reset(); updateQuickWinsState(); }); } async function persistQuickWinSort() { if (!quickWinSortList || !quickWinSortToken) { return; } const ids = [...quickWinSortList.querySelectorAll("[data-quick-win-sort-item]")] .map((item) => item.dataset.quickWinSortItem) .filter(Boolean); await fetch("/settings/quick-wins/reorder", { method: "POST", headers: { "Content-Type": "application/json", "X-CSRFToken": quickWinSortToken.value, }, body: JSON.stringify({ ids }), }); } function setQuickWinSortDirty(isDirty) { quickWinSortDirty = isDirty; if (quickWinSortSave) { quickWinSortSave.disabled = !isDirty; } } if (quickWinSortList) { setQuickWinSortDirty(false); quickWinSortList.querySelectorAll("[data-quick-win-sort-item]").forEach((item) => { item.addEventListener("dragstart", () => { draggedQuickWin = item; item.classList.add("is-dragging"); }); item.addEventListener("dragend", () => { item.classList.remove("is-dragging"); draggedQuickWin = null; }); item.addEventListener("dragover", (event) => { event.preventDefault(); }); item.addEventListener("drop", async (event) => { event.preventDefault(); if (!draggedQuickWin || draggedQuickWin === item) { return; } const items = [...quickWinSortList.querySelectorAll("[data-quick-win-sort-item]")]; const draggedIndex = items.indexOf(draggedQuickWin); const targetIndex = items.indexOf(item); if (draggedIndex < targetIndex) { item.after(draggedQuickWin); } else { item.before(draggedQuickWin); } setQuickWinSortDirty(true); }); }); } if (quickWinSortSave) { quickWinSortSave.addEventListener("click", async () => { if (!quickWinSortDirty) { return; } try { await persistQuickWinSort(); setQuickWinSortDirty(false); } catch (error) { console.error("Quick-Win-Sortierung konnte nicht gespeichert werden", error); } }); } quickWinToggleButtons.forEach((button) => { button.addEventListener("click", () => { const targetId = button.dataset.target; if (!targetId) { return; } const target = document.getElementById(targetId); if (!target) { return; } const willOpen = target.hidden; document.querySelectorAll("[data-quick-win-edit]").forEach((editForm) => { editForm.hidden = true; }); quickWinToggleButtons.forEach((toggle) => { toggle.setAttribute("aria-expanded", "false"); toggle.textContent = "Bearbeiten"; }); if (willOpen) { target.hidden = false; button.setAttribute("aria-expanded", "true"); button.textContent = "Schließen"; } }); }); const pushButton = document.getElementById("pushToggle"); const pushHint = document.getElementById("pushHint"); const vapidKey = document.body.dataset.pushKey; const isIos = /iphone|ipad|ipod/i.test(window.navigator.userAgent); const isStandalone = window.matchMedia("(display-mode: standalone)").matches || window.navigator.standalone === true; function urlBase64ToUint8Array(base64String) { const padding = "=".repeat((4 - (base64String.length % 4)) % 4); const base64 = (base64String + padding).replace(/-/g, "+").replace(/_/g, "/"); const raw = atob(base64); return Uint8Array.from([...raw].map((char) => char.charCodeAt(0))); } async function postJSON(url, payload) { const response = await fetch(url, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(payload), }); return response.json(); } async function togglePush() { if (!("serviceWorker" in navigator) || !("PushManager" in window) || !pushButton) { return; } const registration = await navigator.serviceWorker.register("/service-worker.js"); const existing = await registration.pushManager.getSubscription(); if (existing) { await postJSON("/settings/push/unsubscribe", { endpoint: existing.endpoint }); await existing.unsubscribe(); pushButton.dataset.subscribed = "0"; pushButton.textContent = "Push aktivieren"; return; } const permission = await Notification.requestPermission(); if (permission !== "granted") { return; } const subscription = await registration.pushManager.subscribe({ userVisibleOnly: true, applicationServerKey: urlBase64ToUint8Array(vapidKey), }); await postJSON("/settings/push/subscribe", subscription.toJSON()); pushButton.dataset.subscribed = "1"; pushButton.textContent = "Push deaktivieren"; } if ("serviceWorker" in navigator) { navigator.serviceWorker.register("/service-worker.js").catch(() => {}); } if (pushButton && (!("serviceWorker" in navigator) || !("PushManager" in window))) { pushButton.disabled = true; if (pushHint) { pushHint.textContent = "Dieser Browser unterstützt Web-Push hier aktuell nicht."; } } else if (pushButton && isIos && !isStandalone) { pushButton.disabled = true; if (pushHint) { pushHint.textContent = "Auf iPhone/iPad funktioniert Web-Push erst nach „Zum Home-Bildschirm“ und Öffnen als Web-App."; } } else if (pushButton && vapidKey) { pushButton.addEventListener("click", () => { togglePush().catch((error) => console.error("Push toggle failed", error)); }); } })();