66 lines
1.9 KiB
TypeScript
66 lines
1.9 KiB
TypeScript
// composables/usePushNotifications.ts
|
|
import { useLocalStorage, usePermission } from "@vueuse/core";
|
|
import { onMounted, ref } from "vue";
|
|
import useSubscribeNotification from "../api/notifications/useSubscribeNotification";
|
|
|
|
interface VapidKeys {
|
|
publicKey: string;
|
|
}
|
|
|
|
export const usePushNotifications = () => {
|
|
const isSupported = ref(false);
|
|
const permission = usePermission("notifications");
|
|
const subscription = useLocalStorage<PushSubscriptionJSON | null>(
|
|
"push-subscription",
|
|
null
|
|
);
|
|
const vapid = ref<VapidKeys | null>(null);
|
|
|
|
const { mutateAsync: subscribeNotification } = useSubscribeNotification();
|
|
const toast = useToast();
|
|
|
|
// Only run in client-side
|
|
onMounted(async () => {
|
|
if (typeof window !== "undefined" && "serviceWorker" in navigator) {
|
|
isSupported.value = true;
|
|
vapid.value = await $fetch("/api/vapid");
|
|
}
|
|
});
|
|
|
|
const subscribe = async () => {
|
|
if (!isSupported.value || !vapid.value?.publicKey) {
|
|
throw new Error("Push notifications not supported");
|
|
}
|
|
|
|
const swRegistration = await navigator.serviceWorker.ready;
|
|
|
|
const applicationServerKey = vapid.value.publicKey
|
|
.replace(/-/g, "+")
|
|
.replace(/_/g, "/");
|
|
|
|
const convertedKey = Uint8Array.from(atob(applicationServerKey), (c) =>
|
|
c.charCodeAt(0)
|
|
);
|
|
|
|
const pushSubscription = await swRegistration.pushManager.subscribe({
|
|
userVisibleOnly: true,
|
|
applicationServerKey: convertedKey,
|
|
});
|
|
|
|
const subscriptionJson = pushSubscription.toJSON();
|
|
|
|
subscribeNotification({
|
|
body: subscriptionJson,
|
|
});
|
|
|
|
subscription.value = subscriptionJson;
|
|
};
|
|
|
|
return {
|
|
isSupported,
|
|
permission,
|
|
subscribe,
|
|
subscription,
|
|
};
|
|
};
|