feat: Implement push notifications in Budget Manager PWA
- Added functionality for subscribing to push notifications in Settings.vue. - Integrated service worker registration and notification permission requests. - Enhanced Vite configuration for PWA with manifest and caching strategies. - Created a script for generating PDF reports. - Added project report markdown file detailing the PWA implementation and features.
This commit is contained in:
+105
-9
@@ -110,24 +110,120 @@ self.addEventListener("sync", (event) => {
|
||||
|
||||
// Push notification handler
|
||||
self.addEventListener("push", (event) => {
|
||||
const data = event.data.json();
|
||||
|
||||
let data;
|
||||
try {
|
||||
data = event.data.json();
|
||||
} catch (error) {
|
||||
// If the data is not JSON, try to get it as text
|
||||
data = {
|
||||
message: event.data ? event.data.text() : "New notification",
|
||||
additionalData: {}
|
||||
};
|
||||
}
|
||||
|
||||
// Format transaction type for display
|
||||
let messageText = data.message || "New transaction";
|
||||
|
||||
// Default notification options
|
||||
const options = {
|
||||
body: data.body,
|
||||
body: messageText,
|
||||
icon: "/icons/icon-192px.jpg",
|
||||
badge: "/icons/badge-96x96.png",
|
||||
data: data.data,
|
||||
actions: data.actions || [],
|
||||
badge: "/icons/icon-192px.jpg",
|
||||
vibrate: [100, 50, 100],
|
||||
data: data.additionalData || {},
|
||||
actions: [
|
||||
{
|
||||
action: 'view',
|
||||
title: 'View Details'
|
||||
}
|
||||
],
|
||||
// Tag transactions by ID to prevent duplicate notifications
|
||||
tag: data.additionalData?.transactionId || 'transaction'
|
||||
};
|
||||
|
||||
event.waitUntil(self.registration.showNotification(data.title, options));
|
||||
|
||||
// Show different icons based on transaction type
|
||||
if (data.additionalData?.type === 'income') {
|
||||
options.icon = "/icons/income-icon.jpg";
|
||||
} else if (data.additionalData?.type === 'expense') {
|
||||
options.icon = "/icons/expense-icon.jpg";
|
||||
}
|
||||
|
||||
console.log('Showing notification:', messageText);
|
||||
|
||||
// Forward to any open clients
|
||||
forwardNotificationToClients(data);
|
||||
|
||||
// Show system notification
|
||||
event.waitUntil(self.registration.showNotification("Budget Manager", options));
|
||||
});
|
||||
|
||||
// Notification click handler
|
||||
self.addEventListener("notificationclick", (event) => {
|
||||
event.notification.close();
|
||||
|
||||
// Get transaction ID from notification data
|
||||
const transactionId = event.notification.data?.transactionId;
|
||||
|
||||
// Handle different notification actions
|
||||
if (event.action === 'view' && transactionId) {
|
||||
// Open transaction details page
|
||||
event.waitUntil(
|
||||
clients.matchAll({type: 'window'})
|
||||
.then(clientList => {
|
||||
// Check if there is already a window open
|
||||
for (const client of clientList) {
|
||||
if (client.url.includes('/') && 'focus' in client) {
|
||||
client.navigate(`/edit/${transactionId}`);
|
||||
return client.focus();
|
||||
}
|
||||
}
|
||||
// If no window is open, open a new one
|
||||
return clients.openWindow(`/edit/${transactionId}`);
|
||||
})
|
||||
);
|
||||
} else {
|
||||
// Default: open the app
|
||||
event.waitUntil(
|
||||
clients.matchAll({type: 'window'})
|
||||
.then(clientList => {
|
||||
for (const client of clientList) {
|
||||
if (client.url.includes('/') && 'focus' in client) {
|
||||
return client.focus();
|
||||
}
|
||||
}
|
||||
return clients.openWindow('/');
|
||||
})
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
event.waitUntil(clients.openWindow("/"));
|
||||
// Forward push notifications to all clients
|
||||
function forwardNotificationToClients(data) {
|
||||
self.clients.matchAll().then(clients => {
|
||||
clients.forEach(client => {
|
||||
// Send message to client
|
||||
client.postMessage({
|
||||
type: 'PUSH_NOTIFICATION',
|
||||
title: 'Budget Manager',
|
||||
body: data.message,
|
||||
transactionId: data.additionalData?.transactionId,
|
||||
type: data.additionalData?.type
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Listen for messages from clients
|
||||
self.addEventListener('message', (event) => {
|
||||
if (event.data && event.data.type === 'GET_AUTH_TOKEN') {
|
||||
// Token request from service worker
|
||||
self.clients.matchAll().then(clients => {
|
||||
if (clients.length > 0) {
|
||||
const token = localStorage.getItem('token');
|
||||
event.ports[0].postMessage({ token });
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Sync transactions with the server
|
||||
|
||||
Reference in New Issue
Block a user