hooks/useRealtimeSync.ts
1import { useEffect, useRef } from 'react';
2import { supabase } from '@/lib/supabase';
3
4const DEDUP_WINDOW = 2000; // 2s dedup window
5
Key pattern: dedup window prevents duplicate event processing
6export function useRealtimeSync(table: string, orgId: string) {
7 const lastEvent = useRef<Map<string, number>>(new Map());
8
9 useEffect(() => {
10 const channel = supabase
11 .channel(`${table}:${orgId}`)
12 .on('postgres_changes',
13 { event: '*', schema: 'public', table,
14 filter: `org_id=eq.${orgId}` },
Echo prevention: skip events from own session
15 (payload) => {
16 const id = payload.new?.id;
17 const now = Date.now();
18 const last = lastEvent.current.get(id);
19
20 if (last && now - last < DEDUP_WINDOW) return;
21 lastEvent.current.set(id, now);
22
23 // Stale-refetch: invalidate cache
24 queryClient.invalidateQueries([table]);
25 }
26 )
27 .subscribe();
28
29 return () => supabase.removeChannel(channel);
30 }, [table, orgId]);
31}