Couchers-org / couchers

The next-generation couch surfing platform. Free forever. Community‑led. Non‑profit. Modern. Chuck us a star :)
https://couchers.org
MIT License
358 stars 76 forks source link

Web push notifications #4417

Open aapeliv opened 3 weeks ago

aapeliv commented 3 weeks ago

The web frontend needs a UI and service worker to handle web push notifications. The bulk of it is now implemented in the backend.

aapeliv commented 3 weeks ago

Here is the current service worker code:

self.addEventListener('push', event => {
  const data = event.data.json();
  const options = {
    body: data.body,
    icon: data.icon,
    data: {
      url: data.url
    }
  };

  event.waitUntil(
    self.registration.showNotification(data.title, options)
  );
});

self.addEventListener('notificationclick', event => {
  event.notification.close();

  const url = event.notification.data.url;
  if (!url) {
    return;
  }

  event.waitUntil(
    clients.matchAll({ type: 'window', includeUncontrolled: true }).then(windowClients => {
      // Check if the URL is already open in a tab
      for (let i = 0; i < windowClients.length; i++) {
        const client = windowClients[i];
        if (client.url === url && 'focus' in client) {
          return client.focus();
        }
      }
      // Open a new tab if the URL is not already open
      if (clients.openWindow) {
        return clients.openWindow(url);
      }
    })
  );
});

Here is the current registration code:


  document.addEventListener('DOMContentLoaded', async () => {
    const VAPID_PUBLIC_KEY = "BGzVWgNjv0JuYRoPm5lswCIEyaChcWdZ9jFlU0kG0SUx2MQf6trRZMRTfqVGTUi7K0iRvvbvTIvvKt0M0ogUC-M";
    console.log("vapid public key: " + VAPID_PUBLIC_KEY);
    document.getElementById('registerBtn').addEventListener('click', async () => {
      if ('serviceWorker' in navigator && 'PushManager' in window) {
        try {
          // Register service worker
          const registration = await navigator.serviceWorker.register('/sw.js');
          console.log('Service Worker registered', registration);

          // Request permission to send notifications
          const permission = await Notification.requestPermission();
          if (permission !== 'granted') {
            console.log('Permission not granted for Notifications');
            return;
          }

          const sub = await registration.pushManager.getSubscription();
          console.log(sub);
          if (sub) {
            console.log(sub.toJSON());
            let public_key = sub.toJSON().keys.p256dh;
            console.log(public_key);
            if(public_key != VAPID_PUBLIC_KEY){
              await sub.unsubscribe();
            } else {
              return;
            }
          }

          // Subscribe to push notifications
          const subscription = await registration.pushManager.subscribe({
            userVisibleOnly: true,
            applicationServerKey: VAPID_PUBLIC_KEY
          });

          console.log('Push subscription:', JSON.stringify(subscription));

          const res = await fetch("/json-api/push/complete-registration", {
            method: 'POST',
            headers: {
              'Content-Type': 'application/json'
            },
            body: JSON.stringify(subscription)
          })
          if (res.ok) {
            document.getElementById("success").innerHTML = "Success!"
          }
        } catch (error) {
          console.error('Error during service worker registration or subscription:', error);
        }
      } else {
        console.warn('Push messaging is not supported');
      }
    });
  });