feat: push notifications

This commit is contained in:
2023-12-18 12:20:14 +00:00
parent a3d4b81e23
commit fec6f48bce
5 changed files with 165 additions and 1 deletions

View File

@ -0,0 +1,86 @@
import AsyncButton from "./async-button";
import { useLogin } from "@/hooks/login";
import { NostrStreamProvider } from "@/providers";
import { base64 } from "@scure/base";
import { unwrap } from "@snort/shared";
import { useEffect, useState } from "react";
import { Icon } from "./icon";
export function NotificationsButton({ host, service }: { host: string, service: string }) {
const login = useLogin();
const publisher = login?.publisher();
const [subscribed, setSubscribed] = useState(false);
const api = new NostrStreamProvider("", service, publisher);
async function isSubscribed() {
const reg = await navigator.serviceWorker.ready;
if (reg) {
const sub = await reg.pushManager.getSubscription();
if (sub) {
const auth = base64.encode(new Uint8Array(unwrap(sub.getKey("auth"))));
const subs = await api.listStreamerSubscriptions(auth);
setSubscribed(subs.includes(host));
}
}
}
async function enableNotifications() {
// request permissions to send notifications
if ("Notification" in window) {
try {
if (Notification.permission !== "granted") {
const res = await Notification.requestPermission();
console.debug(res);
}
return Notification.permission === "granted";
} catch (e) {
console.error(e);
}
}
return false;
}
async function subscribe() {
if (await enableNotifications()) {
try {
if ("serviceWorker" in navigator) {
const reg = await navigator.serviceWorker.ready;
if (reg && publisher) {
const sub = await reg.pushManager.subscribe({
userVisibleOnly: true,
applicationServerKey: (await api.getNotificationsInfo()).publicKey,
});
await api.subscribeNotifications({
endpoint: sub.endpoint,
key: base64.encode(new Uint8Array(unwrap(sub.getKey("p256dh")))),
auth: base64.encode(new Uint8Array(unwrap(sub.getKey("auth")))),
scope: `${location.protocol}//${location.hostname}`,
});
await api.addStreamerSubscription(host);
setSubscribed(true);
}
} else {
console.warn("No service worker")
}
} catch (e) {
console.error(e);
}
}
}
async function unsubscribe() {
if (publisher) {
await api.removeStreamerSubscription(host);
setSubscribed(false);
}
}
useEffect(() => {
isSubscribed().catch(console.error);
}, []);
return <AsyncButton onClick={subscribed ? unsubscribe : subscribe}>
<Icon name={subscribed ? "bell-off" : "bell-ringing"} />
</AsyncButton>
}