let deferredInstallPrompt = null; function isStandalone() { return window.matchMedia("(display-mode: standalone)").matches || window.navigator.standalone === true; } export function wirePwaInstall({ sectionId = "pwaInstallSection", buttonId = "installPwa" } = {}) { const section = document.getElementById(sectionId); const button = document.getElementById(buttonId); if (!section || !button) return; const hide = () => { section.hidden = true; }; if (isStandalone()) { hide(); return; } hide(); window.addEventListener("beforeinstallprompt", (e) => { e.preventDefault(); deferredInstallPrompt = e; section.hidden = false; }); window.addEventListener("appinstalled", () => { deferredInstallPrompt = null; hide(); }); button.addEventListener("click", async () => { if (!deferredInstallPrompt) return; deferredInstallPrompt.prompt(); await deferredInstallPrompt.userChoice; deferredInstallPrompt = null; hide(); }); } export async function registerPwa() { if (!("serviceWorker" in navigator)) return; try { const reg = await navigator.serviceWorker.register("/sw.js"); if ("sync" in ServiceWorkerRegistration.prototype) { navigator.serviceWorker.ready.then((readyReg) => { readyReg.sync?.register("sync-logs").catch(() => {}); }); } return reg; } catch (e) { console.error("SW registration failed:", e); } } export async function subscribePush(vapidPublicKey) { if (!("PushManager" in window)) throw new Error("Push nicht unterstützt"); const reg = await navigator.serviceWorker.ready; let sub = await reg.pushManager.getSubscription(); if (!sub) { sub = await reg.pushManager.subscribe({ userVisibleOnly: true, applicationServerKey: urlBase64ToUint8Array(vapidPublicKey), }); } return sub.toJSON(); } 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((c) => c.charCodeAt(0))); }