'use client' import { useEffect, useRef, useCallback, useState } from 'react' import { useRouter } from 'next/navigation' interface UseRealtimeSyncOptions { listId: string enabled?: boolean pollInterval?: number onUpdate?: () => void } /** * Hook to enable real-time synchronization of list data * Polls the server for updates and refreshes the page when changes are detected */ export function useRealtimeSync({ listId, enabled = true, pollInterval = 3000, // Poll every 3 seconds onUpdate }: UseRealtimeSyncOptions) { const router = useRouter() const [lastUpdated, setLastUpdated] = useState(Date.now()) const intervalRef = useRef(null) const isPollingRef = useRef(false) const checkForUpdates = useCallback(async () => { // Prevent concurrent polling if (isPollingRef.current) return try { isPollingRef.current = true // Fetch the latest update timestamp for the list const response = await fetch(`/api/lists/${listId}/last-updated`, { method: 'GET', headers: { 'Cache-Control': 'no-cache', }, }) if (response.ok) { const data = await response.json() const serverTimestamp = new Date(data.lastUpdated).getTime() // If server timestamp is newer than our last known update, refresh if (serverTimestamp > lastUpdated) { setLastUpdated(serverTimestamp) // Refresh the current route to get latest data router.refresh() // Call optional callback if (onUpdate) { onUpdate() } } } } catch (error) { console.error('Error checking for updates:', error) } finally { isPollingRef.current = false } }, [listId, lastUpdated, router, onUpdate]) useEffect(() => { if (!enabled) { if (intervalRef.current) { clearInterval(intervalRef.current) intervalRef.current = null } return } // Start polling intervalRef.current = setInterval(checkForUpdates, pollInterval) // Cleanup on unmount return () => { if (intervalRef.current) { clearInterval(intervalRef.current) intervalRef.current = null } } }, [enabled, pollInterval, checkForUpdates]) // Also check for updates when the page becomes visible again useEffect(() => { const handleVisibilityChange = () => { if (document.visibilityState === 'visible' && enabled) { checkForUpdates() } } document.addEventListener('visibilitychange', handleVisibilityChange) return () => { document.removeEventListener('visibilitychange', handleVisibilityChange) } }, [enabled, checkForUpdates]) return { lastUpdated, checkForUpdates, } }