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 @@
- Notifications are: {{ subscription ? "Enabled" : "Disabled" }}
+ Notifications are: {{ subscribed ? "Enabled" : "Disabled" }}
Debug
@@ -18,102 +18,18 @@
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 @@