File size: 2,115 Bytes
a0c836f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
// Web Push registration + subscription helpers.
import { getVapidKey, subscribePush } from "./api"

export function pushSupported() {
  return "serviceWorker" in navigator && "PushManager" in window
}

export async function registerSW() {
  if (!("serviceWorker" in navigator)) return null
  return navigator.serviceWorker.register("/sw.js")
}

function urlBase64ToUint8Array(base64String) {
  const padding = "=".repeat((4 - (base64String.length % 4)) % 4)
  const base64 = (base64String + padding).replace(/-/g, "+").replace(/_/g, "/")
  const raw = window.atob(base64)
  const arr = new Uint8Array(raw.length)
  for (let i = 0; i < raw.length; i++) arr[i] = raw.charCodeAt(i)
  return arr
}

// Triggered from a user gesture (the Profile "Enable reminders" button).
export async function enableReminders() {
  if (!pushSupported()) {
    throw new Error("Push notifications are not supported in this browser.")
  }

  // If already blocked, requestPermission() returns "denied" without a prompt.
  if (Notification.permission === "denied") {
    throw new Error("Notifications are blocked for this site. Click the lock/info icon at the left of the address bar → Site settings → set Notifications to Allow → reload and try again.")
  }
  const permission = await Notification.requestPermission()
  if (permission !== "granted") {
    throw new Error("Please choose 'Allow' on the notification prompt to enable reminders.")
  }

  const registration = await registerSW()
  await navigator.serviceWorker.ready

  const publicKey = await getVapidKey()
  if (!publicKey) {
    throw new Error("Server is missing VAPID keys. Set VAPID_PUBLIC_KEY / VAPID_PRIVATE_KEY in .env.")
  }

  const existing = await registration.pushManager.getSubscription()
  const subscription =
    existing ||
    (await registration.pushManager.subscribe({
      userVisibleOnly: true,
      applicationServerKey: urlBase64ToUint8Array(publicKey),
    }))

  const json = subscription.toJSON()
  await subscribePush({
    endpoint: json.endpoint,
    keys: { p256dh: json.keys.p256dh, auth: json.keys.auth },
  })

  return true
}