/** * Custom hook for monitoring sync progress * Centralizes the pattern of polling syncProgressManager and updating state */ import { useState, useEffect, useRef } from 'react' import type { SyncProgress } from '../helpers/syncProgressHelper' export interface UseSyncProgressOptions { onComplete?: () => void | Promise pollInterval?: number maxDuration?: number } export interface UseSyncProgressResult { syncProgress: SyncProgress | null isSyncing: boolean startMonitoring: () => void stopMonitoring: () => void } /** * Hook to monitor sync progress from syncProgressManager */ export function useSyncProgress(options: UseSyncProgressOptions = {}): UseSyncProgressResult { const { onComplete, pollInterval = 500, maxDuration = 60000 } = options const [syncProgress, setSyncProgress] = useState(null) const [isSyncing, setIsSyncing] = useState(false) const intervalRef = useRef(null) const timeoutRef = useRef(null) const onCompleteRef = useRef(onComplete) const isMonitoringRef = useRef(false) // Update onComplete ref when it changes useEffect(() => { onCompleteRef.current = onComplete }, [onComplete]) const checkProgress = async (): Promise => { const { syncProgressManager } = await import('../syncProgressManager') const currentProgress = syncProgressManager.getProgress() if (currentProgress) { setSyncProgress(currentProgress) if (currentProgress.completed) { setIsSyncing(false) if (onCompleteRef.current) { await onCompleteRef.current() } stopMonitoring() } } } const startMonitoring = (): void => { if (isMonitoringRef.current) { return } isMonitoringRef.current = true setIsSyncing(true) setSyncProgress({ currentStep: 0, totalSteps: 7, completed: false }) // Poll progress periodically intervalRef.current = setInterval(() => { void checkProgress() }, pollInterval) // Cleanup after max duration timeoutRef.current = setTimeout(() => { stopMonitoring() }, maxDuration) } const stopMonitoring = (): void => { if (!isMonitoringRef.current) { return } isMonitoringRef.current = false setIsSyncing(false) if (intervalRef.current) { clearInterval(intervalRef.current) intervalRef.current = null } if (timeoutRef.current) { clearTimeout(timeoutRef.current) timeoutRef.current = null } } // Cleanup on unmount useEffect(() => { return () => { stopMonitoring() } }, []) return { syncProgress, isSyncing, startMonitoring, stopMonitoring, } }