Ask A Question

Notifications

You’re not receiving notifications from this thread.

Noticed V2 is great! What am I missing on the issue of 'persisting clients subscription'

Walther Diechmann asked in Gems / Libraries

I use the web_push strategy in Noticed V2 - and it's a kicker - my +1 on that, really!

But I must be doing something wrong b/c everytime a user logs into the app hem is requested (by the service-worker) to accept receiving notifications. IMHO the user should only be facing that decision once (and then on a dashboard or profile have an unsubscribe button)

My question boils down to: how do I persist the user's decision to subscribing to notifications on the client - as it apparently is not enough to

  await fetch("/web_push_subscriptions", {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
    },
    body: JSON.stringify(subscription),
  });

thx again for a real gem Chris!

Reply

Doesn't the browser usually store the preference for granted notification access?

You might be able to change it so it only calls requestPermission() if Notification.permission === "default"

See: https://developer.mozilla.org/en-US/docs/Web/API/Notification

Reply

Yeah - turns out I was overthinking it - the browser/device apparently does the house-keeping themselves - so I took it in another direction. Scold me for littering if you must - here is the Stimulus controller that emerged from the thick of the fight

import { Controller } from "@hotwired/stimulus"
import { enter, leave } from "el-transition"

// Connects to data-controller="profile"
export default class extends Controller {

  static targets = [
    "buttonForm",
    "enableNotifications",
    "disableNotifications"
  ]

  registration = null

  connect() {
    navigator.serviceWorker.register("/service-worker.js").then(
      (reg) => {
        this.registration = reg;
        if (!this.registration) return;
        this.showPromptForNotifications();
      },
      (err) => {
        console.error("Service Worker registration failed: ", err);
      }
    );
  }

  enable(event) {
    event.preventDefault()
    if (!this.registration) return;
    this.buttonFormTarget.ariaBusy = true;
    Notification.requestPermission()
      .then((permission) => {
        if (permission === "granted") {
          this.setupSubscription();
        } else {
          console.log("Notifications declined");
        }
      })
      .catch((error) => console.log("Notifications error", error));
  }

  disable(event) {
    event.preventDefault()
    console.log("Disable notifications")
    if (!this.registration) return;

    let r = this.registration
    let en = this.enableNotificationsTarget
    let dn = this.disableNotificationsTarget

    this.registration.pushManager.getSubscription().then(
      async function (subscription) {
        if (!subscription) return;

        await fetch("/web_push_subscriptions?unsubscribe=true", {
          method: "POST",
          headers: {
            "Content-Type": "application/json",
          },
          body: JSON.stringify(subscription),
        }).then((response) => {
          if (response.ok) {
            subscription.unsubscribe()
            r = null
            leave(dn).then(() => {
              enter(en)
            })
          }
        }).catch(function (e) {
          console.log("Server unsubscription setup failed", e);
        })
      })
  }

  // Show a prompt to the user to subscribe to notifications
  showPromptForNotifications() {
    this.registration.pushManager.getSubscription().then(
      (subscription) => {
        if (subscription) {
          this.setupSubscription(subscription);
        } else {
          enter(this.enableNotificationsTarget)
        }
      },
      (err) => {
        console.log("Error getting subscription: ", err);
      }
    );
  }

  //
  // Setup the subscription with the push server - provided the user has granted permission
  async setupSubscription(subscription = null) {
    if (Notification.permission !== "granted" && !subscription) return;

    if (!subscription) {
      let vapid = new Uint8Array(
        JSON.parse(document.querySelector("meta[name=web_push_public]")?.content)
      );

      subscription = await this.registration.pushManager.subscribe({
        userVisibleOnly: true,
        applicationServerKey: vapid,
      });
    }

    await fetch("/web_push_subscriptions", {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
      },
      body: JSON.stringify(subscription),
    }).then((response) => {
      if (response.ok) {
        leave(this.enableNotificationsTarget).then(() => {
          enter(this.disableNotificationsTarget);
        });
      } else {
        console.log("Subscription setup failed");
      }
    });
  }
}

Reply
Join the discussion
Create an account Log in

Want to stay up-to-date with Ruby on Rails?

Join 87,110+ developers who get early access to new tutorials, screencasts, articles, and more.

    We care about the protection of your data. Read our Privacy Policy.