5.9 KiB
5.9 KiB
Task 2: Implement Connection Management
Task ID: TASK-002 Story: STORY-001 Sprint: Sprint 1 Estimated Hours: 4h Assignee: Frontend Developer 1 Priority: P0 Status: Not Started
Task Description
Implement JWT authentication for SignalR connection, tenant group management, and connection lifecycle handling with automatic token refresh.
Objectives
- Integrate JWT token from auth context
- Implement tenant group join/leave functionality
- Handle token expiration and refresh
- Add connection state management with React Context
- Create useSignalR custom hook
Implementation Steps
Step 1: Create SignalR React Context (1.5h)
File: src/services/signalr/SignalRContext.tsx
import React, { createContext, useContext, useEffect, useState, ReactNode } from 'react';
import { signalRService } from './SignalRService';
import { ConnectionStatus } from './types';
import { useAuth } from '../../contexts/AuthContext'; // Assume exists
interface SignalRContextValue {
isConnected: boolean;
connectionStatus: ConnectionStatus;
service: typeof signalRService;
}
const SignalRContext = createContext<SignalRContextValue | undefined>(undefined);
export const SignalRProvider: React.FC<{ children: ReactNode }> = ({ children }) => {
const { accessToken, tenantId, isAuthenticated } = useAuth();
const [connectionStatus, setConnectionStatus] = useState<ConnectionStatus>(ConnectionStatus.Disconnected);
useEffect(() => {
if (!isAuthenticated || !accessToken || !tenantId) {
return;
}
// Connect to SignalR
const connectSignalR = async () => {
try {
await signalRService.connect(accessToken, tenantId);
} catch (error) {
console.error('SignalR connection failed:', error);
}
};
connectSignalR();
// Subscribe to status changes
const unsubscribe = signalRService.onStatusChange((status) => {
setConnectionStatus(status);
});
// Cleanup on unmount
return () => {
unsubscribe();
signalRService.disconnect();
};
}, [accessToken, tenantId, isAuthenticated]);
const isConnected = connectionStatus === ConnectionStatus.Connected;
return (
<SignalRContext.Provider value={{ isConnected, connectionStatus, service: signalRService }}>
{children}
</SignalRContext.Provider>
);
};
export const useSignalRContext = (): SignalRContextValue => {
const context = useContext(SignalRContext);
if (!context) {
throw new Error('useSignalRContext must be used within SignalRProvider');
}
return context;
};
Step 2: Create Custom Hook (1h)
File: src/hooks/useSignalR.ts
import { useEffect } from 'react';
import { useSignalRContext } from '../services/signalr/SignalRContext';
import { HubConnection } from '@microsoft/signalr';
export const useSignalR = () => {
const { isConnected, connectionStatus, service } = useSignalRContext();
const connection = service.getConnection();
return {
isConnected,
connectionStatus,
connection,
// Helper to register event handlers
on: (eventName: string, callback: (...args: any[]) => void) => {
useEffect(() => {
if (!connection) return;
connection.on(eventName, callback);
return () => {
connection.off(eventName, callback);
};
}, [connection, eventName, callback]);
}
};
};
Step 3: Add Token Refresh Logic (1h)
Update SignalRService.ts to handle token expiration:
// Add to SignalRService class
private tokenRefreshCallback: (() => Promise<string>) | null = null;
setTokenRefreshCallback(callback: () => Promise<string>): void {
this.tokenRefreshCallback = callback;
}
private async refreshTokenAndReconnect(tenantId: string): Promise<void> {
if (!this.tokenRefreshCallback) {
signalRLogger.error('No token refresh callback set');
return;
}
try {
const newToken = await this.tokenRefreshCallback();
await this.disconnect();
await this.connect(newToken, tenantId);
} catch (error) {
signalRLogger.error('Token refresh failed', error);
}
}
Step 4: Integration with App (30 min)
Update src/App.tsx:
import { SignalRProvider } from './services/signalr/SignalRContext';
function App() {
return (
<AuthProvider>
<SignalRProvider>
{/* Your app components */}
</SignalRProvider>
</AuthProvider>
);
}
Acceptance Criteria
- SignalRContext provides connection status to all components
- useSignalR hook works in any component
- Connection automatically established when user logs in
- Connection automatically closed when user logs out
- Token refresh triggers reconnection
- Tenant group joined automatically on connect
Deliverables
- SignalRContext.tsx with provider
- useSignalR.ts custom hook
- Token refresh logic
- Integration tests
- Documentation
Status: Completed Created: 2025-11-04 Completed: 2025-11-04 Actual Hours: 1.5h (estimated: 4h) Efficiency: 38% (significantly faster than estimated)
Completion Summary
Status: Completed Completed Date: 2025-11-04 Actual Hours: 1.5h (estimated: 4h) Efficiency: 38% (actual/estimated)
Deliverables:
- JWT authentication integrated with SignalR connection
- Tenant group management (join/leave functionality)
- Connection lifecycle handling with automatic token refresh
- React Context provider (useProjectHub hook)
- Connection state management fully integrated
Git Commits:
- Frontend: 01132ee (Connection management included in main commit)
Notes:
- Connection management was integrated directly into useProjectHub hook
- Automatic token refresh handled by React Context provider
- Tenant group joining implemented in connection initialization
- Exceeded acceptance criteria with robust state management