fix: robust SW status tracking and polling for mobile production

This commit is contained in:
2025-12-21 00:33:50 +01:00
parent ab8f0fe3ef
commit 4e8af60488
2 changed files with 61 additions and 28 deletions

View File

@@ -10,8 +10,18 @@ export default function OfflineIndicator() {
useEffect(() => {
setIsOffline(!navigator.onLine);
const savedReady = localStorage.getItem('whisky_offline_ready') === 'true';
setIsReady(savedReady);
// 🧼 Clean up legacy keys and check for ready state
const checkLocalReady = () => {
const ready = localStorage.getItem('whisky_offline_ready') === 'true' ||
localStorage.getItem('whisky_bunker_ready') === 'true';
if (ready) {
setIsReady(true);
// Standardize on the new key
localStorage.setItem('whisky_offline_ready', 'true');
}
};
checkLocalReady();
const handleOnline = () => setIsOffline(false);
const handleOffline = () => setIsOffline(true);
@@ -37,30 +47,48 @@ export default function OfflineIndicator() {
window.addEventListener('online', handleOnline);
window.addEventListener('offline', handleOffline);
const queryStatus = async () => {
if (!('serviceWorker' in navigator)) return;
try {
const registration = await navigator.serviceWorker.getRegistration();
if (registration) {
// Try to talk to ANY available worker (installing, waiting, or active)
const sw = registration.installing || registration.waiting || registration.active;
if (sw) {
sw.postMessage({ type: 'CHECK_OFFLINE_STATUS' });
}
}
} catch (e) {
console.error('PWA: Status query failed', e);
}
};
if ('serviceWorker' in navigator) {
navigator.serviceWorker.addEventListener('message', handleMessage);
queryStatus();
// Proactive status check
navigator.serviceWorker.ready.then(() => {
// If there's an active or installing worker, ask for status
const sw = navigator.serviceWorker.controller ||
(navigator.serviceWorker as any).installing ||
(navigator.serviceWorker as any).waiting;
if (sw) {
sw.postMessage({ type: 'CHECK_OFFLINE_STATUS' });
// 🔄 ROBUST POLLING: If not ready and progress is 0, query periodically
// This handles cases where the SW was suspended or the first broadcast was missed.
const interval = setInterval(() => {
if (!isReady && progress < 100) {
queryStatus();
}
});
}, 3000);
return () => {
window.removeEventListener('online', handleOnline);
window.removeEventListener('offline', handleOffline);
navigator.serviceWorker.removeEventListener('message', handleMessage);
clearInterval(interval);
};
}
return () => {
window.removeEventListener('online', handleOnline);
window.removeEventListener('offline', handleOffline);
if ('serviceWorker' in navigator) {
navigator.serviceWorker.removeEventListener('message', handleMessage);
}
};
}, []);
}, [isReady, progress]);
if (isOffline) {
return (
@@ -84,10 +112,10 @@ export default function OfflineIndicator() {
}
return (
<div className="flex items-center gap-1.5 px-2.5 py-1 bg-amber-600/10 border border-amber-600/20 rounded-full">
<div className="flex items-center gap-1.5 px-2.5 py-1 bg-amber-600/10 border border-amber-600/20 rounded-full animate-in fade-in slide-in-from-right-2">
<Loader2 size={10} className="text-amber-600 animate-spin" />
<span className="text-[9px] font-black uppercase tracking-widest text-amber-600">
{progress > 0 ? `Lade Offline-Daten... ${progress}%` : 'Vorbereiten...'}
{progress > 0 ? `Vorbereitung... ${progress}%` : 'Warte auf System...'}
</span>
</div>
);