feat: add Offline Mode Indicator (Bunker Status)

This commit is contained in:
2025-12-20 23:51:16 +01:00
parent 7d5091a139
commit b0a79541b6
2 changed files with 77 additions and 5 deletions

View File

@@ -1,32 +1,84 @@
'use client';
import React, { useState, useEffect } from 'react';
import { WifiOff } from 'lucide-react';
import { WifiOff, ShieldCheck } from 'lucide-react';
export default function OfflineIndicator() {
const [isOffline, setIsOffline] = useState(false);
const [isBunkerReady, setIsBunkerReady] = useState(false);
useEffect(() => {
setIsOffline(!navigator.onLine);
// Check if bunker was already ready from previous session
const savedReady = localStorage.getItem('whisky_bunker_ready') === 'true';
setIsBunkerReady(savedReady);
const handleOnline = () => setIsOffline(false);
const handleOffline = () => setIsOffline(true);
const handleMessage = (event: MessageEvent) => {
if (event.data?.type === 'PRECACHE_COMPLETE' || event.data?.type === 'BUNKER_STATUS') {
console.log('🛡️ PWA: Bunker is ready for offline use!');
setIsBunkerReady(true);
localStorage.setItem('whisky_bunker_ready', 'true');
}
};
window.addEventListener('online', handleOnline);
window.addEventListener('offline', handleOffline);
if ('serviceWorker' in navigator) {
navigator.serviceWorker.addEventListener('message', handleMessage);
// Proactively check status if SW is already active
if (navigator.serviceWorker.controller) {
navigator.serviceWorker.controller.postMessage({ type: 'CHECK_BUNKER_STATUS' });
}
}
return () => {
window.removeEventListener('online', handleOnline);
window.removeEventListener('offline', handleOffline);
if ('serviceWorker' in navigator) {
navigator.serviceWorker.removeEventListener('message', handleMessage);
}
};
}, []);
if (!isOffline) return null;
if (isOffline) {
return (
<div className="fixed top-0 left-0 w-full bg-red-600 text-white text-[10px] font-black uppercase tracking-widest py-1 flex items-center justify-center gap-2 z-[9999] animate-pulse">
<WifiOff size={12} />
Offline-Modus: Bunker aktiv 🛡
</div>
);
}
if (isBunkerReady) {
return (
<div className="fixed bottom-20 right-4 z-[90] animate-in fade-in slide-in-from-right-4 duration-500">
<div className="bg-zinc-900/80 backdrop-blur-md border border-green-500/30 px-3 py-1.5 rounded-full flex items-center gap-2 shadow-lg shadow-green-500/10 group hover:bg-zinc-900 transition-colors cursor-help">
<ShieldCheck size={14} className="text-green-500" />
<span className="text-[9px] font-black uppercase tracking-widest text-zinc-300">
Bunker Aktiv
</span>
<div className="absolute bottom-full right-0 mb-2 w-48 p-2 bg-zinc-900 text-[10px] text-zinc-400 rounded-xl border border-white/10 opacity-0 group-hover:opacity-100 transition-opacity pointer-events-none shadow-2xl">
Die App ist vollständig im "Bunker" gespeichert und funktioniert auch ohne Internet.
</div>
</div>
</div>
);
}
// Show nothing if online and not ready yet (or show a loading state?)
return (
<div className="fixed top-0 left-0 w-full bg-red-600 text-white text-[10px] font-black uppercase tracking-widest py-1 flex items-center justify-center gap-2 z-[9999] animate-pulse">
<WifiOff size={12} />
Offline-Modus: Du siehst eine gespeicherte Version
<div className="fixed bottom-20 right-4 z-[90] animate-in fade-in slide-in-from-right-4">
<div className="bg-zinc-900/80 backdrop-blur-md border border-amber-500/30 px-3 py-1.5 rounded-full flex items-center gap-2 shadow-lg shadow-amber-500/10">
<div className="w-1.5 h-1.5 bg-amber-500 rounded-full animate-pulse" />
<span className="text-[9px] font-black uppercase tracking-widest text-zinc-300">
Bunker wird geladen...
</span>
</div>
</div>
);
}