220 lines
6.8 KiB
JavaScript
220 lines
6.8 KiB
JavaScript
// Service Worker pour Portail RH Inter Santé
|
|
const CACHE_NAME = 'inter-sante-portal-v1.1';
|
|
const OFFLINE_URL = '/offline.html';
|
|
|
|
// Ressources ESSENTIELLES à mettre en cache (vérifier l'existence)
|
|
const PRECACHE_URLS = [
|
|
'/',
|
|
'/Bootstrap_new/css/style_office.css',
|
|
'/Bootstrap_new/css/ux_enhancements.css',
|
|
'/Bootstrap_new/js/ux-manager.js',
|
|
'/Js/fonctions.js',
|
|
'/manifest.json',
|
|
'/Bootstrap_new/images/new/favicon.png'
|
|
];
|
|
|
|
// Installation - Pré-cache des ressources essentielles
|
|
self.addEventListener('install', event => {
|
|
event.waitUntil(
|
|
caches.open(CACHE_NAME)
|
|
.then(cache => {
|
|
console.log('[Service Worker] Pré-cache des ressources');
|
|
|
|
// Cache only resources that exist
|
|
const cachePromises = PRECACHE_URLS.map(url => {
|
|
return fetch(url, { mode: 'no-cors' })
|
|
.then(response => {
|
|
if (response.ok || response.type === 'opaque') {
|
|
return cache.put(url, response);
|
|
}
|
|
console.warn(`[SW] Resource not found: ${url}`);
|
|
return Promise.resolve();
|
|
})
|
|
.catch(error => {
|
|
console.warn(`[SW] Failed to cache ${url}:`, error);
|
|
return Promise.resolve();
|
|
});
|
|
});
|
|
|
|
return Promise.all(cachePromises);
|
|
})
|
|
.then(() => {
|
|
console.log('[Service Worker] Installation terminée');
|
|
return self.skipWaiting();
|
|
})
|
|
.catch(error => {
|
|
console.error('[Service Worker] Erreur installation:', error);
|
|
})
|
|
);
|
|
});
|
|
|
|
// Activation - Nettoyage des anciens caches
|
|
self.addEventListener('activate', event => {
|
|
event.waitUntil(
|
|
caches.keys().then(cacheNames => {
|
|
return Promise.all(
|
|
cacheNames.map(cacheName => {
|
|
if (cacheName !== CACHE_NAME) {
|
|
console.log('[Service Worker] Suppression ancien cache:', cacheName);
|
|
return caches.delete(cacheName);
|
|
}
|
|
})
|
|
);
|
|
}).then(() => {
|
|
console.log('[Service Worker] Activation terminée');
|
|
return self.clients.claim();
|
|
})
|
|
);
|
|
});
|
|
|
|
// Stratégie de cache: Stale-While-Revalidate
|
|
self.addEventListener('fetch', event => {
|
|
// Ignorer les requêtes non-GET
|
|
if (event.request.method !== 'GET') {
|
|
return;
|
|
}
|
|
|
|
// Ignorer les requêtes chrome-extension
|
|
if (event.request.url.includes('chrome-extension')) {
|
|
return;
|
|
}
|
|
|
|
// Pour les pages HTML: Network First avec fallback cache
|
|
if (event.request.headers.get('accept').includes('text/html')) {
|
|
event.respondWith(
|
|
fetch(event.request)
|
|
.then(response => {
|
|
// Vérifier si la réponse est valide
|
|
if (!response || response.status !== 200 || response.type === 'error') {
|
|
throw new Error('Network response was not ok');
|
|
}
|
|
|
|
// Cloner la réponse pour le cache
|
|
const responseToCache = response.clone();
|
|
caches.open(CACHE_NAME)
|
|
.then(cache => {
|
|
cache.put(event.request, responseToCache);
|
|
});
|
|
|
|
return response;
|
|
})
|
|
.catch(() => {
|
|
// Fallback au cache
|
|
return caches.match(event.request)
|
|
.then(cachedResponse => {
|
|
return cachedResponse || caches.match('/');
|
|
});
|
|
})
|
|
);
|
|
return;
|
|
}
|
|
|
|
// Pour les autres ressources: Cache First, fallback Network
|
|
event.respondWith(
|
|
caches.match(event.request)
|
|
.then(cachedResponse => {
|
|
if (cachedResponse) {
|
|
// Toujours rafraîchir le cache en arrière-plan
|
|
fetch(event.request)
|
|
.then(response => {
|
|
if (response && response.ok) {
|
|
caches.open(CACHE_NAME)
|
|
.then(cache => cache.put(event.request, response));
|
|
}
|
|
})
|
|
.catch(() => {}); // Ignorer les erreurs de mise à jour
|
|
|
|
return cachedResponse;
|
|
}
|
|
|
|
// Pas dans le cache, aller au réseau
|
|
return fetch(event.request)
|
|
.then(response => {
|
|
// Vérifier si nous avons reçu une réponse valide
|
|
if (!response || !response.ok) {
|
|
return response; // Retourner la réponse même si elle a échoué
|
|
}
|
|
|
|
// Mettre en cache la réponse pour la prochaine fois
|
|
const responseToCache = response.clone();
|
|
caches.open(CACHE_NAME)
|
|
.then(cache => {
|
|
cache.put(event.request, responseToCache);
|
|
});
|
|
|
|
return response;
|
|
})
|
|
.catch(error => {
|
|
console.error('[SW] Fetch failed:', error);
|
|
|
|
// Pour les CSS/JS, retourner des réponses de secours
|
|
const url = event.request.url;
|
|
if (url.includes('.css')) {
|
|
return new Response('/* Ressource temporairement indisponible */', {
|
|
headers: { 'Content-Type': 'text/css' }
|
|
});
|
|
}
|
|
if (url.includes('.js')) {
|
|
return new Response('// Ressource temporairement indisponible', {
|
|
headers: { 'Content-Type': 'application/javascript' }
|
|
});
|
|
}
|
|
|
|
// Pour les images, retourner une image de secours
|
|
if (url.includes('.png') || url.includes('.jpg') || url.includes('.svg')) {
|
|
return fetch('/Bootstrap_new/images/new/favicon.png')
|
|
.catch(() => {
|
|
// Si même l'icône de secours échoue, retourner une réponse vide
|
|
return new Response('', { status: 404 });
|
|
});
|
|
}
|
|
|
|
return new Response('Ressource non disponible hors ligne', {
|
|
headers: { 'Content-Type': 'text/plain' }
|
|
});
|
|
});
|
|
})
|
|
);
|
|
});
|
|
|
|
// Gestion des messages entre l'app et le Service Worker
|
|
self.addEventListener('message', event => {
|
|
if (event.data && event.data.type === 'SKIP_WAITING') {
|
|
self.skipWaiting();
|
|
}
|
|
|
|
if (event.data && event.data.type === 'GET_CACHE_STATUS') {
|
|
event.ports[0].postMessage({
|
|
cacheName: CACHE_NAME,
|
|
status: 'active'
|
|
});
|
|
}
|
|
});
|
|
|
|
// Gestion des notifications push (optionnel)
|
|
self.addEventListener('push', event => {
|
|
if (!event.data) return;
|
|
|
|
const data = event.data.json();
|
|
const options = {
|
|
body: data.body || 'Nouvelle notification',
|
|
icon: '/Bootstrap_new/images/new/favicon.png',
|
|
badge: '/Bootstrap_new/images/new/favicon.png',
|
|
vibrate: [200, 100, 200],
|
|
data: {
|
|
url: data.url || '/'
|
|
}
|
|
};
|
|
|
|
event.waitUntil(
|
|
self.registration.showNotification(data.title || 'Inter Santé', options)
|
|
);
|
|
});
|
|
|
|
self.addEventListener('notificationclick', event => {
|
|
event.notification.close();
|
|
|
|
event.waitUntil(
|
|
clients.openWindow(event.notification.data.url || '/')
|
|
);
|
|
}); |