184 lines
4.9 KiB
TypeScript
184 lines
4.9 KiB
TypeScript
import { useEffect, useState } from "react"
|
|
|
|
export type PushObject = {
|
|
/**
|
|
* Boolean state indicating whether the user is subscribed to push notifications or not.
|
|
*/
|
|
isSubscribed: boolean
|
|
/**
|
|
* The push subscription object
|
|
*/
|
|
pushSubscription: PushSubscription | null
|
|
/**
|
|
* Request permission for push notifications
|
|
* @returns The permission status of the push notifications
|
|
*/
|
|
requestPermission: () => NotificationPermission
|
|
/**
|
|
* Utility to subscribe to push notifications
|
|
* @param publicKey the public vapid key
|
|
* @param callback a callback function to be called when the subscription is successful
|
|
* @param errorCallback a callback function to be called if the subscription fails
|
|
*/
|
|
subscribeToPush: (
|
|
publicKey: string,
|
|
callback?: (subscription: PushSubscription) => void,
|
|
errorCallback?: (error: any) => void
|
|
) => void
|
|
/**
|
|
* Utility to unsubscribe from push notifications
|
|
* @param callback a callback function to be called when the unsubscription is successful
|
|
* @param errorCallback a callback function to be called if the unsubscription fails
|
|
*/
|
|
unsubscribeFromPush: (
|
|
callback?: () => void,
|
|
errorCallback?: (error: any) => void
|
|
) => void
|
|
/**
|
|
* Boolean state indicating whether the user has allowed sending of push notifications or not.
|
|
*/
|
|
canSendPush: boolean
|
|
}
|
|
|
|
/**
|
|
* Push API hook - contains all your necessities for handling push notifications in the client
|
|
*/
|
|
export const usePush = (): PushObject => {
|
|
const [swRegistration, setSWRegistration] =
|
|
useState<ServiceWorkerRegistration | null>(null)
|
|
const [isSubscribed, setIsSubscribed] = useState<boolean>(false)
|
|
const [pushSubscription, setPushSubscription] =
|
|
useState<PushSubscription | null>(null)
|
|
const [canSendPush, setCanSendPush] = useState<boolean>(false)
|
|
|
|
const requestPermission = () => {
|
|
if (canSendPush) return "granted"
|
|
|
|
Notification.requestPermission().then((permission) => {
|
|
if (permission === "granted") {
|
|
setCanSendPush(true)
|
|
return permission
|
|
} else {
|
|
setCanSendPush(false)
|
|
return permission
|
|
}
|
|
})
|
|
|
|
return "default"
|
|
}
|
|
|
|
const subscribeToPush = (
|
|
publicKey: string,
|
|
callback?: (subscription: PushSubscription) => void,
|
|
errorCallback?: (error: any) => void
|
|
) => {
|
|
if (swRegistration === null || swRegistration.pushManager === undefined)
|
|
return
|
|
|
|
swRegistration.pushManager
|
|
.subscribe({
|
|
userVisibleOnly: true,
|
|
applicationServerKey: publicKey,
|
|
})
|
|
.then(
|
|
(subscription) => {
|
|
setIsSubscribed(true)
|
|
setPushSubscription(subscription)
|
|
callback && callback(subscription)
|
|
},
|
|
(error) => {
|
|
errorCallback && errorCallback(error)
|
|
}
|
|
)
|
|
}
|
|
|
|
const unsubscribeFromPush = (
|
|
callback?: () => void,
|
|
errorCallback?: (error: any) => void
|
|
) => {
|
|
if (swRegistration === null || swRegistration.pushManager === undefined)
|
|
return
|
|
|
|
swRegistration.pushManager
|
|
.getSubscription()
|
|
.then((subscription) => {
|
|
if (subscription) {
|
|
subscription.unsubscribe().then(
|
|
() => {
|
|
setIsSubscribed(false)
|
|
setPushSubscription(null)
|
|
callback && callback()
|
|
},
|
|
(error) => {
|
|
errorCallback && errorCallback(error)
|
|
}
|
|
)
|
|
}
|
|
})
|
|
.catch((error) => {
|
|
errorCallback && errorCallback(error)
|
|
})
|
|
}
|
|
|
|
useEffect(() => {
|
|
if (typeof window === "undefined") return
|
|
|
|
const getRegistration = async () => {
|
|
if ("serviceWorker" in navigator) {
|
|
try {
|
|
const _registration = await navigator.serviceWorker.getRegistration()
|
|
setSWRegistration(_registration ?? null)
|
|
} catch (err) {
|
|
console.error("Error getting service worker registration:", err)
|
|
}
|
|
} else {
|
|
console.warn("Service Workers are not supported in this browser.")
|
|
}
|
|
}
|
|
|
|
const handleControllerChange = () => {
|
|
getRegistration()
|
|
}
|
|
|
|
if ("serviceWorker" in navigator) {
|
|
navigator.serviceWorker.addEventListener(
|
|
"controllerchange",
|
|
handleControllerChange
|
|
)
|
|
}
|
|
|
|
getRegistration()
|
|
|
|
return () => {
|
|
if ("serviceWorker" in navigator) {
|
|
navigator.serviceWorker.removeEventListener(
|
|
"controllerchange",
|
|
handleControllerChange
|
|
)
|
|
}
|
|
}
|
|
}, [])
|
|
|
|
useEffect(() => {
|
|
if (swRegistration && swRegistration.pushManager !== undefined) {
|
|
swRegistration.pushManager.getSubscription().then((subscription) => {
|
|
setIsSubscribed(!!subscription)
|
|
setPushSubscription(subscription)
|
|
})
|
|
|
|
Notification.permission === "granted"
|
|
? setCanSendPush(true)
|
|
: setCanSendPush(false)
|
|
}
|
|
}, [swRegistration])
|
|
|
|
return {
|
|
isSubscribed,
|
|
pushSubscription,
|
|
requestPermission,
|
|
subscribeToPush,
|
|
unsubscribeFromPush,
|
|
canSendPush,
|
|
}
|
|
}
|