/// /// /// /// self.addEventListener('install', (event) => { self.skipWaiting(); }); self.addEventListener('activate', (event) => { event.waitUntil(self.clients.claim()); }); // ###### Handle unread badge: const conversationReadStatus = { // Format: // conversationId: { lastRead: Optional(Datetime), lastMessage: Datetime } }; function countUnreadChannels() { return Object.entries(conversationReadStatus) .map(([conversationId, { lastRead, lastMessage }]) => { return !lastRead || lastRead < lastMessage ? 1 : 0; }) .reduce((total, current) => total + current, 0); } self.addEventListener('push', (event) => { const data = event.data.json(); if (data.type === 'heartbeat') { // Let's show a notification right away so Safari doesn't tell Apple to be // mad at us: event.waitUntil( self.registration.showNotification('Test notification', { actions: [], body: event.data.text(), }), ); } if (data.type === 'message' && data.event === 'sent') { // Now we can do slower things that might fail: conversationReadStatus[data.conversation] ||= { lastRead: null, lastMessage: null }; conversationReadStatus[data.conversation].lastMessage = new Date(); event.waitUntil( (async () => { if (navigator.setAppBadge) { await navigator.setAppBadge(countUnreadChannels()); } })(), ); } }); // The client has to tell us when it has read a conversation: self.addEventListener('message', (event) => { const data = event.data; switch (data.type) { case 'CONVERSATION_READ': conversationReadStatus[data.conversationId] ||= { lastRead: null, lastMessage: null }; if (data.at) { conversationReadStatus[data.conversationId].lastRead = new Date(data.at.ts); } else { conversationReadStatus[data.conversationId].lastRead = new Date(); } event.waitUntil( (async () => { if (navigator.setAppBadge) { await navigator.setAppBadge(countUnreadChannels()); } })(), ); break; default: break; } });