send notifications over SSE to be displayed inside the app

This commit is contained in:
m5r
2022-06-19 17:57:51 +02:00
parent a46a4a3861
commit 6cf2f8cb94
13 changed files with 146 additions and 63 deletions

View File

@ -5,7 +5,8 @@ import useAppLoaderData from "~/features/core/hooks/use-app-loader-data";
export default function useNotifications() {
const isServiceWorkerSupported = useMemo(() => "serviceWorker" in navigator, []);
const [subscription, setSubscription] = useState<PushSubscription | null>(null);
const isWebPushSupported = useMemo(() => "PushManager" in window, []);
const [subscription, setSubscription] = useState<PushSubscription | null>();
const { webPushPublicKey } = useAppLoaderData().config;
const fetcher = useFetcher();
const subscribeToNotifications = (subscription: PushSubscriptionJSON) => {
@ -29,7 +30,7 @@ export default function useNotifications() {
useEffect(() => {
(async () => {
if (!isServiceWorkerSupported) {
if (!isServiceWorkerSupported || !isWebPushSupported) {
return;
}
@ -37,10 +38,10 @@ export default function useNotifications() {
const subscription = await registration.pushManager.getSubscription();
setSubscription(subscription);
})();
}, [isServiceWorkerSupported]);
}, [isServiceWorkerSupported, isWebPushSupported]);
async function subscribe() {
if (!isServiceWorkerSupported || subscription !== null || fetcher.state !== "idle") {
if (!isServiceWorkerSupported || !isWebPushSupported || subscription !== null || fetcher.state !== "idle") {
return;
}
@ -54,7 +55,7 @@ export default function useNotifications() {
}
async function unsubscribe() {
if (!isServiceWorkerSupported || !subscription || fetcher.state !== "idle") {
if (!isServiceWorkerSupported || !isWebPushSupported || !subscription || fetcher.state !== "idle") {
return;
}
@ -69,7 +70,7 @@ export default function useNotifications() {
}
return {
isServiceWorkerSupported,
isNotificationSupported: isServiceWorkerSupported && isWebPushSupported,
subscription,
subscribe,
unsubscribe,

View File

@ -7,22 +7,39 @@ export default function useNotifications() {
const [notificationData, setNotificationData] = useAtom(notificationDataAtom);
useEffect(() => {
const channel = new BroadcastChannel("notifications");
const eventSource = new EventSource("/sse/notifications");
eventSource.addEventListener("message", onMessage);
return () => {
eventSource.removeEventListener("message", onMessage);
eventSource.close();
};
function onMessage(event: MessageEvent) {
console.log("event.data", JSON.parse(event.data));
const notifyChannel = new BroadcastChannel("notifications");
notifyChannel.postMessage(event.data);
notifyChannel.close();
}
}, []);
useEffect(() => {
const notifyChannel = new BroadcastChannel("notifications");
async function eventHandler(event: MessageEvent) {
const payload: NotificationPayload = JSON.parse(event.data);
setNotificationData(payload);
}
channel.addEventListener("message", eventHandler);
notifyChannel.addEventListener("message", eventHandler);
return () => {
channel.removeEventListener("message", eventHandler);
channel.close();
notifyChannel.removeEventListener("message", eventHandler);
notifyChannel.close();
};
}, [setNotificationData]);
useEffect(() => {
if (!notificationData) {
if (!notificationData || notificationData.data.type === "call") {
return;
}