161 lines
4.1 KiB
JavaScript
161 lines
4.1 KiB
JavaScript
const CACHE_NAME = 'fina-v1';
|
|
const STATIC_CACHE = 'fina-static-v1';
|
|
const DYNAMIC_CACHE = 'fina-dynamic-v1';
|
|
|
|
// Assets to cache on install
|
|
const STATIC_ASSETS = [
|
|
'/',
|
|
'/static/css/style.css',
|
|
'/static/js/script.js',
|
|
'/static/js/chart.min.js',
|
|
'/static/images/fina-logo.png'
|
|
];
|
|
|
|
// Install event - cache static assets
|
|
self.addEventListener('install', event => {
|
|
console.log('[Service Worker] Installing...');
|
|
event.waitUntil(
|
|
caches.open(STATIC_CACHE)
|
|
.then(cache => {
|
|
console.log('[Service Worker] Caching static assets');
|
|
return cache.addAll(STATIC_ASSETS);
|
|
})
|
|
.then(() => self.skipWaiting())
|
|
);
|
|
});
|
|
|
|
// Activate event - clean up old caches
|
|
self.addEventListener('activate', event => {
|
|
console.log('[Service Worker] Activating...');
|
|
event.waitUntil(
|
|
caches.keys().then(cacheNames => {
|
|
return Promise.all(
|
|
cacheNames
|
|
.filter(name => name !== STATIC_CACHE && name !== DYNAMIC_CACHE)
|
|
.map(name => caches.delete(name))
|
|
);
|
|
}).then(() => self.clients.claim())
|
|
);
|
|
});
|
|
|
|
// Fetch event - network first, then cache
|
|
self.addEventListener('fetch', event => {
|
|
const { request } = event;
|
|
|
|
// Skip non-GET requests
|
|
if (request.method !== 'GET') {
|
|
return;
|
|
}
|
|
|
|
// Skip chrome extension and other non-http(s) requests
|
|
if (!request.url.startsWith('http')) {
|
|
return;
|
|
}
|
|
|
|
// API requests - network first, cache fallback
|
|
if (request.url.includes('/api/')) {
|
|
event.respondWith(
|
|
fetch(request)
|
|
.then(response => {
|
|
const responseClone = response.clone();
|
|
caches.open(DYNAMIC_CACHE).then(cache => {
|
|
cache.put(request, responseClone);
|
|
});
|
|
return response;
|
|
})
|
|
.catch(() => caches.match(request))
|
|
);
|
|
return;
|
|
}
|
|
|
|
// Static assets - cache first, network fallback
|
|
if (
|
|
request.url.includes('/static/') ||
|
|
request.url.endsWith('.css') ||
|
|
request.url.endsWith('.js') ||
|
|
request.url.endsWith('.png') ||
|
|
request.url.endsWith('.jpg') ||
|
|
request.url.endsWith('.jpeg') ||
|
|
request.url.endsWith('.gif') ||
|
|
request.url.endsWith('.svg')
|
|
) {
|
|
event.respondWith(
|
|
caches.match(request)
|
|
.then(cachedResponse => {
|
|
if (cachedResponse) {
|
|
return cachedResponse;
|
|
}
|
|
return fetch(request).then(response => {
|
|
const responseClone = response.clone();
|
|
caches.open(STATIC_CACHE).then(cache => {
|
|
cache.put(request, responseClone);
|
|
});
|
|
return response;
|
|
});
|
|
})
|
|
);
|
|
return;
|
|
}
|
|
|
|
// HTML pages - network first, cache fallback
|
|
event.respondWith(
|
|
fetch(request)
|
|
.then(response => {
|
|
const responseClone = response.clone();
|
|
caches.open(DYNAMIC_CACHE).then(cache => {
|
|
cache.put(request, responseClone);
|
|
});
|
|
return response;
|
|
})
|
|
.catch(() => {
|
|
return caches.match(request).then(cachedResponse => {
|
|
if (cachedResponse) {
|
|
return cachedResponse;
|
|
}
|
|
// Return offline page if available
|
|
return caches.match('/');
|
|
});
|
|
})
|
|
);
|
|
});
|
|
|
|
// Handle messages from clients
|
|
self.addEventListener('message', event => {
|
|
if (event.data && event.data.type === 'SKIP_WAITING') {
|
|
self.skipWaiting();
|
|
}
|
|
});
|
|
|
|
// Background sync for offline form submissions
|
|
self.addEventListener('sync', event => {
|
|
if (event.tag === 'sync-expenses') {
|
|
event.waitUntil(syncExpenses());
|
|
}
|
|
});
|
|
|
|
async function syncExpenses() {
|
|
// Placeholder for syncing offline data
|
|
console.log('[Service Worker] Syncing expenses...');
|
|
}
|
|
|
|
// Push notifications support (for future feature)
|
|
self.addEventListener('push', event => {
|
|
const options = {
|
|
body: event.data ? event.data.text() : 'New notification from FINA',
|
|
icon: '/static/images/fina-logo.png',
|
|
badge: '/static/images/fina-logo.png',
|
|
vibrate: [200, 100, 200]
|
|
};
|
|
|
|
event.waitUntil(
|
|
self.registration.showNotification('FINA', options)
|
|
);
|
|
});
|
|
|
|
// Notification click handler
|
|
self.addEventListener('notificationclick', event => {
|
|
event.notification.close();
|
|
event.waitUntil(
|
|
clients.openWindow('/')
|
|
);
|
|
});
|