'use client' /** * React context for mizan/channels */ import { createContext, useContext, useEffect, useMemo, useRef, useState, type ReactNode } from 'react' import { ChannelConnection, type ChannelConnectionOptions } from './connection' import type { ConnectionStatus } from './types' interface ChannelContextValue { connection: ChannelConnection status: ConnectionStatus } const ChannelContext = createContext(null) export interface ChannelProviderProps { children: ReactNode /** WebSocket URL (default: /ws/) */ url?: string /** Reconnect on disconnect (default: true) */ reconnect?: boolean /** Reconnection delay in ms (default: 1000) */ reconnectDelay?: number /** Maximum reconnection attempts (default: 10) */ maxReconnectAttempts?: number /** Connect automatically on mount (default: true) */ autoConnect?: boolean /** Custom connection instance (for testing) */ connection?: ChannelConnection } export function ChannelProvider({ children, url, reconnect, reconnectDelay, maxReconnectAttempts, autoConnect = true, connection: providedConnection, }: ChannelProviderProps) { const connectionRef = useRef(null) // Use provided connection or create one if (!connectionRef.current) { connectionRef.current = providedConnection ?? new ChannelConnection({ url, reconnect, reconnectDelay, maxReconnectAttempts, }) } const connection = connectionRef.current // Track status for context value const [status, setStatus] = useState(connection.status) useEffect(() => { const unsubscribe = connection.onStatusChange(setStatus) if (autoConnect) { connection.connect() } return () => { unsubscribe() connection.disconnect() } }, [connection, autoConnect]) const value = useMemo(() => ({ connection, status, }), [connection, status]) return ( {children} ) } export function useChannelContext(): ChannelContextValue { const context = useContext(ChannelContext) if (!context) { throw new Error('useChannelContext must be used within a ChannelProvider') } return context } export function useChannelStatus(): ConnectionStatus { const { status } = useChannelContext() return status }