/** * Push Notification Helper */ import { logError, logWarn } from './logger'; 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; } export const setupNotifications = async (token: string, orgId: string) => { if (!('serviceWorker' in navigator) || !('PushManager' in window)) { logWarn('Push notifications are not supported in this browser.'); return; } try { // 1. Check existing permission — ne pas re-demander si déjà refusé if (Notification.permission === 'denied') { return; // silencieux : l'utilisateur a déjà dit non } // 2. Register Service Worker const registration = await navigator.serviceWorker.register('/sw.js'); // 3. Request Permission (seulement si 'default', pas 'denied') const permission = Notification.permission === 'granted' ? 'granted' : await Notification.requestPermission(); if (permission !== 'granted') { return; // silencieux } // 3. Get VAPID public key from server const keyRes = await fetch(`${import.meta.env.VITE_API_URL}/v1/notifications/vapid-key`, { headers: { 'Authorization': `Bearer ${token}`, 'x-organization-id': orgId } }); const { publicKey } = await keyRes.json(); if (!publicKey) { logWarn('VAPID public key missing from server'); return; } // 4. Subscribe to Push const subscription = await registration.pushManager.subscribe({ userVisibleOnly: true, applicationServerKey: urlBase64ToUint8Array(publicKey) }); // 5. Send subscription to server await fetch(`${import.meta.env.VITE_API_URL}/v1/notifications/subscribe`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}`, 'x-organization-id': orgId }, body: JSON.stringify({ subscription }) }); } catch (err) { logError('Failed to setup push notifications', err); } };