From bd40eaeb0cdd899f4b6a0767f37a3b64be9757ca Mon Sep 17 00:00:00 2001 From: pradeepkumar Date: Sat, 28 Mar 2026 02:03:04 +0530 Subject: [PATCH] feat: Implement message delivered event handling to update message statuses in conversations. --- src/hooks/useMessaging.ts | 21 +++++++++++++++++++++ src/services/socket.service.ts | 12 ++++++++++++ src/types/messaging.ts | 7 +++++++ 3 files changed, 40 insertions(+) diff --git a/src/hooks/useMessaging.ts b/src/hooks/useMessaging.ts index edc0e84..0cad3a5 100644 --- a/src/hooks/useMessaging.ts +++ b/src/hooks/useMessaging.ts @@ -10,6 +10,7 @@ import type { TypingIndicator, UserStatusChange, MessagesReadEvent, + MessageDeliveredEvent, MessageType, MessageStatus, } from '@/types/messaging'; @@ -561,6 +562,25 @@ export function useMessaging(options: UseMessagingOptions = {}): UseMessagingRet } ); + const unsubscribeDelivered = socketService.onMessageDelivered( + (data: MessageDeliveredEvent) => { + if (data.conversationId === currentConversationIdRef.current) { + // Update single message or batch of messages to DELIVERED + const deliveredIds = data.messageIds || (data.messageId ? [data.messageId] : []); + if (deliveredIds.length > 0) { + setMessages((prev) => + prev.map((m) => { + if (deliveredIds.includes(m.id) && m.status === 'SENT') { + return { ...m, status: 'DELIVERED' as MessageStatus, deliveredAt: data.deliveredAt }; + } + return m; + }) + ); + } + } + } + ); + // Auth error handling (token refresh + reconnect) is handled globally // by PresenceProvider — no duplicate handler needed here. @@ -571,6 +591,7 @@ export function useMessaging(options: UseMessagingOptions = {}): UseMessagingRet unsubscribeTypingStop(); unsubscribeStatus(); unsubscribeRead(); + unsubscribeDelivered(); }; }, [updateUserStatus]); diff --git a/src/services/socket.service.ts b/src/services/socket.service.ts index 2493c8a..d6542ab 100644 --- a/src/services/socket.service.ts +++ b/src/services/socket.service.ts @@ -4,6 +4,7 @@ import type { TypingIndicator, UserStatusChange, MessagesReadEvent, + MessageDeliveredEvent, CreateMessageDto, } from '@/types/messaging'; @@ -11,6 +12,7 @@ type MessageHandler = (message: Message) => void; type TypingHandler = (data: TypingIndicator) => void; type StatusHandler = (data: UserStatusChange) => void; type ReadHandler = (data: MessagesReadEvent) => void; +type DeliveredHandler = (data: MessageDeliveredEvent) => void; class SocketService { private socket: Socket | null = null; @@ -21,6 +23,7 @@ class SocketService { private typingStopHandlers: Set = new Set(); private statusHandlers: Set = new Set(); private readHandlers: Set = new Set(); + private deliveredHandlers: Set = new Set(); private connectionHandlers: Set<(connected: boolean) => void> = new Set(); private authErrorHandlers: Set<() => void> = new Set(); private isConnecting = false; @@ -125,6 +128,10 @@ class SocketService { this.socket.on('messages_read', (data: MessagesReadEvent) => { this.readHandlers.forEach((handler) => handler(data)); }); + + this.socket.on('message_delivered', (data: MessageDeliveredEvent) => { + this.deliveredHandlers.forEach((handler) => handler(data)); + }); }); } @@ -265,6 +272,11 @@ class SocketService { return () => this.readHandlers.delete(handler); } + onMessageDelivered(handler: DeliveredHandler): () => void { + this.deliveredHandlers.add(handler); + return () => this.deliveredHandlers.delete(handler); + } + onConnectionChange(handler: (connected: boolean) => void): () => void { this.connectionHandlers.add(handler); return () => this.connectionHandlers.delete(handler); diff --git a/src/types/messaging.ts b/src/types/messaging.ts index 16e3531..d072729 100644 --- a/src/types/messaging.ts +++ b/src/types/messaging.ts @@ -99,6 +99,13 @@ export interface MessagesReadEvent { readAt: string; } +export interface MessageDeliveredEvent { + messageId?: string; + messageIds?: string[]; + conversationId: string; + deliveredAt: string; +} + export interface PaginationInfo { page: number; limit: number;