diff --git a/src/components/providers/header-provider.tsx b/src/components/providers/header-provider.tsx index cfcf303..539deeb 100644 --- a/src/components/providers/header-provider.tsx +++ b/src/components/providers/header-provider.tsx @@ -6,6 +6,7 @@ import { agentsService } from '@/services/agents.service'; import { usersService } from '@/services/users.service'; import { uploadService } from '@/services/upload.service'; import { notificationsApiService } from '@/services/notifications-api.service'; +import { socketService } from '@/services'; interface HeaderData { profileImage: string | null; @@ -102,7 +103,7 @@ export function HeaderProvider({ children }: { children: React.ReactNode }) { return () => window.removeEventListener('profile-updated', handleProfileUpdate); }, [fetchProfileData]); - // Notification count polling + // Notification count polling + real-time socket updates useEffect(() => { if (status !== 'authenticated') return; @@ -120,9 +121,17 @@ export function HeaderProvider({ children }: { children: React.ReactNode }) { const handleNotification = () => fetchCount(); window.addEventListener('notification-received', handleNotification); + // Listen to socket events for immediate notification count refresh + const unsubConnectionReq = socketService.onConnectionRequest(() => fetchCount()); + const unsubConnectionRes = socketService.onConnectionResponse(() => fetchCount()); + const unsubNewMessage = socketService.onNewMessage(() => fetchCount()); + return () => { clearInterval(interval); window.removeEventListener('notification-received', handleNotification); + unsubConnectionReq(); + unsubConnectionRes(); + unsubNewMessage(); }; }, [status]); diff --git a/src/components/providers/notification-provider.tsx b/src/components/providers/notification-provider.tsx index 26d547b..1352bd1 100644 --- a/src/components/providers/notification-provider.tsx +++ b/src/components/providers/notification-provider.tsx @@ -3,6 +3,7 @@ import { useEffect, useRef, useState, useCallback } from "react"; import { useSession } from "next-auth/react"; import { notificationService } from "@/services/notification.service"; +import { socketService } from "@/services"; interface ToastNotification { id: number; @@ -50,8 +51,26 @@ export function NotificationProvider() { init(); + // Listen to socket events for real-time toast notifications + const unsubConnectionReq = socketService.onConnectionRequest((data) => { + const senderName = (data.senderName as string) || "Someone"; + addToast({ title: "New Connection Request", body: `${senderName} wants to connect with you` }); + }); + + const unsubConnectionRes = socketService.onConnectionResponse((data) => { + const agentName = (data.agentName as string) || "An agent"; + const status = data.status as string; + if (status === "ACCEPTED") { + addToast({ title: "Connection Accepted", body: `${agentName} accepted your connection request` }); + } else { + addToast({ title: "Connection Declined", body: `${agentName} declined your connection request` }); + } + }); + return () => { if (unsubscribe) unsubscribe(); + unsubConnectionReq(); + unsubConnectionRes(); }; }, [status, addToast]); diff --git a/src/services/socket.service.ts b/src/services/socket.service.ts index d6542ab..ab8c7e2 100644 --- a/src/services/socket.service.ts +++ b/src/services/socket.service.ts @@ -13,6 +13,7 @@ type TypingHandler = (data: TypingIndicator) => void; type StatusHandler = (data: UserStatusChange) => void; type ReadHandler = (data: MessagesReadEvent) => void; type DeliveredHandler = (data: MessageDeliveredEvent) => void; +type NotificationEventHandler = (data: Record) => void; class SocketService { private socket: Socket | null = null; @@ -24,6 +25,8 @@ class SocketService { private statusHandlers: Set = new Set(); private readHandlers: Set = new Set(); private deliveredHandlers: Set = new Set(); + private connectionRequestHandlers: Set = new Set(); + private connectionResponseHandlers: Set = new Set(); private connectionHandlers: Set<(connected: boolean) => void> = new Set(); private authErrorHandlers: Set<() => void> = new Set(); private isConnecting = false; @@ -132,6 +135,14 @@ class SocketService { this.socket.on('message_delivered', (data: MessageDeliveredEvent) => { this.deliveredHandlers.forEach((handler) => handler(data)); }); + + this.socket.on('connection_request', (data: Record) => { + this.connectionRequestHandlers.forEach((handler) => handler(data)); + }); + + this.socket.on('connection_response', (data: Record) => { + this.connectionResponseHandlers.forEach((handler) => handler(data)); + }); }); } @@ -277,6 +288,16 @@ class SocketService { return () => this.deliveredHandlers.delete(handler); } + onConnectionRequest(handler: NotificationEventHandler): () => void { + this.connectionRequestHandlers.add(handler); + return () => this.connectionRequestHandlers.delete(handler); + } + + onConnectionResponse(handler: NotificationEventHandler): () => void { + this.connectionResponseHandlers.add(handler); + return () => this.connectionResponseHandlers.delete(handler); + } + onConnectionChange(handler: (connected: boolean) => void): () => void { this.connectionHandlers.add(handler); return () => this.connectionHandlers.delete(handler);