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:
2025-05-23 23:54:46 +02:00
parent 26e3b76b11
commit 8681aa88af
37 changed files with 7034 additions and 85 deletions
+105 -9
View File
@@ -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