@pubuduth-aplicy/chat-ui 2.1.34 → 2.1.36
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 +1 -1
- package/src/components/Chat.tsx +19 -1
- package/src/components/messages/Message.tsx +30 -1
- package/src/components/messages/MessageContainer.tsx +7 -0
- package/src/components/messages/MessageInput.tsx +68 -51
- package/src/components/messages/Messages.tsx +60 -16
- package/src/components/sidebar/Conversation.tsx +18 -0
- package/src/service/sidebarApi.ts +13 -8
- package/src/stores/Zustant.ts +24 -12
- package/src/types/type.ts +13 -2
package/package.json
CHANGED
package/src/components/Chat.tsx
CHANGED
|
@@ -1,11 +1,29 @@
|
|
|
1
|
+
import { useEffect } from 'react';
|
|
1
2
|
import useChatUIStore from '../stores/Zustant';
|
|
2
3
|
import MessageContainer from './messages/MessageContainer';
|
|
3
4
|
import { Sidebar } from './sidebar/Sidebar'
|
|
5
|
+
import { useChatContext } from '../providers/ChatProvider';
|
|
6
|
+
|
|
4
7
|
// import MessageContainer from './components/messages/MessageContainer'
|
|
5
8
|
// import useConversation from '../../zustand/useConversation';
|
|
6
9
|
|
|
7
10
|
export const Chat = () => {
|
|
8
|
-
const { selectedConversation } = useChatUIStore();
|
|
11
|
+
const { selectedConversation, messages, setMessages, updateMessageStatus } = useChatUIStore();
|
|
12
|
+
const {socket}=useChatContext()
|
|
13
|
+
useEffect(() => {
|
|
14
|
+
socket.on("receiveMessage", (messageData) => {
|
|
15
|
+
setMessages([...messages, { ...messageData, status: "sent" }]);
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
socket.on("messageDelivered", ({ messageId }) => {
|
|
19
|
+
updateMessageStatus(messageId, "delivered");
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
return () => {
|
|
23
|
+
socket.off("receiveMessage");
|
|
24
|
+
socket.off("messageDelivered");
|
|
25
|
+
};
|
|
26
|
+
}, [messages, setMessages, updateMessageStatus]);
|
|
9
27
|
return (
|
|
10
28
|
<>
|
|
11
29
|
<div className='container mx-auto mb-5'>
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
2
|
/* eslint-disable @typescript-eslint/no-unused-vars */
|
|
3
3
|
|
|
4
|
+
import { MessageStatus } from "../../types/type";
|
|
4
5
|
import { useChatContext } from "../../providers/ChatProvider";
|
|
5
6
|
import useChatUIStore from "../../stores/Zustant";
|
|
6
7
|
|
|
@@ -11,6 +12,7 @@ interface MessageProps {
|
|
|
11
12
|
message: {
|
|
12
13
|
senderId: string;
|
|
13
14
|
message: string;
|
|
15
|
+
status: MessageStatus;
|
|
14
16
|
createdAt:any;
|
|
15
17
|
};
|
|
16
18
|
}
|
|
@@ -29,16 +31,43 @@ const seconds = date.getUTCSeconds();
|
|
|
29
31
|
|
|
30
32
|
// Format the time as HH:mm:ss (24-hour format)
|
|
31
33
|
const time = `${hours}.${minutes}`;
|
|
34
|
+
|
|
35
|
+
const getStatusIcon = () => {
|
|
36
|
+
if (!fromMe) return null;
|
|
37
|
+
|
|
38
|
+
switch (message.status) {
|
|
39
|
+
case 'sent':
|
|
40
|
+
return <span className="message-status sent">✓</span>;
|
|
41
|
+
case 'delivered':
|
|
42
|
+
return <span className="message-status delivered">✓✓</span>;
|
|
43
|
+
case 'read':
|
|
44
|
+
return <span className="message-status read">✓✓ (blue)</span>;
|
|
45
|
+
default:
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
|
|
32
50
|
return (
|
|
33
51
|
<>
|
|
52
|
+
{/* <div className="w-max grid">
|
|
53
|
+
<div className="px-3.5 py-2 bg-gray-100 rounded-3xl rounded-tl-none justify-start items-center gap-3 inline-flex">
|
|
54
|
+
<h5 className="text-gray-900 text-sm font-normal leading-snug">{message.message}</h5>
|
|
55
|
+
</div>
|
|
56
|
+
<div className="justify-end items-center inline-flex mb-2.5">
|
|
57
|
+
<h6 className="text-gray-500 text-xs font-normal leading-4 py-1">05:14 PM</h6>
|
|
58
|
+
</div>
|
|
59
|
+
</div> */}
|
|
60
|
+
|
|
34
61
|
<div className='chatMessage'>
|
|
35
62
|
<div className="chatMessagesContainer">
|
|
36
63
|
<div style={{color:"#374151"}}>
|
|
37
64
|
<div className={`chatMessagesBubble_inner ${alignItems} ${bubbleBgColor} `}>
|
|
38
65
|
<p style={{fontSize:"14px"}}>{message.message}</p>
|
|
39
|
-
<div className='chatMessagesBubble_Time'>{
|
|
66
|
+
<div className='chatMessagesBubble_Time'> {new Date(message.createdAt).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })}</div>
|
|
67
|
+
{getStatusIcon()}
|
|
40
68
|
</div>
|
|
41
69
|
</div>
|
|
70
|
+
|
|
42
71
|
{/* <div className="clear-both flex text-gray-700" /> */}
|
|
43
72
|
</div>
|
|
44
73
|
</div>
|
|
@@ -12,6 +12,13 @@ const MessageContainer = () => {
|
|
|
12
12
|
const { selectedConversation, setSelectedConversation ,onlineUsers, setOnlineUsers } = useChatUIStore();
|
|
13
13
|
const {socket} = useChatContext();
|
|
14
14
|
|
|
15
|
+
useEffect(() => {
|
|
16
|
+
if (selectedConversation?._id && socket) {
|
|
17
|
+
socket.emit("joinChat", selectedConversation._id); // Join chat room
|
|
18
|
+
}
|
|
19
|
+
}, [selectedConversation?._id, socket]);
|
|
20
|
+
|
|
21
|
+
|
|
15
22
|
useEffect(() => {
|
|
16
23
|
if (!socket) return;
|
|
17
24
|
|
|
@@ -12,7 +12,8 @@ const MessageInput = () => {
|
|
|
12
12
|
const { userId } = useChatContext();
|
|
13
13
|
const { selectedConversation } = useChatUIStore();
|
|
14
14
|
const [message, setMessage] = useState(""); // State for storing the message input
|
|
15
|
-
const { mutate: sendMessage } = useMessageMutation();
|
|
15
|
+
// const { mutate: sendMessage } = useMessageMutation();
|
|
16
|
+
const mutation = useMessageMutation(); // useMutation hook to send message
|
|
16
17
|
const [typingUser, setTypingUser] = useState<string | null>(null);
|
|
17
18
|
const [isSending, setIsSending] = useState(false);
|
|
18
19
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
@@ -40,20 +41,25 @@ const MessageInput = () => {
|
|
|
40
41
|
userId,
|
|
41
42
|
});
|
|
42
43
|
}
|
|
43
|
-
},
|
|
44
|
+
}, 200);
|
|
44
45
|
|
|
45
46
|
return () => clearTimeout(typingTimeout);
|
|
46
47
|
}, [message, socket, selectedConversation?._id, userId]);
|
|
47
48
|
|
|
49
|
+
|
|
48
50
|
useEffect(() => {
|
|
49
|
-
if (!socket) return;
|
|
51
|
+
if (!socket || !selectedConversation?._id) return;
|
|
50
52
|
|
|
51
|
-
const handleTyping = ({ userId }: { userId: string }) => {
|
|
52
|
-
|
|
53
|
+
const handleTyping = ({ userId, chatId }: { userId: string; chatId: string }) => {
|
|
54
|
+
if (chatId === selectedConversation._id) {
|
|
55
|
+
setTypingUser(userId);
|
|
56
|
+
}
|
|
53
57
|
};
|
|
54
|
-
|
|
55
|
-
const handleStopTyping = ({ userId }: { userId: string }) => {
|
|
56
|
-
|
|
58
|
+
|
|
59
|
+
const handleStopTyping = ({ userId, chatId }: { userId: string; chatId: string }) => {
|
|
60
|
+
if (chatId === selectedConversation._id) {
|
|
61
|
+
setTypingUser((prev) => (prev === userId ? null : prev));
|
|
62
|
+
}
|
|
57
63
|
};
|
|
58
64
|
|
|
59
65
|
socket.on("typing", handleTyping);
|
|
@@ -63,27 +69,7 @@ const MessageInput = () => {
|
|
|
63
69
|
socket.off("typing", handleTyping);
|
|
64
70
|
socket.off("stopTyping", handleStopTyping);
|
|
65
71
|
};
|
|
66
|
-
}, [socket]);
|
|
67
|
-
|
|
68
|
-
// useEffect(() => {
|
|
69
|
-
// if (message) {
|
|
70
|
-
// setIsTyping(true);
|
|
71
|
-
// socket.emit("typing", {
|
|
72
|
-
// chatId: selectedConversation?._id,
|
|
73
|
-
// userId,
|
|
74
|
-
// });
|
|
75
|
-
// }
|
|
76
|
-
|
|
77
|
-
// // Clear typing indicator when user stops typing
|
|
78
|
-
// const typingTimeout = setTimeout(() => {
|
|
79
|
-
// if (message === "") {
|
|
80
|
-
// setIsTyping(false);
|
|
81
|
-
// socket.emit("stopTyping", { chatId: selectedConversation?._id, userId });
|
|
82
|
-
// }
|
|
83
|
-
// }, 2000);
|
|
84
|
-
|
|
85
|
-
// return () => clearTimeout(typingTimeout);
|
|
86
|
-
// }, [message, socket, selectedConversation?._id, userId]);
|
|
72
|
+
}, [socket, selectedConversation?._id]);
|
|
87
73
|
|
|
88
74
|
const handleSubmit = useCallback(
|
|
89
75
|
async (e: any) => {
|
|
@@ -94,18 +80,48 @@ const MessageInput = () => {
|
|
|
94
80
|
try {
|
|
95
81
|
console.log("📤 Sending message:", message);
|
|
96
82
|
|
|
97
|
-
if (selectedConversation?._id) {
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
83
|
+
// if (selectedConversation?._id) {
|
|
84
|
+
// const response = await sendMessage({
|
|
85
|
+
// chatId: selectedConversation.participantDetails._id,
|
|
86
|
+
// senderId: userId,
|
|
87
|
+
// message,
|
|
88
|
+
// });
|
|
89
|
+
|
|
90
|
+
// // You can log or handle the response here
|
|
91
|
+
// console.log('Response from sendMessage:', response);
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
// socket.emit("sendMessage", {
|
|
95
|
+
// chatId: selectedConversation._id,
|
|
96
|
+
// message,
|
|
97
|
+
// senderId: userId,
|
|
98
|
+
// receiverId: selectedConversation.participantDetails._id,
|
|
99
|
+
// });
|
|
100
|
+
// }
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
mutation.mutate({
|
|
105
|
+
chatId: selectedConversation?.participantDetails._id,
|
|
106
|
+
senderId: userId,
|
|
107
|
+
message,
|
|
108
|
+
}, {
|
|
109
|
+
onSuccess: (data) => {
|
|
110
|
+
console.log('Response from sendMessage:', data);
|
|
111
|
+
// After successfully sending the message, emit the socket event
|
|
112
|
+
socket.emit("sendMessage", {
|
|
113
|
+
chatId: selectedConversation?._id,
|
|
114
|
+
message,
|
|
115
|
+
messageId:data[1]._id,
|
|
116
|
+
senderId: userId,
|
|
117
|
+
receiverId: selectedConversation?.participantDetails._id,
|
|
118
|
+
});
|
|
119
|
+
},
|
|
120
|
+
onError: (error) => {
|
|
121
|
+
console.error("❌ Error in sending message:", error);
|
|
122
|
+
},
|
|
123
|
+
});
|
|
124
|
+
|
|
109
125
|
} catch (error) {
|
|
110
126
|
console.error("❌ Error sending message:", error);
|
|
111
127
|
} finally {
|
|
@@ -132,16 +148,17 @@ const MessageInput = () => {
|
|
|
132
148
|
</button>
|
|
133
149
|
</div>
|
|
134
150
|
|
|
135
|
-
{typingUser && typingUser !== userId && !isSending && (
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
151
|
+
{typingUser && typingUser !== userId && typingUser === selectedConversation?.participantDetails?._id && !isSending && (
|
|
152
|
+
<div className="typingIndicator">
|
|
153
|
+
<div className="loader">
|
|
154
|
+
<div className="ball" />
|
|
155
|
+
<div className="ball" />
|
|
156
|
+
<div className="ball" />
|
|
157
|
+
typing
|
|
158
|
+
</div>
|
|
159
|
+
</div>
|
|
160
|
+
)}
|
|
161
|
+
|
|
145
162
|
</form>
|
|
146
163
|
);
|
|
147
164
|
};
|
|
@@ -29,13 +29,22 @@ const Messages = () => {
|
|
|
29
29
|
const handleNewMessage = (newMessage:any) => {
|
|
30
30
|
newMessage.shouldShake = true;
|
|
31
31
|
console.log("📩 New message received:", newMessage);
|
|
32
|
-
|
|
32
|
+
// setMessages([...messages, newMessage[1]]);
|
|
33
|
+
setMessages((prevMessages) => [...prevMessages, newMessage]);
|
|
33
34
|
};
|
|
35
|
+
|
|
36
|
+
const handleStatusUpdate = ({ messageId, status }) => {
|
|
37
|
+
setMessages(prev => prev.map(msg =>
|
|
38
|
+
msg._id === messageId ? { ...msg, status } : msg
|
|
39
|
+
));
|
|
40
|
+
};
|
|
34
41
|
|
|
35
|
-
|
|
42
|
+
socket.on("newMessage", handleNewMessage);
|
|
43
|
+
socket.on("messageStatusUpdated", handleStatusUpdate);
|
|
36
44
|
|
|
37
45
|
return () => {
|
|
38
|
-
|
|
46
|
+
socket.off("newMessage", handleNewMessage);
|
|
47
|
+
socket.off("messageStatusUpdated", handleStatusUpdate);
|
|
39
48
|
};
|
|
40
49
|
}, [socket,setMessages, messages]);
|
|
41
50
|
|
|
@@ -43,7 +52,27 @@ const Messages = () => {
|
|
|
43
52
|
setTimeout(() => {
|
|
44
53
|
lastMessageRef.current?.scrollIntoView({ behavior: "smooth" });
|
|
45
54
|
}, 100);
|
|
46
|
-
}, [messages]);
|
|
55
|
+
}, [ messages]);
|
|
56
|
+
|
|
57
|
+
useEffect(() => {
|
|
58
|
+
if (!socket || !messages.length) return;
|
|
59
|
+
|
|
60
|
+
const observer = new IntersectionObserver((entries) => {
|
|
61
|
+
entries.forEach(entry => {
|
|
62
|
+
if (entry.isIntersecting) {
|
|
63
|
+
const messageId = entry.target.getAttribute('data-message-id');
|
|
64
|
+
if (messageId) {
|
|
65
|
+
socket.emit('confirmDelivery', { messageId });
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
}, { threshold: 0.5 });
|
|
70
|
+
|
|
71
|
+
const messageElements = document.querySelectorAll('[data-message-id]');
|
|
72
|
+
messageElements.forEach(el => observer.observe(el));
|
|
73
|
+
|
|
74
|
+
return () => observer.disconnect();
|
|
75
|
+
}, [messages, socket]);
|
|
47
76
|
|
|
48
77
|
if (isLoading) {
|
|
49
78
|
return <p>Loading messages...</p>;
|
|
@@ -57,18 +86,33 @@ const Messages = () => {
|
|
|
57
86
|
console.log("📩 Messages Length:", messages?.length);
|
|
58
87
|
|
|
59
88
|
return (
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
89
|
+
// <div className="chatMessages">
|
|
90
|
+
// {messages?.length > 0 ? (
|
|
91
|
+
// messages?.map((message: any) => (
|
|
92
|
+
// <div key={message._id} ref={lastMessageRef}>
|
|
93
|
+
// <Message message={message} />
|
|
94
|
+
// </div>
|
|
95
|
+
// ))
|
|
96
|
+
// ) : (
|
|
97
|
+
// <p style={{ textAlign: "center" }}>Send a message to start the conversation</p>
|
|
98
|
+
// )}
|
|
99
|
+
// </div>
|
|
100
|
+
<div className="chatMessages">
|
|
101
|
+
{messages?.length > 0 ? (
|
|
102
|
+
messages?.map((message: any) =>
|
|
103
|
+
// Check if the message object is valid and has an _id before rendering
|
|
104
|
+
message ? (
|
|
105
|
+
<div key={message._id} ref={lastMessageRef}>
|
|
106
|
+
<Message message={message} />
|
|
107
|
+
</div>
|
|
108
|
+
) : null
|
|
109
|
+
)
|
|
110
|
+
) : (
|
|
111
|
+
<p style={{ textAlign: "center" }}>
|
|
112
|
+
Send a message to start the conversation
|
|
113
|
+
</p>
|
|
114
|
+
)}
|
|
115
|
+
</div>
|
|
72
116
|
);
|
|
73
117
|
};
|
|
74
118
|
export default Messages;
|
|
@@ -1,13 +1,31 @@
|
|
|
1
1
|
// import { useSocketContext } from "../../context/SocketContext";
|
|
2
2
|
// import useConversation from "../../zustand/useConversation";
|
|
3
3
|
|
|
4
|
+
import { useChatContext } from "../../providers/ChatProvider";
|
|
4
5
|
import useChatUIStore from "../../stores/Zustant";
|
|
5
6
|
import { ConversationProps } from "../../types/type";
|
|
6
7
|
|
|
7
8
|
const Conversation = ({ conversation, lastIdx }: ConversationProps) => {
|
|
8
9
|
const { setSelectedConversation } = useChatUIStore();
|
|
10
|
+
const { socket } = useChatContext();
|
|
9
11
|
console.log(conversation);
|
|
10
12
|
|
|
13
|
+
const handleSelectConversation = async () => {
|
|
14
|
+
setSelectedConversation(conversation);
|
|
15
|
+
|
|
16
|
+
const lastMessageId = conversation.lastMessageId; // You should have this in conversation data
|
|
17
|
+
|
|
18
|
+
if (lastMessageId) {
|
|
19
|
+
// ✅ Notify server via socket
|
|
20
|
+
socket.emit("messageRead", {
|
|
21
|
+
messageId: lastMessageId,
|
|
22
|
+
receiverId: conversation.participantDetails._id, // or receiverId
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
|
|
11
29
|
// const isSelected = selectedConversation?._id === conversation._id;
|
|
12
30
|
// const { onlineUsers } = useSocketContext();
|
|
13
31
|
// const isOnline = onlineUsers.includes(conversation._id);
|
|
@@ -7,18 +7,23 @@ import { ApiResponse } from "../types/type";
|
|
|
7
7
|
export const getAllConversationData = async (userid: string) => {
|
|
8
8
|
try {
|
|
9
9
|
const res = await apiClient.get<ApiResponse>(`${Path.getconversation}/${userid}`);
|
|
10
|
-
|
|
10
|
+
if (res.data) {
|
|
11
|
+
console.log("API Response: ", res.data);
|
|
12
|
+
|
|
13
|
+
}
|
|
11
14
|
// Access conversations with participant details from the API response
|
|
12
|
-
const
|
|
13
|
-
|
|
15
|
+
const conversationsWithParticipantDetails = res.data.serviceInfo;
|
|
16
|
+
console.log("conversationsWithParticipantDetails", res.data.serviceInfo);
|
|
17
|
+
|
|
14
18
|
// If needed, you can map the conversations in the specific structure
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
+
// const formattedConversations = conversationsWithParticipantDetails?.map((conversation) => ({
|
|
20
|
+
// _id: conversation._id,
|
|
21
|
+
// participantDetails: conversation.participantDetails,
|
|
22
|
+
// }));
|
|
23
|
+
// console.log("formattedConversations", formattedConversations);
|
|
19
24
|
|
|
20
25
|
// Return the formatted conversations
|
|
21
|
-
return
|
|
26
|
+
return conversationsWithParticipantDetails;
|
|
22
27
|
} catch (error: any) {
|
|
23
28
|
console.error("ERROR: ", error);
|
|
24
29
|
// Optionally log the error to an external logger
|
package/src/stores/Zustant.ts
CHANGED
|
@@ -1,21 +1,24 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
-
import {create} from
|
|
2
|
+
import { create } from "zustand";
|
|
3
3
|
|
|
4
4
|
interface ChatUIState {
|
|
5
5
|
isChatOpen: boolean;
|
|
6
6
|
unreadCount: number;
|
|
7
7
|
selectedConversation: {
|
|
8
|
-
participantDetails:{
|
|
8
|
+
participantDetails: {
|
|
9
9
|
_id: string;
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
}
|
|
14
|
-
_id:string;
|
|
10
|
+
profilePic: string;
|
|
11
|
+
firstname: string;
|
|
12
|
+
idpic: string;
|
|
13
|
+
};
|
|
14
|
+
_id: string;
|
|
15
15
|
} | null;
|
|
16
|
-
setSelectedConversation: (
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
setSelectedConversation: (
|
|
17
|
+
selectedConversation: ChatUIState["selectedConversation"]
|
|
18
|
+
) => void;
|
|
19
|
+
messages: { id: string; text: string; sender: string; status: string }[];
|
|
20
|
+
setMessages: (messages: ChatUIState["messages"] | ((prev: ChatUIState["messages"]) => ChatUIState["messages"])) => void;
|
|
21
|
+
updateMessageStatus: (messageId: string, status: string) => void;
|
|
19
22
|
toggleChat: () => void;
|
|
20
23
|
incrementUnreadCount: () => void;
|
|
21
24
|
onlineUsers: string[];
|
|
@@ -28,7 +31,16 @@ const useChatUIStore = create<ChatUIState>((set) => ({
|
|
|
28
31
|
unreadCount: 0,
|
|
29
32
|
selectedConversation: null,
|
|
30
33
|
messages: [],
|
|
31
|
-
|
|
34
|
+
setMessages: (updater: any) =>
|
|
35
|
+
set((state) => ({
|
|
36
|
+
messages: typeof updater === "function" ? updater(state.messages) : updater,
|
|
37
|
+
})),
|
|
38
|
+
updateMessageStatus: (messageId, status) =>
|
|
39
|
+
set((state) => ({
|
|
40
|
+
messages: state.messages.map((msg) =>
|
|
41
|
+
msg.id === messageId ? { ...msg, status } : msg
|
|
42
|
+
),
|
|
43
|
+
})),
|
|
32
44
|
setSelectedConversation: (selectedConversation) => set({ selectedConversation }),
|
|
33
45
|
toggleChat: () => set((state) => ({ isChatOpen: !state.isChatOpen })),
|
|
34
46
|
onlineUsers: [],
|
|
@@ -37,4 +49,4 @@ const useChatUIStore = create<ChatUIState>((set) => ({
|
|
|
37
49
|
resetUnreadCount: () => set({ unreadCount: 0 }),
|
|
38
50
|
}));
|
|
39
51
|
|
|
40
|
-
export default useChatUIStore;
|
|
52
|
+
export default useChatUIStore;
|
package/src/types/type.ts
CHANGED
|
@@ -21,6 +21,15 @@ export interface ParticipantDetails {
|
|
|
21
21
|
export interface Conversation {
|
|
22
22
|
_id: string;
|
|
23
23
|
createdAt: string;
|
|
24
|
+
lastMessage:{
|
|
25
|
+
_id: string;
|
|
26
|
+
senderId: string;
|
|
27
|
+
message: string;
|
|
28
|
+
chatId: string;
|
|
29
|
+
createdAt: string;
|
|
30
|
+
updatedAt: string;
|
|
31
|
+
__v: number;
|
|
32
|
+
},
|
|
24
33
|
updatedAt: string;
|
|
25
34
|
__v: number;
|
|
26
35
|
participantDetails: ParticipantDetails;
|
|
@@ -33,7 +42,7 @@ export interface ServiceInfo {
|
|
|
33
42
|
export interface ApiResponse {
|
|
34
43
|
success: boolean;
|
|
35
44
|
message: string;
|
|
36
|
-
serviceInfo:
|
|
45
|
+
serviceInfo: Conversation[];
|
|
37
46
|
}
|
|
38
47
|
|
|
39
48
|
export interface ConversationProps {
|
|
@@ -48,4 +57,6 @@ export interface ConversationProps {
|
|
|
48
57
|
_id: string;
|
|
49
58
|
};
|
|
50
59
|
lastIdx: boolean;
|
|
51
|
-
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export type MessageStatus = 'sent' | 'delivered' | 'read';
|