diff --git a/components/PushNotification.vue b/components/PushNotification.vue index 4e1e6f1..93f7005 100644 --- a/components/PushNotification.vue +++ b/components/PushNotification.vue @@ -1,14 +1,14 @@ diff --git a/composables/push-notification.ts b/composables/push-notification.ts new file mode 100644 index 0000000..9668a45 --- /dev/null +++ b/composables/push-notification.ts @@ -0,0 +1,109 @@ +function notificationSupported() { + return ( + import.meta.client + && "serviceWorker" in navigator + && "PushManager" in window + && "showNotification" in ServiceWorkerRegistration.prototype + ); +} + +export const usePushNotification = () => { + const subscription = ref(null); + const supported = ref(undefined); + const runtimeConfig = useRuntimeConfig(); + + function checkSupport() { + return supported.value = notificationSupported(); + } + + async function postSubscription(subscription: PushSubscriptionJSON) { + const result = await $fetch("/api/subscribe", { + method: "POST", + body: { subscription }, + }); + console.log("/api/subscribe returned", result); + } + + async function postUnsubscription() { + const result = await $fetch("/api/unsubscribe", { + method: "POST", + }); + console.log("/api/unsubscribe returned", result); + } + + async function subscribe() { + if (!checkSupport()) + return; + + let registration; + try { + registration = await navigator.serviceWorker.register("/sw.js"); + } catch (err) { + console.error("Failed to register service worker:", err); + return; + } + + // Check if we already have a subscription. + if (!subscription.value) { + subscription.value = await registration.pushManager.getSubscription(); + } + + // Create a new push subscription if none exists. + if (!subscription.value) { + try { + subscription.value = await registration.pushManager.subscribe({ + userVisibleOnly: true, + applicationServerKey: runtimeConfig.public.vapidPublicKey, + }); + } catch (err) { + console.error("Failed to subscribe:" , err); + return; + } + } + + console.log("Subscribing with", subscription.value); + + // Tell server about the new subscription. + try { + await postSubscription(subscription.value.toJSON()); + } catch (err) { + console.log("Failed to post subscription to server", err) + return; + } + } + + async function unsubscribe() { + if (!checkSupport()) + return; + + // Fetch subscription if it hasn't already been fetched. + if (!subscription.value) { + await getSubscription(); + } + + if (!subscription.value) { + return; + } + + await subscription.value.unsubscribe(); + subscription.value = null; + await postUnsubscription(); + } + + async function getSubscription() { + if (!checkSupport()) + return; + const registration = await navigator.serviceWorker.getRegistration("./sw.js"); + if (!registration) + return; + return subscription.value = await registration.pushManager.getSubscription(); + } + + return { + supported, + subscription, + getSubscription, + subscribe, + unsubscribe, + } +} diff --git a/pages/login.vue b/pages/login.vue index f0a96f4..106a33a 100644 --- a/pages/login.vue +++ b/pages/login.vue @@ -12,6 +12,7 @@