veza/apps/web/src/components/OfflineIndicator.tsx

88 lines
2.8 KiB
TypeScript
Raw Normal View History

import { useEffect, useState } from 'react';
import { useOnlineStatus } from '@/hooks/useOnlineStatus';
import { offlineQueue } from '@/services/offlineQueue';
import { WifiOff, Wifi, Loader2 } from 'lucide-react';
/**
* Composant pour afficher un indicateur de mode hors ligne avec nombre de requêtes en attente
*/
export function OfflineIndicator() {
const isOnline = useOnlineStatus();
const [queueSize, setQueueSize] = useState(0);
const [isProcessing, setIsProcessing] = useState(false);
// Mettre à jour la taille de la file d'attente
useEffect(() => {
const updateQueueSize = () => {
setQueueSize(offlineQueue.getQueueSize());
};
// Mettre à jour immédiatement
updateQueueSize();
// Mettre à jour toutes les secondes
const interval = setInterval(updateQueueSize, 1000);
return () => clearInterval(interval);
}, []);
// Vérifier si la file est en cours de traitement
useEffect(() => {
if (isOnline && queueSize > 0) {
setIsProcessing(true);
// Vérifier périodiquement si le traitement est terminé
const checkProcessing = setInterval(() => {
const currentSize = offlineQueue.getQueueSize();
if (currentSize === 0) {
setIsProcessing(false);
clearInterval(checkProcessing);
}
}, 500);
return () => clearInterval(checkProcessing);
} else {
setIsProcessing(false);
}
}, [isOnline, queueSize]);
// Ne rien afficher si en ligne et aucune requête en attente
if (isOnline && queueSize === 0 && !isProcessing) {
return null;
}
// Mode hors ligne
if (!isOnline) {
return (
<div className="fixed top-0 left-0 right-0 bg-kodo-red/90 backdrop-blur-sm text-white px-4 py-2.5 text-sm z-50 flex items-center justify-center gap-2 shadow-lg border-b border-kodo-red">
<WifiOff className="w-4 h-4" />
<span>
Mode hors ligne
{queueSize > 0 && (
<span className="ml-2 font-semibold">
- {queueSize} {queueSize === 1 ? 'requête' : 'requêtes'} en attente
</span>
)}
</span>
</div>
);
}
// En ligne mais traitement de la file en cours
if (isProcessing && queueSize > 0) {
return (
<div className="fixed top-0 left-0 right-0 bg-kodo-cyan/90 backdrop-blur-sm text-kodo-void px-4 py-2.5 text-sm z-50 flex items-center justify-center gap-2 shadow-lg border-b border-kodo-cyan">
<Loader2 className="w-4 h-4 animate-spin" />
<span>
Synchronisation en cours
{queueSize > 0 && (
<span className="ml-2 font-semibold">
- {queueSize} {queueSize === 1 ? 'requête' : 'requêtes'} restante{queueSize > 1 ? 's' : ''}
</span>
)}
</span>
</div>
);
}
return null;
}