@pubuduth-aplicy/chat-ui 2.2.12 → 2.2.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
package/src/components/Chat.tsx
CHANGED
|
@@ -5,7 +5,7 @@ import { Sidebar } from "./sidebar/Sidebar";
|
|
|
5
5
|
import { useChatContext } from "../providers/ChatProvider";
|
|
6
6
|
|
|
7
7
|
export const Chat = () => {
|
|
8
|
-
const {
|
|
8
|
+
const { selectedConversation, updateMessageStatus } = useChatUIStore();
|
|
9
9
|
|
|
10
10
|
const { socket, sendMessage } = useChatContext();
|
|
11
11
|
|
|
@@ -20,12 +20,12 @@ export const Chat = () => {
|
|
|
20
20
|
const message = parsed.data.data;
|
|
21
21
|
// Send delivery confirmation
|
|
22
22
|
// Update UI immediately
|
|
23
|
-
setMessages((prev) => [...prev, message]);
|
|
23
|
+
// setMessages((prev) => [...prev, message]);
|
|
24
24
|
sendMessage({
|
|
25
|
-
event: "
|
|
25
|
+
event: "confirmDelivery",
|
|
26
26
|
data: {
|
|
27
27
|
messageIds: [message._id],
|
|
28
|
-
chatId: message.conversationId,
|
|
28
|
+
chatId: message.conversationId,
|
|
29
29
|
senderRole: message.senderRole,
|
|
30
30
|
receiverRole: message.receiverRole,
|
|
31
31
|
senderId: message.senderId,
|
|
@@ -34,24 +34,22 @@ export const Chat = () => {
|
|
|
34
34
|
});
|
|
35
35
|
|
|
36
36
|
// Optional: update UI
|
|
37
|
-
|
|
38
|
-
updateMessageStatus(message._id, "read");
|
|
37
|
+
updateMessageStatus(message._id, "delivered");
|
|
39
38
|
|
|
40
|
-
//
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
// }
|
|
39
|
+
// Only append to the message list if the message belongs to the currently open conversation
|
|
40
|
+
if (message.conversationId === selectedConversation?._id) {
|
|
41
|
+
sendMessage({
|
|
42
|
+
event: "messageRead",
|
|
43
|
+
data: {
|
|
44
|
+
messageIds: [message._id],
|
|
45
|
+
chatId: message.conversationId,
|
|
46
|
+
senderId: message.senderId,
|
|
47
|
+
receiverId: message.receiverId,
|
|
48
|
+
receiverRole: message.receiverRole,
|
|
49
|
+
senderRole: message.senderRole,
|
|
50
|
+
},
|
|
51
|
+
});
|
|
52
|
+
}
|
|
55
53
|
}
|
|
56
54
|
} catch (error) {
|
|
57
55
|
console.error("WebSocket message parse error:", error);
|
|
@@ -60,7 +58,7 @@ export const Chat = () => {
|
|
|
60
58
|
|
|
61
59
|
socket.addEventListener("message", handleMessage);
|
|
62
60
|
return () => socket.removeEventListener("message", handleMessage);
|
|
63
|
-
}, [socket,
|
|
61
|
+
}, [socket, sendMessage, updateMessageStatus, selectedConversation]);
|
|
64
62
|
|
|
65
63
|
return (
|
|
66
64
|
<div className="container mx-auto mb-5">
|
|
@@ -16,8 +16,9 @@ const MessageContainer = () => {
|
|
|
16
16
|
const { role } = getChatConfig();
|
|
17
17
|
|
|
18
18
|
useEffect(() => {
|
|
19
|
-
if (selectedConversation?._id
|
|
20
|
-
|
|
19
|
+
if (!socket || !selectedConversation?._id) return;
|
|
20
|
+
|
|
21
|
+
const sendJoinChat = () => {
|
|
21
22
|
socket.send(
|
|
22
23
|
JSON.stringify({
|
|
23
24
|
event: "joinChat",
|
|
@@ -28,8 +29,35 @@ const MessageContainer = () => {
|
|
|
28
29
|
},
|
|
29
30
|
})
|
|
30
31
|
);
|
|
32
|
+
|
|
33
|
+
// Bulk-mark all existing unread messages as read when the conversation is opened
|
|
34
|
+
const unreadIds = selectedConversation.unreadMessageIds ?? [];
|
|
35
|
+
const lastMsg = selectedConversation.lastMessage;
|
|
36
|
+
if (unreadIds.length > 0 && lastMsg) {
|
|
37
|
+
socket.send(
|
|
38
|
+
JSON.stringify({
|
|
39
|
+
event: "messageRead",
|
|
40
|
+
data: {
|
|
41
|
+
messageIds: unreadIds,
|
|
42
|
+
chatId: selectedConversation._id,
|
|
43
|
+
senderId: lastMsg.senderId,
|
|
44
|
+
receiverId: userId,
|
|
45
|
+
// roles are not always available here — backend should infer from chatId if needed
|
|
46
|
+
},
|
|
47
|
+
})
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
if (socket.readyState === WebSocket.OPEN) {
|
|
53
|
+
// Socket already open — fire immediately
|
|
54
|
+
sendJoinChat();
|
|
55
|
+
} else if (socket.readyState === WebSocket.CONNECTING) {
|
|
56
|
+
// Socket still connecting — wait for it to open, then fire once
|
|
57
|
+
socket.addEventListener("open", sendJoinChat, { once: true });
|
|
58
|
+
return () => socket.removeEventListener("open", sendJoinChat);
|
|
31
59
|
}
|
|
32
|
-
}, [selectedConversation?._id, socket]);
|
|
60
|
+
}, [selectedConversation?._id, socket, userId, role]);
|
|
33
61
|
|
|
34
62
|
useEffect(() => {
|
|
35
63
|
if (!socket) return;
|
|
@@ -160,13 +160,16 @@ const Conversation = ({ conversation }: ConversationProps) => {
|
|
|
160
160
|
</div>
|
|
161
161
|
{/* <span className="text-xs text-gray-500">{lastMessageTimestamp}</span> */}
|
|
162
162
|
</div>
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
163
|
+
<p className="text-xs text-gray-600 dark:text-gray-500">
|
|
164
|
+
{conversation.lastMessage?.status === "deleted"
|
|
165
|
+
? "This message was deleted"
|
|
166
|
+
: conversation.lastMessage?.media?.length > 0
|
|
167
|
+
? "Attachment"
|
|
168
|
+
: conversation.lastMessage?.message?.length > 30
|
|
169
|
+
? conversation.lastMessage.message.slice(0, 30) + "..."
|
|
170
|
+
: conversation.lastMessage?.message}
|
|
171
|
+
</p>
|
|
172
|
+
|
|
170
173
|
</div>
|
|
171
174
|
</div>
|
|
172
175
|
);
|
|
@@ -198,18 +198,21 @@ const Conversations = () => {
|
|
|
198
198
|
|
|
199
199
|
const messageListener = (event: MessageEvent) => {
|
|
200
200
|
try {
|
|
201
|
-
const
|
|
202
|
-
|
|
203
|
-
|
|
201
|
+
const parsed = JSON.parse(event.data);
|
|
202
|
+
|
|
203
|
+
if (parsed.event === "newMessage") {
|
|
204
|
+
// Actual message is nested at parsed.data.data — same structure as Messages.tsx
|
|
205
|
+
const newMessage = parsed?.data?.data;
|
|
206
|
+
handleNewMessage(newMessage);
|
|
204
207
|
} else if (
|
|
205
|
-
|
|
206
|
-
|
|
208
|
+
parsed.event === "messageStatusUpdated" &&
|
|
209
|
+
parsed.data?.status === "read"
|
|
207
210
|
) {
|
|
211
|
+
// messageId can come as a single id or an array depending on backend
|
|
212
|
+
const rawId = parsed.data.messageId ?? parsed.data.messageIds;
|
|
208
213
|
handleMessageReadAck({
|
|
209
|
-
messageIds: Array.isArray(
|
|
210
|
-
|
|
211
|
-
: [data.data.messageId],
|
|
212
|
-
chatId: data.data.chatId,
|
|
214
|
+
messageIds: Array.isArray(rawId) ? rawId : [rawId].filter(Boolean),
|
|
215
|
+
chatId: parsed.data.chatId,
|
|
213
216
|
});
|
|
214
217
|
}
|
|
215
218
|
} catch (e) {
|