'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 { Project } from '@/types/project'; interface UseProjectHubOptions { onProjectUpdated?: (project: Project) => void; onProjectArchived?: (data: { ProjectId: string }) => void; onIssueCreated?: (issue: any) => void; onIssueUpdated?: (issue: any) => void; onIssueDeleted?: (data: { IssueId: string }) => void; onIssueStatusChanged?: (data: any) => void; onUserJoinedProject?: (data: any) => void; onUserLeftProject?: (data: any) => void; onTypingIndicator?: (data: { UserId: string; IssueId: string; IsTyping: boolean }) => void; } 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); // 监听项目事件 manager.on('ProjectUpdated', (data: any) => { console.log('[ProjectHub] Project updated:', data); options?.onProjectUpdated?.(data); }); manager.on('ProjectArchived', (data: { ProjectId: string }) => { console.log('[ProjectHub] Project archived:', data); options?.onProjectArchived?.(data); }); manager.on('IssueCreated', (issue: any) => { console.log('[ProjectHub] Issue created:', issue); options?.onIssueCreated?.(issue); }); manager.on('IssueUpdated', (issue: any) => { console.log('[ProjectHub] Issue updated:', issue); options?.onIssueUpdated?.(issue); }); manager.on('IssueDeleted', (data: { IssueId: string }) => { console.log('[ProjectHub] Issue deleted:', data); options?.onIssueDeleted?.(data); }); manager.on('IssueStatusChanged', (data: any) => { console.log('[ProjectHub] Issue status changed:', data); options?.onIssueStatusChanged?.(data); }); 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: { UserId: string; IssueId: string; IsTyping: boolean }) => { 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', }; }