cre-sync/components/realtime/RealtimeProvider.tsx
BusyBee3333 4e6467ffb0 Add CRESync CRM application with Setup page
- Build complete Next.js CRM for commercial real estate
- Add authentication with JWT sessions and role-based access
- Add GoHighLevel API integration for contacts, conversations, opportunities
- Add AI-powered Control Center with tool calling
- Add Setup page with onboarding checklist (/setup)
- Add sidebar navigation with Setup menu item
- Fix type errors in onboarding API, GHL services, and control center tools
- Add Prisma schema with SQLite for local development
- Add UI components with clay morphism design system

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-14 17:30:55 -05:00

82 lines
2.3 KiB
TypeScript

'use client';
import { createContext, useContext, useEffect, useState } from 'react';
import { RealtimeEvent, RealtimeMessage, REALTIME_EVENTS } from '@/lib/realtime/events';
interface RealtimeContextValue {
isConnected: boolean;
subscribe: <T = any>(event: RealtimeEvent, handler: (data: T) => void) => () => void;
lastEvent: RealtimeMessage | null;
}
const RealtimeContext = createContext<RealtimeContextValue | null>(null);
export function RealtimeProvider({ children }: { children: React.ReactNode }) {
const [isConnected, setIsConnected] = useState(false);
const [lastEvent, setLastEvent] = useState<RealtimeMessage | null>(null);
const [handlers, setHandlers] = useState<Map<RealtimeEvent, Set<(data: any) => void>>>(new Map());
useEffect(() => {
const eventSource = new EventSource('/api/v1/realtime/events');
eventSource.onopen = () => {
setIsConnected(true);
};
eventSource.onmessage = (event) => {
try {
const message = JSON.parse(event.data);
if (message.type === 'connected') return;
setLastEvent(message);
const eventHandlers = handlers.get(message.event);
if (eventHandlers) {
eventHandlers.forEach(handler => handler(message.data));
}
} catch (e) {
console.error('Parse error:', e);
}
};
eventSource.onerror = () => {
setIsConnected(false);
};
return () => eventSource.close();
}, [handlers]);
const subscribe = <T = any>(event: RealtimeEvent, handler: (data: T) => void) => {
setHandlers(prev => {
const newHandlers = new Map(prev);
if (!newHandlers.has(event)) {
newHandlers.set(event, new Set());
}
newHandlers.get(event)!.add(handler);
return newHandlers;
});
return () => {
setHandlers(prev => {
const newHandlers = new Map(prev);
newHandlers.get(event)?.delete(handler);
return newHandlers;
});
};
};
return (
<RealtimeContext.Provider value={{ isConnected, subscribe, lastEvent }}>
{children}
</RealtimeContext.Provider>
);
}
export function useRealtimeContext() {
const context = useContext(RealtimeContext);
if (!context) {
throw new Error('useRealtimeContext must be used within RealtimeProvider');
}
return context;
}