feat(pwa): add auto-update on reopen, live tickers, and manual refresh to dashboards
This commit is contained in:
@@ -537,6 +537,8 @@ def generate_dashboard_html(engine: DatastoreEngine) -> str:
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover">
|
||||
<meta name="build-time" content="{now_berlin.isoformat()}">
|
||||
<meta name="build-epoch" content="{int(now_berlin.timestamp())}">
|
||||
<title>Moritz Health — Energiebilanz & Sport</title>
|
||||
|
||||
<!-- PWA & Mobile Web App Meta Tags -->
|
||||
@@ -587,6 +589,9 @@ def generate_dashboard_html(engine: DatastoreEngine) -> str:
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<button id="manual-refresh-btn" onclick="triggerManualRefresh()" title="Aktualisieren" class="inline-flex items-center justify-center p-2 rounded-lg bg-slate-100 hover:bg-slate-200 text-slate-600 hover:text-slate-900 border border-slate-200/80 transition active:scale-95 shadow-xs">
|
||||
<i data-lucide="refresh-cw" class="w-3.5 h-3.5"></i>
|
||||
</button>
|
||||
<button onclick="openModal('modal-today-meals')" class="inline-flex items-center gap-1.5 px-3 py-1.5 rounded-lg bg-sky-50 text-sky-700 hover:bg-sky-100 border border-sky-200/70 text-xs font-semibold shadow-xs transition">
|
||||
<i data-lucide="utensils" class="w-3.5 h-3.5"></i>
|
||||
<span>Heute ({today_count})</span>
|
||||
@@ -1106,6 +1111,91 @@ def generate_dashboard_html(engine: DatastoreEngine) -> str:
|
||||
document.addEventListener('DOMContentLoaded', () => {{
|
||||
lucide.createIcons();
|
||||
}});
|
||||
|
||||
// Service Worker Registration for PWA caching & offline support
|
||||
if ('serviceWorker' in navigator) {{
|
||||
window.addEventListener('load', () => {{
|
||||
navigator.serviceWorker.register('/family/sw.js', {{ scope: '/family/' }})
|
||||
.then(reg => console.log('[PWA] Service Worker registered:', reg.scope))
|
||||
.catch(err => console.warn('[PWA] Service Worker registration failed:', err));
|
||||
}});
|
||||
}}
|
||||
|
||||
// ==============================================================================
|
||||
// Self-Updating Engine
|
||||
// ==============================================================================
|
||||
(function() {{
|
||||
const currentBuildEpoch = parseInt(document.querySelector('meta[name="build-epoch"]')?.content || '0', 10);
|
||||
let lastCheckMs = Date.now();
|
||||
let isChecking = false;
|
||||
|
||||
// 1. Server Update Checker
|
||||
async function checkForUpdates() {{
|
||||
if (isChecking) return;
|
||||
isChecking = true;
|
||||
try {{
|
||||
const res = await fetch(window.location.pathname + '?_poll=' + Date.now(), {{
|
||||
cache: 'no-store',
|
||||
headers: {{ 'Cache-Control': 'no-cache, no-store, must-revalidate', 'Pragma': 'no-cache' }}
|
||||
}});
|
||||
if (res.ok) {{
|
||||
const html = await res.text();
|
||||
const parser = new DOMParser();
|
||||
const doc = parser.parseFromString(html, 'text/html');
|
||||
const remoteEpoch = parseInt(doc.querySelector('meta[name="build-epoch"]')?.content || '0', 10);
|
||||
|
||||
if (remoteEpoch && currentBuildEpoch && remoteEpoch > currentBuildEpoch) {{
|
||||
console.log('[AutoUpdate] Server has newer build (' + remoteEpoch + ' > ' + currentBuildEpoch + '). Reloading...');
|
||||
window.location.reload();
|
||||
return;
|
||||
}}
|
||||
}}
|
||||
}} catch (err) {{
|
||||
console.warn('[AutoUpdate] Check failed:', err);
|
||||
}} finally {{
|
||||
isChecking = false;
|
||||
lastCheckMs = Date.now();
|
||||
}}
|
||||
}}
|
||||
|
||||
// 2. Auto-update on reopen / foreground resume (PWA & Mobile Safari)
|
||||
document.addEventListener('visibilitychange', () => {{
|
||||
if (document.visibilityState === 'visible') {{
|
||||
if (Date.now() - lastCheckMs > 10000) {{
|
||||
checkForUpdates();
|
||||
}}
|
||||
}}
|
||||
}});
|
||||
|
||||
window.addEventListener('pageshow', (e) => {{
|
||||
if (e.persisted || Date.now() - lastCheckMs > 10000) {{
|
||||
checkForUpdates();
|
||||
}}
|
||||
}});
|
||||
|
||||
window.addEventListener('focus', () => {{
|
||||
if (Date.now() - lastCheckMs > 15000) {{
|
||||
checkForUpdates();
|
||||
}}
|
||||
}});
|
||||
|
||||
// 3. Background check every 30 seconds when visible
|
||||
setInterval(() => {{
|
||||
if (document.visibilityState === 'visible') {{
|
||||
checkForUpdates();
|
||||
}}
|
||||
}}, 30000);
|
||||
|
||||
// 4. Manual refresh trigger
|
||||
window.triggerManualRefresh = function() {{
|
||||
const btn = document.getElementById('manual-refresh-btn');
|
||||
if (btn) {{
|
||||
const icon = btn.querySelector('svg') || btn.querySelector('i');
|
||||
if (icon) icon.classList.add('animate-spin');
|
||||
}}
|
||||
window.location.reload();
|
||||
}};
|
||||
}})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user