// async function registerPush() { // try { // console.log("Registering for push notifications"); // if (!('serviceWorker' in navigator)) { // console.error("ServiceWorker not supported"); // return; // } // const permission = await Notification.requestPermission(); // console.log("Permission:", permission); // if (permission !== 'granted') { // console.warn("Notification permission denied"); // return; // } // const registration = await navigator.serviceWorker.register('/sw.js'); // console.log("SW registered:", registration); // // const subscription = await registration.pushManager.subscribe({ // // userVisibleOnly: true, // // applicationServerKey: vapidKey // // }); // const subscription = await registration.pushManager.subscribe({ // userVisibleOnly: true, // applicationServerKey: urlBase64ToUint8Array(vapidKey), // }); // console.log('VAPID key:', vapidKey); // console.log("Subscription created:", subscription); // const res = await fetch('/push/subscribe', { // method: 'POST', // headers: { // 'Content-Type': 'application/json', // 'X-CSRF-TOKEN': csrfToken // }, // body: JSON.stringify(subscription) // }); // console.log("Server response:", await res.text()); // alert("Push enabled ✅"); // } catch (e) { // console.error("Push registration failed ❌", e); // } // } async function registerPush() { try { console.log("Registering for push notifications"); if (!('serviceWorker' in navigator)) { console.error("ServiceWorker not supported"); return; } const permission = await Notification.requestPermission(); if (permission !== 'granted') { console.warn("Notification permission denied"); return; } const registration = await navigator.serviceWorker.register('/sw.js'); // ✅ GET first let subscription = await registration.pushManager.getSubscription(); // ✅ CREATE only if not exists if (!subscription) { subscription = await registration.pushManager.subscribe({ userVisibleOnly: true, applicationServerKey: urlBase64ToUint8Array(vapidKey), }); console.log("New subscription created"); } else { console.log("Existing subscription reused"); } // 🔥 ALWAYS send to backend await fetch('/push/subscribe', { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-CSRF-TOKEN': csrfToken }, body: JSON.stringify(subscription) }); alert("Push enabled ✅"); } catch (e) { console.error("Push registration failed ❌", e); } } function urlBase64ToUint8Array(base64String) { const padding = '='.repeat((4 - base64String.length % 4) % 4); const base64 = (base64String + padding) .replace(/-/g, '+') .replace(/_/g, '/'); const rawData = window.atob(base64); const outputArray = new Uint8Array(rawData.length); for (let i = 0; i < rawData.length; ++i) { outputArray[i] = rawData.charCodeAt(i); } return outputArray; }