- ✅ Herramientas nuevas: * Temporizador de RCP con alertas cada 2 minutos * Calculadora de Duración de Botella de Oxígeno * Calculadora de Goteo (gotas/min y ml/h) * Tabla de perfusión Adrenalina agregada - ✅ Actualización Protocolo RCP: * Orden actualizado: Comprobar consciencia → Llamar 112 → Iniciar RCP * Aplicado a RCP Adulto SVB y Pediátrico - ✅ Cambios UI: * Botones de emergencias críticas con fondo negro y texto blanco * Enlaces de códigos corregidos - ✅ Medicación TES: * Nueva sección separada para medicación autorizada bajo prescripción * Aviso legal prominente * Sin dosis ni decisiones clínicas - ✅ Correcciones: * Errores de sintaxis JSX corregidos (símbolos < y >) * Favicon SVG actualizado * GitHub Pages configurado correctamente
148 lines
3.7 KiB
JavaScript
148 lines
3.7 KiB
JavaScript
// Service Worker para PWA
|
|
// Cache First Strategy para funcionamiento offline
|
|
|
|
const CACHE_NAME = 'emerges-tes-v1';
|
|
const RUNTIME_CACHE = 'emerges-tes-runtime-v1';
|
|
|
|
// Archivos estáticos a cachear en la instalación
|
|
const STATIC_ASSETS = [
|
|
'/',
|
|
'/index.html',
|
|
'/manifest.json',
|
|
'/favicon.ico',
|
|
];
|
|
|
|
// Instalación del Service Worker
|
|
self.addEventListener('install', (event) => {
|
|
console.log('[SW] Installing service worker...');
|
|
|
|
event.waitUntil(
|
|
caches.open(CACHE_NAME)
|
|
.then((cache) => {
|
|
console.log('[SW] Caching static assets');
|
|
return cache.addAll(STATIC_ASSETS);
|
|
})
|
|
.then(() => self.skipWaiting()) // Activar inmediatamente
|
|
);
|
|
});
|
|
|
|
// Activación del Service Worker
|
|
self.addEventListener('activate', (event) => {
|
|
console.log('[SW] Activating service worker...');
|
|
|
|
event.waitUntil(
|
|
caches.keys().then((cacheNames) => {
|
|
return Promise.all(
|
|
cacheNames
|
|
.filter((cacheName) => {
|
|
// Eliminar caches antiguos
|
|
return cacheName !== CACHE_NAME && cacheName !== RUNTIME_CACHE;
|
|
})
|
|
.map((cacheName) => {
|
|
console.log('[SW] Deleting old cache:', cacheName);
|
|
return caches.delete(cacheName);
|
|
})
|
|
);
|
|
})
|
|
.then(() => self.clients.claim()) // Tomar control de todas las páginas
|
|
);
|
|
});
|
|
|
|
// Interceptar peticiones
|
|
self.addEventListener('fetch', (event) => {
|
|
const { request } = event;
|
|
const url = new URL(request.url);
|
|
|
|
// Ignorar peticiones no GET
|
|
if (request.method !== 'GET') {
|
|
return;
|
|
}
|
|
|
|
// Ignorar peticiones a APIs externas (si las hay)
|
|
if (url.origin !== location.origin) {
|
|
return;
|
|
}
|
|
|
|
// Estrategia: Cache First para assets estáticos
|
|
if (
|
|
request.destination === 'script' ||
|
|
request.destination === 'style' ||
|
|
request.destination === 'image' ||
|
|
request.destination === 'font' ||
|
|
url.pathname.endsWith('.md')
|
|
) {
|
|
event.respondWith(cacheFirst(request));
|
|
} else {
|
|
// Network First para HTML y otros
|
|
event.respondWith(networkFirst(request));
|
|
}
|
|
});
|
|
|
|
// Cache First Strategy
|
|
async function cacheFirst(request) {
|
|
const cache = await caches.open(CACHE_NAME);
|
|
const cached = await cache.match(request);
|
|
|
|
if (cached) {
|
|
return cached;
|
|
}
|
|
|
|
try {
|
|
const response = await fetch(request);
|
|
if (response.ok) {
|
|
cache.put(request, response.clone());
|
|
}
|
|
return response;
|
|
} catch (error) {
|
|
console.error('[SW] Fetch failed:', error);
|
|
// Si es una imagen, retornar una imagen placeholder
|
|
if (request.destination === 'image') {
|
|
return new Response('', { status: 404 });
|
|
}
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
// Network First Strategy
|
|
async function networkFirst(request) {
|
|
const cache = await caches.open(RUNTIME_CACHE);
|
|
|
|
try {
|
|
const response = await fetch(request);
|
|
if (response.ok) {
|
|
cache.put(request, response.clone());
|
|
}
|
|
return response;
|
|
} catch (error) {
|
|
console.log('[SW] Network failed, trying cache:', error);
|
|
const cached = await cache.match(request);
|
|
if (cached) {
|
|
return cached;
|
|
}
|
|
// Si no hay cache y estamos offline, retornar index.html para SPA
|
|
if (request.mode === 'navigate') {
|
|
const indexCache = await caches.open(CACHE_NAME);
|
|
const indexHtml = await indexCache.match('/index.html');
|
|
if (indexHtml) {
|
|
return indexHtml;
|
|
}
|
|
}
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
// Manejar mensajes del cliente
|
|
self.addEventListener('message', (event) => {
|
|
if (event.data && event.data.type === 'SKIP_WAITING') {
|
|
self.skipWaiting();
|
|
}
|
|
|
|
if (event.data && event.data.type === 'CACHE_URLS') {
|
|
event.waitUntil(
|
|
caches.open(CACHE_NAME).then((cache) => {
|
|
return cache.addAll(event.data.urls);
|
|
})
|
|
);
|
|
}
|
|
});
|