}
return outputArray;
}
+
+ public updateLastNotificationTime(timestamp: number): void {
+ window.navigator.serviceWorker.controller?.postMessage({
+ type: "SAVE_LAST_NOTIFICATION_TIMESTAMP",
+ timestamp: timestamp,
+ });
+ }
}
export function serviceWorkerSupported(): boolean {
return true;
}
-export function setup(publicKey: string, serviceWorkerJsUrl: string, registerUrl: string): void {
+export function setup(
+ publicKey: string,
+ serviceWorkerJsUrl: string,
+ registerUrl: string,
+ lastReadNotification: number,
+): void {
if (!serviceWorkerSupported()) {
return;
}
_serviceWorker = new ServiceWorker(publicKey, serviceWorkerJsUrl, registerUrl);
if (Notification.permission === "granted") {
registerServiceWorker();
+ _serviceWorker.updateLastNotificationTime(lastReadNotification);
}
}
export function registerServiceWorker(): void {
void _serviceWorker?.register();
}
+
+export function updateLastNotificationTime(timestamp: number): void {
+ _serviceWorker?.updateLastNotificationTime(timestamp);
+}
exports.serviceWorkerSupported = serviceWorkerSupported;
exports.setup = setup;
exports.registerServiceWorker = registerServiceWorker;
+ exports.updateLastNotificationTime = updateLastNotificationTime;
let _serviceWorker = null;
class ServiceWorker {
#publicKey;
}
return outputArray;
}
+ updateLastNotificationTime(timestamp) {
+ window.navigator.serviceWorker.controller?.postMessage({
+ type: "SAVE_LAST_NOTIFICATION_TIMESTAMP",
+ timestamp: timestamp,
+ });
+ }
}
function serviceWorkerSupported() {
if (location.protocol !== "https:") {
}
return true;
}
- function setup(publicKey, serviceWorkerJsUrl, registerUrl) {
+ function setup(publicKey, serviceWorkerJsUrl, registerUrl, lastReadNotification) {
if (!serviceWorkerSupported()) {
return;
}
_serviceWorker = new ServiceWorker(publicKey, serviceWorkerJsUrl, registerUrl);
if (Notification.permission === "granted") {
registerServiceWorker();
+ _serviceWorker.updateLastNotificationTime(lastReadNotification);
}
}
function registerServiceWorker() {
void _serviceWorker?.register();
}
+ function updateLastNotificationTime(timestamp) {
+ _serviceWorker?.updateLastNotificationTime(timestamp);
+ }
});
const payload = event.data.json();
- event.waitUntil(
- removeOldNotifications(payload.notificationID, payload.time).then(() =>
- self.registration.showNotification(payload.title, {
- body: payload.message,
- icon: payload.icon,
- timestamp: payload.time * 1000,
- tag: payload.notificationID,
- data: {
- url: payload.url,
- time: payload.time,
- },
- }),
- ).then(() => {
- sendToClients(payload);
- }),
- );
+ getLastNotificationTimestamp().then(lastNotificationTimestamp => {
+ if (!lastNotificationTimestamp || payload.time < lastNotificationTimestamp) {
+ return;
+ }
+
+ event.waitUntil(
+ removeOldNotifications(payload.notificationID, payload.time).then(() =>
+ self.registration.showNotification(payload.title, {
+ body: payload.message,
+ icon: payload.icon,
+ timestamp: payload.time * 1000,
+ tag: payload.notificationID,
+ data: {
+ url: payload.url,
+ time: payload.time,
+ },
+ }),
+ ).then(() => {
+ sendToClients(payload);
+ }),
+ );
+ });
});
self.addEventListener("notificationclick", (event) => {
event.waitUntil(self.clients.openWindow(event.notification.data.url));
});
+self.addEventListener('message', event => {
+ if (event.data && event.data.type === 'SAVE_LAST_NOTIFICATION_TIMESTAMP') {
+ saveLastNotificationTimestamp(event.data.timestamp);
+ }
+});
+
async function sendToClients(payload){
const allClients = await self.clients.matchAll({
includeUncontrolled: true,
notification.close();
});
}
+
+/**
+ * IndexedDB functions to store the last notification timestamp.
+ */
+function openDatabase() {
+ return new Promise((resolve, reject) => {
+ const request = indexedDB.open('WOLTLAB_SUITE_CORE', 1);
+
+ request.onupgradeneeded = (event) => {
+ const db = event.target.result;
+ if (!db.objectStoreNames.contains('notifications')) {
+ db.createObjectStore('notifications');
+ }
+ };
+
+ request.onsuccess = (event) => {
+ resolve(event.target.result);
+
+ if (!db.objectStoreNames.contains('notifications')) {
+ db.createObjectStore('notifications');
+ }
+ };
+
+ request.onerror = (event) => {
+ reject('Database error: ' + event.target.errorCode);
+ };
+ });
+}
+
+function saveLastNotificationTimestamp(timestamp) {
+ if (!timestamp || timestamp <= 0) {
+ return;
+ }
+
+ openDatabase().then(db => {
+ const tx = db.transaction('notifications', 'readwrite');
+ const store = tx.objectStore('notifications');
+ const getRequest = store.get('lastNotification');
+
+ getRequest.onsuccess = () => {
+ const storedTimestamp = getRequest.result;
+
+ // Check if the new timestamp is greater than the stored timestamp
+ if (storedTimestamp === undefined || newTimestamp > storedTimestamp) {
+ store.put(timestamp, 'lastNotification');
+ }
+ };
+
+ getRequest.onerror = () => {
+ console.error('Failed to retrieve timestamp', getRequest.error);
+ };
+
+ tx.onerror = () => {
+ console.error('Transaktionsfehler', tx.error);
+ };
+ }).catch(err => console.error('Failed to open database', err));
+}
+
+function getLastNotificationTimestamp() {
+ return openDatabase().then(db => {
+ return new Promise((resolve, reject) => {
+ const tx = db.transaction('notifications', 'readonly');
+ const store = tx.objectStore('notifications');
+ const request = store.get('lastNotification');
+
+ request.onsuccess = () => {
+ resolve(request.result);
+ };
+ request.onerror = () => {
+ reject('Failed to retrieve timestamp');
+ };
+ });
+ });
+}