- Implemented push notifications with a service worker (sw.ts) to handle caching and notifications. - Added API routes for push subscription and notification management in routes/api.php. - Created NotificationTest to validate notification service functionality and ensure correct notifications are sent based on user roles and actions. - Updated Permissions component to manage notification permissions and subscriptions. - Enhanced CategoryIndex component to highlight categories based on notifications. - Excluded service worker from TypeScript compilation in tsconfig.json. - Updated Vite configuration to include service worker in the build process.
107 lines
2.7 KiB
TypeScript
107 lines
2.7 KiB
TypeScript
import { clientsClaim } from 'workbox-core';
|
|
import { ExpirationPlugin } from 'workbox-expiration';
|
|
import { precacheAndRoute } from 'workbox-precaching';
|
|
import { registerRoute } from 'workbox-routing';
|
|
import { CacheFirst, NetworkFirst } from 'workbox-strategies';
|
|
|
|
declare const self: ServiceWorkerGlobalScope;
|
|
|
|
precacheAndRoute(self.__WB_MANIFEST);
|
|
|
|
self.skipWaiting();
|
|
clientsClaim();
|
|
|
|
registerRoute(
|
|
({ url }) => url.origin === 'https://fonts.bunny.net',
|
|
new CacheFirst({
|
|
cacheName: 'bunny-fonts-cache',
|
|
plugins: [
|
|
new ExpirationPlugin({
|
|
maxEntries: 10,
|
|
maxAgeSeconds: 60 * 60 * 24 * 365,
|
|
}),
|
|
],
|
|
}),
|
|
);
|
|
|
|
registerRoute(
|
|
({ url }) => url.origin === 'https://fonts.googleapis.com',
|
|
new CacheFirst({
|
|
cacheName: 'google-fonts-cache',
|
|
plugins: [
|
|
new ExpirationPlugin({
|
|
maxEntries: 10,
|
|
maxAgeSeconds: 60 * 60 * 24 * 365,
|
|
}),
|
|
],
|
|
}),
|
|
);
|
|
|
|
registerRoute(
|
|
({ url }) => url.pathname.startsWith('/api/'),
|
|
new NetworkFirst({
|
|
cacheName: 'api-cache',
|
|
networkTimeoutSeconds: 10,
|
|
plugins: [
|
|
new ExpirationPlugin({
|
|
maxEntries: 50,
|
|
maxAgeSeconds: 60 * 60 * 24,
|
|
}),
|
|
],
|
|
}),
|
|
);
|
|
|
|
self.addEventListener('push', (event: PushEvent) => {
|
|
if (!event.data) {
|
|
return;
|
|
}
|
|
|
|
const data = event.data.json();
|
|
|
|
const options: NotificationOptions = {
|
|
body: data.body || '',
|
|
icon: data.icon || '/icon-192x192.png',
|
|
badge: '/icon-192x192.png',
|
|
data: data.data || {},
|
|
actions: data.actions || [],
|
|
};
|
|
|
|
event.waitUntil(
|
|
self.registration.showNotification(
|
|
data.title || 'DST Collection',
|
|
options,
|
|
),
|
|
);
|
|
});
|
|
|
|
self.addEventListener('notificationclick', (event: NotificationEvent) => {
|
|
event.notification.close();
|
|
|
|
const action = event.action;
|
|
const data = event.notification.data;
|
|
|
|
let url = '/';
|
|
|
|
if (action === 'view_category' && data.category_id) {
|
|
url = `/admin/master/categories`;
|
|
} else if (data.url) {
|
|
url = data.url;
|
|
}
|
|
|
|
event.waitUntil(
|
|
self.clients
|
|
.matchAll({ type: 'window', includeUncontrolled: true })
|
|
.then((clients) => {
|
|
for (const client of clients) {
|
|
if (client.url.includes(url) && 'focus' in client) {
|
|
return client.focus();
|
|
}
|
|
}
|
|
|
|
if (self.clients.openWindow) {
|
|
return self.clients.openWindow(url);
|
|
}
|
|
}),
|
|
);
|
|
});
|