Files
thrilltrack-explorer/src-old/hooks/useSubmissionQueue.ts

147 lines
4.1 KiB
TypeScript

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<QueuedSubmission[]>([]);
const [lastSyncTime, setLastSyncTime] = useState<Date | null>(null);
const [nextRetryTime, setNextRetryTime] = useState<Date | null>(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,
};
}