(async()=>{ const panel=document.querySelector('#push-prompt'); const toggle=document.querySelector('#push-toggle'); const enable=document.querySelector('#push-enable'); const dismiss=document.querySelector('#push-dismiss'); const message=document.querySelector('#push-message'); const status=document.querySelector('#push-status'); let registration; let config; let subscription; const remember=()=>{try{localStorage.setItem('truenews-push-dismissed',String(Date.now()));}catch{}}; const dismissed=()=>{try{return Date.now()-Number(localStorage.getItem('truenews-push-dismissed')||0)<30*86400000;}catch{return false;}}; const api=async(action,value)=>{ const response=await fetch(`/api/push/${action}`,{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify(value)}); if(!response.ok)throw new Error('Could not save your preference. Please try again.'); }; const show=()=>{panel.hidden=false;}; const update=()=>{ toggle.textContent=subscription?'Notifications on':'Get new stories'; enable.textContent=subscription?'Turn off notifications':'Enable notifications'; message.textContent=subscription?'You’ll get a notification when a new article is published.':'Get a browser notification when a new story is published. You can turn this off anytime.'; }; try { const response=await fetch('/api/push/config'); if(!response.ok)return; config=await response.json(); if(!config.enabled)return; toggle.hidden=false; const supported=window.isSecureContext && 'serviceWorker' in navigator && 'PushManager' in window && 'Notification' in window; if(!supported){ const explain=()=>{ show();enable.hidden=true; const apple=/iPad|iPhone|iPod/.test(navigator.userAgent)||(navigator.platform==='MacIntel'&&navigator.maxTouchPoints>1); message.textContent=apple?'On iPhone or iPad, add TrueNews to your Home Screen, open it from there, then enable notifications.':'Notifications need a supported browser and a secure HTTPS connection.'; }; toggle.addEventListener('click',explain); if((/iPad|iPhone|iPod/.test(navigator.userAgent)||(navigator.platform==='MacIntel'&&navigator.maxTouchPoints>1))&&!dismissed())explain(); dismiss.addEventListener('click',()=>{panel.hidden=true;remember();}); return; } registration=await navigator.serviceWorker.register('/sw.js'); await navigator.serviceWorker.ready; subscription=await registration.pushManager.getSubscription(); if(subscription && Notification.permission==='granted') { // Restore the server record if a device revisits after a transient failure. await api('subscribe',subscription.toJSON()).catch(()=>{status.textContent='Could not sync notifications. You can retry or turn them off below.';}); } update(); toggle.addEventListener('click',()=>{status.textContent='';update();show();}); dismiss.addEventListener('click',()=>{panel.hidden=true;remember();}); enable.addEventListener('click',async()=>{ enable.disabled=true;status.textContent=''; try { if(subscription){ await api('unsubscribe',subscription.toJSON()); await subscription.unsubscribe();subscription=null;remember();update();status.textContent='Notifications turned off.'; }else{ // Permission must be requested directly from this user gesture. const permission=await Notification.requestPermission(); if(permission!=='granted'){ remember();status.textContent=permission==='denied'?'Notifications are blocked. You can change this in your browser’s site settings.':'No problem. You can enable notifications here later.';return; } const key=Uint8Array.from(atob(config.publicKey.replace(/-/g,'+').replace(/_/g,'/')),c=>c.charCodeAt(0)); const created=await registration.pushManager.subscribe({userVisibleOnly:true,applicationServerKey:key}); try {await api('subscribe',created.toJSON());}catch(error){await created.unsubscribe();throw error;} subscription=created;update();status.textContent='You’re subscribed. Watch for the next story.'; } }catch(error){status.textContent=error.message || 'Could not update notifications. Please try again.';} finally{enable.disabled=false;} }); if(!subscription && Notification.permission==='default' && !dismissed()) show(); }catch{toggle.hidden=true;panel.hidden=true;} })();