import { ref } from 'vue'; export function usePushNotifications() { const isSubscribed = ref(false); async function subscribe() { if (!('serviceWorker' in navigator)) { return; } const registration = await navigator.serviceWorker.ready; const subscription = await registration.pushManager.subscribe({ userVisibleOnly: true, applicationServerKey: urlBase64ToUint8Array( document.querySelector('meta[name="vapid-public-key"]')?.getAttribute('content') || '', ), }); await fetch('/subscriptions', { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]')?.getAttribute('content') || '', }, body: JSON.stringify(subscription), }); isSubscribed.value = true; } async function unsubscribe() { if (!('serviceWorker' in navigator)) { return; } const registration = await navigator.serviceWorker.ready; const subscription = await registration.pushManager.getSubscription(); if (subscription) { await fetch('/subscriptions/delete', { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]')?.getAttribute('content') || '', }, body: JSON.stringify({ endpoint: subscription.endpoint }), }); await subscription.unsubscribe(); } isSubscribed.value = false; } function urlBase64ToUint8Array(base64String: string) { 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; } return { isSubscribed, subscribe, unsubscribe, }; }