Push notifications: Send notifications through service worker if possible (#1068)
This commit is contained in:
parent
272b4c23fd
commit
753a1bb6bf
@ -7,7 +7,7 @@ enum Boolean {
|
|||||||
False = '0'
|
False = '0'
|
||||||
}
|
}
|
||||||
|
|
||||||
export type NotificationData = {
|
type PushData = {
|
||||||
custom: {
|
custom: {
|
||||||
msg_id?: string;
|
msg_id?: string;
|
||||||
channel_id?: string;
|
channel_id?: string;
|
||||||
@ -23,10 +23,17 @@ export type NotificationData = {
|
|||||||
description: string;
|
description: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type NotificationData = {
|
||||||
|
messageId?: number;
|
||||||
|
chatId?: number;
|
||||||
|
title: string;
|
||||||
|
body: string;
|
||||||
|
};
|
||||||
|
|
||||||
const clickBuffer: Record<string, NotificationData> = {};
|
const clickBuffer: Record<string, NotificationData> = {};
|
||||||
const shownNotifications = new Set();
|
const shownNotifications = new Set();
|
||||||
|
|
||||||
function getPushData(e: PushEvent | Notification): NotificationData | undefined {
|
function getPushData(e: PushEvent | Notification): PushData | undefined {
|
||||||
try {
|
try {
|
||||||
return e.data.json();
|
return e.data.json();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@ -38,6 +45,46 @@ function getPushData(e: PushEvent | Notification): NotificationData | undefined
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getChatId(data: PushData) {
|
||||||
|
if (data.custom.from_id) {
|
||||||
|
return parseInt(data.custom.from_id, 10);
|
||||||
|
}
|
||||||
|
// Chats and channels have negative IDs
|
||||||
|
if (data.custom.chat_id) {
|
||||||
|
return parseInt(data.custom.chat_id, 10) * -1;
|
||||||
|
}
|
||||||
|
if (data.custom.channel_id) {
|
||||||
|
return parseInt(data.custom.channel_id, 10) * -1;
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getMessageId(data: PushData) {
|
||||||
|
if (!data.custom.msg_id) return undefined;
|
||||||
|
return parseInt(data.custom.msg_id, 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getNotificationData(data: PushData):NotificationData {
|
||||||
|
return {
|
||||||
|
chatId: getChatId(data),
|
||||||
|
messageId: getMessageId(data),
|
||||||
|
title: data.title || process.env.APP_INFO!,
|
||||||
|
body: data.description,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function showNotification({
|
||||||
|
chatId, messageId, body, title,
|
||||||
|
}: NotificationData) {
|
||||||
|
return self.registration.showNotification(title, {
|
||||||
|
body,
|
||||||
|
data: { chatId, messageId },
|
||||||
|
icon: 'icon-192x192.png',
|
||||||
|
badge: 'icon-192x192.png',
|
||||||
|
vibrate: [200, 100, 200],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
export function handlePush(e: PushEvent) {
|
export function handlePush(e: PushEvent) {
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
@ -52,49 +99,19 @@ export function handlePush(e: PushEvent) {
|
|||||||
// Do not show muted notifications
|
// Do not show muted notifications
|
||||||
if (!data || data.mute === Boolean.True) return;
|
if (!data || data.mute === Boolean.True) return;
|
||||||
|
|
||||||
|
const notification = getNotificationData(data);
|
||||||
|
|
||||||
// Dont show already triggered notification
|
// Dont show already triggered notification
|
||||||
const messageId = getMessageId(data);
|
if (shownNotifications.has(notification.messageId)) {
|
||||||
if (shownNotifications.has(messageId)) {
|
shownNotifications.delete(notification.messageId);
|
||||||
shownNotifications.delete(messageId);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const title = data.title || process.env.APP_INFO!;
|
e.waitUntil(showNotification(notification));
|
||||||
const body = data.description;
|
|
||||||
|
|
||||||
e.waitUntil(
|
|
||||||
self.registration.showNotification(title, {
|
|
||||||
body,
|
|
||||||
data,
|
|
||||||
icon: 'icon-192x192.png',
|
|
||||||
badge: 'icon-192x192.png',
|
|
||||||
vibrate: [200, 100, 200],
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function getChatId(data: NotificationData) {
|
function focusChatMessage(client: WindowClient, data: {chatId?: number; messageId?: number}) {
|
||||||
if (data.custom.from_id) {
|
const { chatId, messageId } = data;
|
||||||
return parseInt(data.custom.from_id, 10);
|
|
||||||
}
|
|
||||||
// Chats and channels have negative IDs
|
|
||||||
if (data.custom.chat_id) {
|
|
||||||
return parseInt(data.custom.chat_id, 10) * -1;
|
|
||||||
}
|
|
||||||
if (data.custom.channel_id) {
|
|
||||||
return parseInt(data.custom.channel_id, 10) * -1;
|
|
||||||
}
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getMessageId(data: NotificationData) {
|
|
||||||
if (!data.custom.msg_id) return undefined;
|
|
||||||
return parseInt(data.custom.msg_id, 10);
|
|
||||||
}
|
|
||||||
|
|
||||||
function focusChatMessage(client: WindowClient, data: NotificationData) {
|
|
||||||
const chatId = getChatId(data);
|
|
||||||
const messageId = getMessageId(data);
|
|
||||||
|
|
||||||
if (chatId) {
|
if (chatId) {
|
||||||
client.postMessage({
|
client.postMessage({
|
||||||
@ -147,7 +164,8 @@ export function handleClientMessage(e: ExtendableMessageEvent) {
|
|||||||
}
|
}
|
||||||
if (e.data.type === 'newMessageNotification') {
|
if (e.data.type === 'newMessageNotification') {
|
||||||
// store messageId for already shown notification
|
// store messageId for already shown notification
|
||||||
const { messageId } = e.data.payload;
|
const notification: NotificationData = e.data.payload;
|
||||||
shownNotifications.add(messageId);
|
e.waitUntil(showNotification(notification));
|
||||||
|
shownNotifications.add(notification.messageId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -242,33 +242,40 @@ export async function showNewMessageNotification({
|
|||||||
body,
|
body,
|
||||||
} = getNotificationContent(chat, message as ApiMessage);
|
} = getNotificationContent(chat, message as ApiMessage);
|
||||||
|
|
||||||
const notification = new Notification(title, {
|
if (checkIfPushSupported()) {
|
||||||
body,
|
if (navigator.serviceWorker.controller) {
|
||||||
icon: 'icon-192x192.png',
|
// notify service worker about new message notification
|
||||||
badge: 'icon-192x192.png',
|
navigator.serviceWorker.controller.postMessage({
|
||||||
tag: message.id.toString(),
|
type: 'newMessageNotification',
|
||||||
vibrate: [200, 100, 200],
|
payload: {
|
||||||
});
|
title,
|
||||||
|
body,
|
||||||
if (navigator.serviceWorker.controller) {
|
chatId: chat.id,
|
||||||
// notify service worker about new message notification
|
messageId: message.id,
|
||||||
navigator.serviceWorker.controller.postMessage({
|
},
|
||||||
type: 'newMessageNotification',
|
});
|
||||||
payload: { messageId: message.id },
|
|
||||||
});
|
|
||||||
}
|
|
||||||
const dispatch = getDispatch();
|
|
||||||
|
|
||||||
notification.onclick = () => {
|
|
||||||
notification.close();
|
|
||||||
dispatch.focusMessage({
|
|
||||||
chatId: chat.id,
|
|
||||||
messageId: message.id,
|
|
||||||
});
|
|
||||||
if (window.focus) {
|
|
||||||
window.focus();
|
|
||||||
}
|
}
|
||||||
};
|
} else {
|
||||||
|
const dispatch = getDispatch();
|
||||||
|
const notification = new Notification(title, {
|
||||||
|
body,
|
||||||
|
icon: 'icon-192x192.png',
|
||||||
|
badge: 'icon-192x192.png',
|
||||||
|
tag: message.id.toString(),
|
||||||
|
vibrate: [200, 100, 200],
|
||||||
|
});
|
||||||
|
|
||||||
|
notification.onclick = () => {
|
||||||
|
notification.close();
|
||||||
|
dispatch.focusMessage({
|
||||||
|
chatId: chat.id,
|
||||||
|
messageId: message.id,
|
||||||
|
});
|
||||||
|
if (window.focus) {
|
||||||
|
window.focus();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Notify service worker that client is fully loaded
|
// Notify service worker that client is fully loaded
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user