'use client'; import { useEffect, useState, useCallback, useRef } from 'react'; import { SignalRConnectionManager } from '@/lib/signalr/ConnectionManager'; import { SIGNALR_CONFIG } from '@/lib/signalr/config'; import { useAuthStore } from '@/stores/authStore'; import type { ProjectHubEventCallbacks } from '@/lib/signalr/types'; // Re-export for backward compatibility interface UseProjectHubOptions extends ProjectHubEventCallbacks {} export function useProjectHub(projectId?: string, options?: UseProjectHubOptions) { const isAuthenticated = useAuthStore((state) => state.isAuthenticated); const [connectionState, setConnectionState] = useState< 'disconnected' | 'connecting' | 'connected' | 'reconnecting' >('disconnected'); const managerRef = useRef(null); useEffect(() => { if (!isAuthenticated) return; const manager = new SignalRConnectionManager( SIGNALR_CONFIG.HUB_URLS.PROJECT ); managerRef.current = manager; const unsubscribe = manager.onStateChange(setConnectionState); // ============================================ // PROJECT EVENTS (3) // ============================================ manager.on('ProjectCreated', (data: any) => { console.log('[ProjectHub] Project created:', data); options?.onProjectCreated?.(data); }); manager.on('ProjectUpdated', (data: any) => { console.log('[ProjectHub] Project updated:', data); options?.onProjectUpdated?.(data); }); manager.on('ProjectArchived', (data: any) => { console.log('[ProjectHub] Project archived:', data); options?.onProjectArchived?.(data); }); // ============================================ // EPIC EVENTS (3) // ============================================ manager.on('EpicCreated', (data: any) => { console.log('[ProjectHub] Epic created:', data); options?.onEpicCreated?.(data); }); manager.on('EpicUpdated', (data: any) => { console.log('[ProjectHub] Epic updated:', data); options?.onEpicUpdated?.(data); }); manager.on('EpicDeleted', (data: any) => { console.log('[ProjectHub] Epic deleted:', data); options?.onEpicDeleted?.(data); }); // ============================================ // STORY EVENTS (3) // ============================================ manager.on('StoryCreated', (data: any) => { console.log('[ProjectHub] Story created:', data); options?.onStoryCreated?.(data); }); manager.on('StoryUpdated', (data: any) => { console.log('[ProjectHub] Story updated:', data); options?.onStoryUpdated?.(data); }); manager.on('StoryDeleted', (data: any) => { console.log('[ProjectHub] Story deleted:', data); options?.onStoryDeleted?.(data); }); // ============================================ // TASK EVENTS (4) // ============================================ manager.on('TaskCreated', (data: any) => { console.log('[ProjectHub] Task created:', data); options?.onTaskCreated?.(data); }); manager.on('TaskUpdated', (data: any) => { console.log('[ProjectHub] Task updated:', data); options?.onTaskUpdated?.(data); }); manager.on('TaskDeleted', (data: any) => { console.log('[ProjectHub] Task deleted:', data); options?.onTaskDeleted?.(data); }); manager.on('TaskAssigned', (data: any) => { console.log('[ProjectHub] Task assigned:', data); options?.onTaskAssigned?.(data); }); // ============================================ // LEGACY ISSUE EVENTS (Backward Compatibility) // ============================================ manager.on('IssueCreated', (data: any) => { console.log('[ProjectHub] Issue created:', data); options?.onIssueCreated?.(data); }); manager.on('IssueUpdated', (data: any) => { console.log('[ProjectHub] Issue updated:', data); options?.onIssueUpdated?.(data); }); manager.on('IssueDeleted', (data: any) => { console.log('[ProjectHub] Issue deleted:', data); options?.onIssueDeleted?.(data); }); manager.on('IssueStatusChanged', (data: any) => { console.log('[ProjectHub] Issue status changed:', data); options?.onIssueStatusChanged?.(data); }); // ============================================ // USER COLLABORATION EVENTS // ============================================ manager.on('UserJoinedProject', (data: any) => { console.log('[ProjectHub] User joined:', data); options?.onUserJoinedProject?.(data); }); manager.on('UserLeftProject', (data: any) => { console.log('[ProjectHub] User left:', data); options?.onUserLeftProject?.(data); }); manager.on('TypingIndicator', (data: any) => { console.log('[ProjectHub] Typing indicator:', data); options?.onTypingIndicator?.(data); }); manager.start(); return () => { unsubscribe(); manager.stop(); }; }, [isAuthenticated, options]); // 加入项目房间 const joinProject = useCallback(async (projectId: string) => { if (!managerRef.current) return; try { await managerRef.current.invoke('JoinProject', projectId); console.log(`[ProjectHub] Joined project ${projectId}`); } catch (error) { console.error('[ProjectHub] Error joining project:', error); } }, []); // 离开项目房间 const leaveProject = useCallback(async (projectId: string) => { if (!managerRef.current) return; try { await managerRef.current.invoke('LeaveProject', projectId); console.log(`[ProjectHub] Left project ${projectId}`); } catch (error) { console.error('[ProjectHub] Error leaving project:', error); } }, []); // 发送正在输入指示器 const sendTypingIndicator = useCallback( async (projectId: string, issueId: string, isTyping: boolean) => { if (!managerRef.current) return; try { await managerRef.current.invoke( 'SendTypingIndicator', projectId, issueId, isTyping ); } catch (error) { console.error('[ProjectHub] Error sending typing indicator:', error); } }, [] ); // 当 projectId 变化时自动加入/离开 useEffect(() => { if (connectionState === 'connected' && projectId) { joinProject(projectId); return () => { leaveProject(projectId); }; } }, [connectionState, projectId, joinProject, leaveProject]); return { connectionState, joinProject, leaveProject, sendTypingIndicator, isConnected: connectionState === 'connected', }; }