data-flow: integrate offline queue UI with OfflineIndicator

- Added state to manage queue manager dialog visibility
- Added 'View Queue' button in offline mode banner (when queueSize > 0)
- Added 'View Queue' button in processing mode banner (when queueSize > 0)
- Button opens OfflineQueueManager dialog when clicked
- Button styled appropriately for each banner variant
- Users can now view and manage queued requests directly from the indicator
- Action 2.5.1.5 complete
This commit is contained in:
senke 2026-01-15 18:02:40 +01:00
parent 244f2a8ca9
commit 784a8add88
2 changed files with 67 additions and 24 deletions

View file

@ -789,11 +789,20 @@ Critical path dependencies:
- UI shows queued requests correctly
- **Rollback**: Delete component
- [ ] **Action 2.5.1.5**: Integrate offline queue UI with OfflineIndicator
- [x] **Action 2.5.1.5**: Integrate offline queue UI with OfflineIndicator
- **Scope**: `apps/web/src/components/OfflineIndicator.tsx` - Show queue status, link to manager
- **Dependencies**: Action 2.5.1.4 complete
- **Dependencies**: Action 2.5.1.4 complete
- **Risk**: LOW 🔒
- **Validation**: Indicator shows queue status
- **Validation**: ✅ Integrated OfflineQueueManager with OfflineIndicator:
- Added state to manage queue manager dialog visibility
- Added "View Queue" button in offline mode banner (when queueSize > 0)
- Added "View Queue" button in processing mode banner (when queueSize > 0)
- Button opens OfflineQueueManager dialog when clicked
- Button styled appropriately for each banner variant (red for offline, cyan for processing)
- Imported OfflineQueueManager component
- Imported List icon from lucide-react for button
- Indicator shows queue status and provides access to queue manager
- Users can now view and manage queued requests directly from the indicator
- **Rollback**: Remove queue status
- [x] **Action 2.5.1.6**: Test request deduplication works correctly

View file

@ -1,8 +1,9 @@
import { useEffect, useState } from 'react';
import { useOnlineStatus } from '@/hooks/useOnlineStatus';
import { offlineQueue } from '@/services/offlineQueue';
import { WifiOff, Loader2 } from 'lucide-react';
import { WifiOff, Loader2, List } from 'lucide-react';
import { hasRecentNetworkError } from '@/utils/networkErrorTracker';
import { OfflineQueueManager } from './OfflineQueueManager';
/**
* Composant pour afficher un indicateur de mode hors ligne avec nombre de requêtes en attente
@ -12,6 +13,7 @@ export function OfflineIndicator() {
const [queueSize, setQueueSize] = useState(0);
const [isProcessing, setIsProcessing] = useState(false);
const [hasNetworkError, setHasNetworkError] = useState(false);
const [showQueueManager, setShowQueueManager] = useState(false);
// Mettre à jour la taille de la file d'attente
useEffect(() => {
@ -70,36 +72,68 @@ export function OfflineIndicator() {
// Mode hors ligne ou erreur réseau récente
if (!isOnline || hasNetworkError) {
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
<>
<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>
{queueSize > 0 && (
<span className="ml-2 font-semibold">
- {queueSize} {queueSize === 1 ? 'requête' : 'requêtes'} en
attente
</span>
<button
onClick={() => setShowQueueManager(true)}
className="ml-3 px-2 py-1 bg-white/10 hover:bg-white/20 rounded border border-white/20 transition-colors flex items-center gap-1.5 text-xs font-medium"
title="View queued requests"
>
<List className="w-3.5 h-3.5" />
View Queue
</button>
)}
</span>
</div>
</div>
<OfflineQueueManager
open={showQueueManager}
onClose={() => setShowQueueManager(false)}
/>
</>
);
}
// 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
<>
<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>
{queueSize > 0 && (
<span className="ml-2 font-semibold">
- {queueSize} {queueSize === 1 ? 'requête' : 'requêtes'} restante
{queueSize > 1 ? 's' : ''}
</span>
<button
onClick={() => setShowQueueManager(true)}
className="ml-3 px-2 py-1 bg-kodo-void/20 hover:bg-kodo-void/30 rounded border border-kodo-void/30 transition-colors flex items-center gap-1.5 text-xs font-medium"
title="View queued requests"
>
<List className="w-3.5 h-3.5" />
View Queue
</button>
)}
</span>
</div>
</div>
<OfflineQueueManager
open={showQueueManager}
onClose={() => setShowQueueManager(false)}
/>
</>
);
}