import { useState, useEffect, useCallback } from 'react'; import { QueuedSubmission } from '@/components/submission/SubmissionQueueIndicator'; import { useNetworkStatus } from './useNetworkStatus'; import { getPendingSubmissions, processQueue, removeFromQueue, clearQueue as clearQueueStorage, getPendingCount, } from '@/lib/submissionQueue'; import { logger } from '@/lib/logger'; interface UseSubmissionQueueOptions { autoRetry?: boolean; retryDelayMs?: number; maxRetries?: number; } export function useSubmissionQueue(options: UseSubmissionQueueOptions = {}) { const { autoRetry = true, retryDelayMs = 5000, maxRetries = 3, } = options; const [queuedItems, setQueuedItems] = useState([]); const [lastSyncTime, setLastSyncTime] = useState(null); const [nextRetryTime, setNextRetryTime] = useState(null); const { isOnline } = useNetworkStatus(); // Load queued items from IndexedDB on mount useEffect(() => { loadQueueFromStorage(); }, []); // Auto-retry when back online useEffect(() => { if (isOnline && autoRetry && queuedItems.length > 0) { const timer = setTimeout(() => { retryAll(); }, retryDelayMs); setNextRetryTime(new Date(Date.now() + retryDelayMs)); return () => clearTimeout(timer); } }, [isOnline, autoRetry, queuedItems.length, retryDelayMs]); const loadQueueFromStorage = useCallback(async () => { try { const pending = await getPendingSubmissions(); // Transform to QueuedSubmission format const items: QueuedSubmission[] = pending.map(item => ({ id: item.id, type: item.type, entityName: item.data?.name || item.data?.title || 'Unknown', timestamp: new Date(item.timestamp), status: item.retries >= 3 ? 'failed' : (item.lastAttempt ? 'retrying' : 'pending'), retryCount: item.retries, error: item.error || undefined, })); setQueuedItems(items); logger.info('[SubmissionQueue] Loaded queue', { count: items.length }); } catch (error) { logger.error('[SubmissionQueue] Failed to load queue', { error }); } }, []); const retryItem = useCallback(async (id: string) => { setQueuedItems(prev => prev.map(item => item.id === id ? { ...item, status: 'retrying' as const } : item ) ); try { // Placeholder: Retry the submission // await retrySubmission(id); // Remove from queue on success setQueuedItems(prev => prev.filter(item => item.id !== id)); setLastSyncTime(new Date()); } catch (error) { // Mark as failed setQueuedItems(prev => prev.map(item => item.id === id ? { ...item, status: 'failed' as const, retryCount: (item.retryCount || 0) + 1, error: error instanceof Error ? error.message : 'Unknown error', } : item ) ); } }, []); const retryAll = useCallback(async () => { const pendingItems = queuedItems.filter( item => item.status === 'pending' || item.status === 'failed' ); for (const item of pendingItems) { if ((item.retryCount || 0) < maxRetries) { await retryItem(item.id); } } }, [queuedItems, maxRetries, retryItem]); const removeItem = useCallback(async (id: string) => { try { await removeFromQueue(id); setQueuedItems(prev => prev.filter(item => item.id !== id)); logger.info('[SubmissionQueue] Removed item', { id }); } catch (error) { logger.error('[SubmissionQueue] Failed to remove item', { id, error }); } }, []); const clearQueue = useCallback(async () => { try { const count = await clearQueueStorage(); setQueuedItems([]); logger.info('[SubmissionQueue] Cleared queue', { count }); } catch (error) { logger.error('[SubmissionQueue] Failed to clear queue', { error }); } }, []); return { queuedItems, lastSyncTime, nextRetryTime, retryItem, retryAll, removeItem, clearQueue, refresh: loadQueueFromStorage, }; }