import { useEffect, useState, useCallback, useRef } from 'react'; import { websocketService, PresenceUpdate, WebSocketEventCallback } from '@/lib/websocket'; import { useAuth } from '@/lib/auth/AuthContext'; /** * React Hook for WebSocket Connection * * Features: * - Automatic connection management * - Family room subscription * - Connection status * - Presence indicators */ export function useWebSocket() { const { user, token } = useAuth(); const [isConnected, setIsConnected] = useState(false); const [presence, setPresence] = useState({ onlineUsers: [], count: 0 }); const hasInitialized = useRef(false); console.log('[useWebSocket] Hook called - User:', !!user, 'Token:', !!token, 'Initialized:', hasInitialized.current); // Connect to WebSocket when user is authenticated useEffect(() => { console.log('[useWebSocket] useEffect triggered - User:', !!user, 'Token:', !!token, 'Initialized:', hasInitialized.current); if (user && token && !hasInitialized.current) { hasInitialized.current = true; const backendUrl = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:3020'; console.log('[useWebSocket] Connecting to:', backendUrl); console.log('[useWebSocket] User authenticated:', !!user); console.log('[useWebSocket] Token available:', !!token); websocketService.connect({ url: backendUrl, token, }); // Subscribe to connection status const unsubscribe = websocketService.onConnectionStatusChange(setIsConnected); return () => { console.log('[useWebSocket] Disconnecting...'); unsubscribe(); websocketService.disconnect(); hasInitialized.current = false; }; } }, [user, token]); // Auto-join family when user is in a family useEffect(() => { const familyId = user?.families?.[0]?.familyId; if (isConnected && familyId) { console.log('[useWebSocket] Auto-joining family:', familyId); websocketService.joinFamily(familyId); return () => { websocketService.leaveFamily(); }; } }, [isConnected, user?.families]); // Subscribe to presence updates useEffect(() => { const unsubscribe = websocketService.on('presenceUpdate', setPresence); // Get initial presence when family is joined const unsubscribeJoined = websocketService.on('familyJoined', (data: any) => { if (data.onlineUsers) { setPresence({ onlineUsers: data.onlineUsers, count: data.onlineUsers.length }); } }); return () => { unsubscribe(); unsubscribeJoined(); }; }, []); // Join a specific family room const joinFamily = useCallback((familyId: string) => { if (isConnected) { websocketService.joinFamily(familyId); } }, [isConnected]); // Leave current family room const leaveFamily = useCallback(() => { websocketService.leaveFamily(); }, []); return { isConnected, presence, joinFamily, leaveFamily, }; } /** * Hook for subscribing to specific WebSocket events */ export function useWebSocketEvent( event: string, callback: WebSocketEventCallback, dependencies: any[] = [] ) { useEffect(() => { const unsubscribe = websocketService.on(event, callback); return unsubscribe; }, [event, ...dependencies]); // eslint-disable-line react-hooks/exhaustive-deps } /** * Hook for real-time activity updates * * Automatically updates local state when activities are created/updated/deleted by other family members */ export function useRealTimeActivities( onActivityCreated?: (activity: any) => void, onActivityUpdated?: (activity: any) => void, onActivityDeleted?: (data: { activityId: string }) => void ) { useWebSocketEvent('activityCreated', (activity) => { console.log('[useRealTimeActivities] Activity created:', activity); onActivityCreated?.(activity); }, [onActivityCreated]); useWebSocketEvent('activityUpdated', (activity) => { console.log('[useRealTimeActivities] Activity updated:', activity); onActivityUpdated?.(activity); }, [onActivityUpdated]); useWebSocketEvent('activityDeleted', (data) => { console.log('[useRealTimeActivities] Activity deleted:', data); onActivityDeleted?.(data); }, [onActivityDeleted]); } /** * Hook for real-time child updates */ export function useRealTimeChildren( onChildAdded?: (child: any) => void, onChildUpdated?: (child: any) => void, onChildDeleted?: (data: { childId: string }) => void ) { useWebSocketEvent('childAdded', (child) => { console.log('[useRealTimeChildren] Child added:', child); onChildAdded?.(child); }, [onChildAdded]); useWebSocketEvent('childUpdated', (child) => { console.log('[useRealTimeChildren] Child updated:', child); onChildUpdated?.(child); }, [onChildUpdated]); useWebSocketEvent('childDeleted', (data) => { console.log('[useRealTimeChildren] Child deleted:', data); onChildDeleted?.(data); }, [onChildDeleted]); } /** * Hook for real-time family member updates */ export function useRealTimeFamilyMembers( onMemberAdded?: (member: any) => void, onMemberUpdated?: (member: any) => void, onMemberRemoved?: (data: { userId: string }) => void ) { useWebSocketEvent('memberAdded', (member) => { console.log('[useRealTimeFamilyMembers] Member added:', member); onMemberAdded?.(member); }, [onMemberAdded]); useWebSocketEvent('memberUpdated', (member) => { console.log('[useRealTimeFamilyMembers] Member updated:', member); onMemberUpdated?.(member); }, [onMemberUpdated]); useWebSocketEvent('memberRemoved', (data) => { console.log('[useRealTimeFamilyMembers] Member removed:', data); onMemberRemoved?.(data); }, [onMemberRemoved]); }