@pubuduth-aplicy/chat-ui 2.1.36 → 2.1.38
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 +2 -1
- package/src/components/messages/MessageInput.tsx +0 -22
- package/src/components/messages/Messages.tsx +375 -101
- package/src/components/sidebar/Conversation.tsx +7 -8
- package/src/declarations.d.ts +16 -10
- package/src/hooks/queries/useChatApi.ts +10 -10
- package/src/service/messageService.ts +4 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pubuduth-aplicy/chat-ui",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.38",
|
|
4
4
|
"description": "This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.",
|
|
5
5
|
"license": "ISC",
|
|
6
6
|
"author": "",
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
"axios": "^1.8.2",
|
|
17
17
|
"react": "^19.0.0",
|
|
18
18
|
"react-dom": "^19.0.0",
|
|
19
|
+
"react-intersection-observer": "^9.16.0",
|
|
19
20
|
"socket.io-client": "^4.8.1",
|
|
20
21
|
"zustand": "^5.0.3"
|
|
21
22
|
},
|
|
@@ -79,28 +79,6 @@ const MessageInput = () => {
|
|
|
79
79
|
setIsSending(true);
|
|
80
80
|
try {
|
|
81
81
|
console.log("📤 Sending message:", message);
|
|
82
|
-
|
|
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
82
|
mutation.mutate({
|
|
105
83
|
chatId: selectedConversation?.participantDetails._id,
|
|
106
84
|
senderId: userId,
|
|
@@ -1,119 +1,393 @@
|
|
|
1
|
+
// /* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
+
// import { useCallback, useEffect, useRef } from "react";
|
|
3
|
+
// import Message from "./Message";
|
|
4
|
+
// import { useChatContext } from "../../providers/ChatProvider";
|
|
5
|
+
// import { useMessages } from "../../hooks/queries/useChatApi";
|
|
6
|
+
// import useChatUIStore from "../../stores/Zustant";
|
|
7
|
+
// import { useInfiniteQuery } from "@tanstack/react-query";
|
|
8
|
+
// import { fetchMessages } from "../../service/messageService";
|
|
9
|
+
// import { useInView } from "react-intersection-observer";
|
|
10
|
+
|
|
11
|
+
// const Messages = () => {
|
|
12
|
+
// const { selectedConversation, setMessages, messages } = useChatUIStore();
|
|
13
|
+
// const { userId, socket } = useChatContext();
|
|
14
|
+
// const { ref, inView } = useInView();
|
|
15
|
+
// const previousScrollHeight = useRef(0);
|
|
16
|
+
// const scrollContainerRef = useRef<HTMLDivElement>(null);
|
|
17
|
+
|
|
18
|
+
// // const { data, isLoading, isError, error } = useMessages(selectedConversation?._id, userId);
|
|
19
|
+
|
|
20
|
+
// const lastMessageRef = useRef<HTMLDivElement>(null);
|
|
21
|
+
|
|
22
|
+
// const { data, fetchNextPage, hasNextPage, isFetchingNextPage } =
|
|
23
|
+
// useInfiniteQuery({
|
|
24
|
+
// queryKey: ["messages", selectedConversation?._id, userId],
|
|
25
|
+
// queryFn: ({ pageParam = 1 }) =>
|
|
26
|
+
// fetchMessages(selectedConversation?._id, userId, pageParam),
|
|
27
|
+
// initialPageParam: 1,
|
|
28
|
+
// getNextPageParam: (lastPage, allPages) => {
|
|
29
|
+
// return lastPage.messages.length ? allPages.length + 1: undefined;
|
|
30
|
+
// },
|
|
31
|
+
// });
|
|
32
|
+
|
|
33
|
+
// useEffect(() => {
|
|
34
|
+
// if (inView) {
|
|
35
|
+
// fetchNextPage();
|
|
36
|
+
// }
|
|
37
|
+
// }, [fetchNextPage, inView]);
|
|
38
|
+
|
|
39
|
+
// // useEffect(() => {
|
|
40
|
+
// // if (data) {
|
|
41
|
+
// // console.log(data,'message data');
|
|
42
|
+
|
|
43
|
+
// // setMessages(data.messages);
|
|
44
|
+
// // }
|
|
45
|
+
// // }, [selectedConversation?._id, data]);
|
|
46
|
+
|
|
47
|
+
// useEffect(() => {
|
|
48
|
+
// if (data) {
|
|
49
|
+
// const allMessages = data.pages.flatMap(page => page.messages);
|
|
50
|
+
// setMessages(allMessages);
|
|
51
|
+
|
|
52
|
+
// if (scrollContainerRef.current) {
|
|
53
|
+
// const newScrollHeight = scrollContainerRef.current.scrollHeight;
|
|
54
|
+
// scrollContainerRef.current.scrollTop = newScrollHeight - previousScrollHeight.current;
|
|
55
|
+
// }
|
|
56
|
+
// }
|
|
57
|
+
// }, [data]);
|
|
58
|
+
|
|
59
|
+
// // Listen for new messages from the server
|
|
60
|
+
// useEffect(() => {
|
|
61
|
+
// if (!socket || !selectedConversation?._id) return;
|
|
62
|
+
|
|
63
|
+
// // const handleNewMessage = (newMessage: any) => {
|
|
64
|
+
// // newMessage.shouldShake = true;
|
|
65
|
+
// // console.log("📩 New message received:", newMessage);
|
|
66
|
+
// // setMessages((prevMessages) => [...prevMessages, newMessage[1]]);
|
|
67
|
+
// // };
|
|
68
|
+
|
|
69
|
+
// const handleNewMessage = (newMessage: any) => {
|
|
70
|
+
// newMessage.shouldShake = true;
|
|
71
|
+
// console.log("📩 New message received:", newMessage);
|
|
72
|
+
// setMessages((prevMessages) => {
|
|
73
|
+
// const updatedMessages = [...prevMessages, newMessage];
|
|
74
|
+
// return [...new Map(updatedMessages.map(m => [m._id, m])).values()]; // Prevent duplicates
|
|
75
|
+
// });
|
|
76
|
+
// };
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
// const handleStatusUpdate = ({
|
|
80
|
+
// messageId,
|
|
81
|
+
// status,
|
|
82
|
+
// }: {
|
|
83
|
+
// messageId: string;
|
|
84
|
+
// status: string;
|
|
85
|
+
// }) => {
|
|
86
|
+
// setMessages((prev) =>
|
|
87
|
+
// prev.map((msg) => (msg._id === messageId ? { ...msg, status } : msg))
|
|
88
|
+
// );
|
|
89
|
+
// };
|
|
90
|
+
|
|
91
|
+
// socket.on("newMessage", handleNewMessage);
|
|
92
|
+
// socket.on("messageStatusUpdated", handleStatusUpdate);
|
|
93
|
+
|
|
94
|
+
// return () => {
|
|
95
|
+
// socket.off("newMessage", handleNewMessage);
|
|
96
|
+
// socket.off("messageStatusUpdated", handleStatusUpdate);
|
|
97
|
+
// };
|
|
98
|
+
// }, [socket, setMessages, messages]);
|
|
99
|
+
|
|
100
|
+
// // useEffect(() => {
|
|
101
|
+
// // setTimeout(() => {
|
|
102
|
+
// // lastMessageRef.current?.scrollIntoView({ behavior: "smooth" });
|
|
103
|
+
// // }, 100);
|
|
104
|
+
// // }, [messages]);
|
|
105
|
+
|
|
106
|
+
// useEffect(() => {
|
|
107
|
+
// if (!scrollContainerRef.current) return;
|
|
108
|
+
|
|
109
|
+
// const { scrollTop, scrollHeight, clientHeight } = scrollContainerRef.current;
|
|
110
|
+
// const isAtBottom = scrollHeight - scrollTop <= clientHeight + 100;
|
|
111
|
+
|
|
112
|
+
// if (isAtBottom) {
|
|
113
|
+
// setTimeout(() => {
|
|
114
|
+
// lastMessageRef.current?.scrollIntoView({ behavior: "smooth" });
|
|
115
|
+
// }, 100);
|
|
116
|
+
// }
|
|
117
|
+
// }, [messages]);
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
// useEffect(() => {
|
|
121
|
+
// if (!socket || !messages.length) return;
|
|
122
|
+
|
|
123
|
+
// const observer = new IntersectionObserver(
|
|
124
|
+
// (entries) => {
|
|
125
|
+
// entries.forEach((entry) => {
|
|
126
|
+
// if (entry.isIntersecting) {
|
|
127
|
+
// const messageId = entry.target.getAttribute("data-message-id");
|
|
128
|
+
// if (messageId) {
|
|
129
|
+
// socket.emit("confirmDelivery", { messageId });
|
|
130
|
+
// }
|
|
131
|
+
// }
|
|
132
|
+
// });
|
|
133
|
+
// },
|
|
134
|
+
// { threshold: 0.5 }
|
|
135
|
+
// );
|
|
136
|
+
|
|
137
|
+
// const messageElements = document.querySelectorAll("[data-message-id]");
|
|
138
|
+
// messageElements.forEach((el) => observer.observe(el));
|
|
139
|
+
|
|
140
|
+
// return () => observer.disconnect();
|
|
141
|
+
// }, [messages, socket]);
|
|
142
|
+
|
|
143
|
+
// const handleScroll = useCallback(() => {
|
|
144
|
+
// if (!scrollContainerRef.current || isFetchingNextPage || !hasNextPage) return;
|
|
145
|
+
|
|
146
|
+
// const { scrollTop } = scrollContainerRef.current;
|
|
147
|
+
|
|
148
|
+
// if (scrollTop < 50) { // Fetch next page only if close to the top
|
|
149
|
+
// fetchNextPage();
|
|
150
|
+
// }
|
|
151
|
+
// }, [fetchNextPage, isFetchingNextPage, hasNextPage]);
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
// useEffect(() => {
|
|
156
|
+
// const scrollContainer = scrollContainerRef.current;
|
|
157
|
+
// if (scrollContainer) {
|
|
158
|
+
// scrollContainer.addEventListener("scroll", handleScroll);
|
|
159
|
+
// return () => scrollContainer.removeEventListener("scroll", handleScroll);
|
|
160
|
+
// }
|
|
161
|
+
// }, [handleScroll]);
|
|
162
|
+
|
|
163
|
+
// console.log("📩 Messages:", messages);
|
|
164
|
+
// console.log("📩 Messages Length:", messages?.length);
|
|
165
|
+
|
|
166
|
+
// return (
|
|
167
|
+
// <div className="chatMessages">
|
|
168
|
+
|
|
169
|
+
// <div ref={ref} className="my-8">
|
|
170
|
+
// {isFetchingNextPage ? '<Loading isLoading={isFetchingNextPage} /> ': null}
|
|
171
|
+
// </div>
|
|
172
|
+
// {messages?.length > 0 ? (
|
|
173
|
+
// messages?.map((message: any) =>
|
|
174
|
+
// // Check if the message object is valid and has an _id before rendering
|
|
175
|
+
// message ? (
|
|
176
|
+
// <div key={message._id} ref={lastMessageRef}>
|
|
177
|
+
// <Message message={message} />
|
|
178
|
+
// </div>
|
|
179
|
+
// ) : null
|
|
180
|
+
// )
|
|
181
|
+
// ) : (
|
|
182
|
+
// <p style={{ textAlign: "center" }}>
|
|
183
|
+
// Send a message to start the conversation
|
|
184
|
+
// </p>
|
|
185
|
+
// )}
|
|
186
|
+
|
|
187
|
+
// </div>
|
|
188
|
+
// );
|
|
189
|
+
// };
|
|
190
|
+
// export default Messages;
|
|
191
|
+
|
|
192
|
+
|
|
1
193
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
-
import { useEffect, useRef } from "react";
|
|
3
|
-
// import useGetMessages from "../../hooks/useGetMessages";
|
|
4
|
-
// import MessageSkeleton from "../skeletons/MessageSkeleton";
|
|
194
|
+
import { useCallback, useEffect, useRef, useState } from "react";
|
|
5
195
|
import Message from "./Message";
|
|
6
196
|
import { useChatContext } from "../../providers/ChatProvider";
|
|
7
197
|
import { useMessages } from "../../hooks/queries/useChatApi";
|
|
8
198
|
import useChatUIStore from "../../stores/Zustant";
|
|
9
|
-
|
|
199
|
+
import { useInfiniteQuery } from "@tanstack/react-query";
|
|
200
|
+
import { fetchMessages } from "../../service/messageService";// Assuming you have a loading spinner component
|
|
10
201
|
|
|
11
202
|
const Messages = () => {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
203
|
+
const { selectedConversation, setMessages, messages } = useChatUIStore();
|
|
204
|
+
const { userId, socket } = useChatContext();
|
|
205
|
+
const scrollContainerRef = useRef<HTMLDivElement>(null);
|
|
206
|
+
const [isAutoScrolling, setIsAutoScrolling] = useState(false);
|
|
207
|
+
const [initialLoad, setInitialLoad] = useState(true);
|
|
208
|
+
|
|
209
|
+
const {
|
|
210
|
+
data,
|
|
211
|
+
fetchNextPage,
|
|
212
|
+
hasNextPage,
|
|
213
|
+
isFetchingNextPage,
|
|
214
|
+
isLoading,
|
|
215
|
+
} = useInfiniteQuery({
|
|
216
|
+
queryKey: ["messages", selectedConversation?._id, userId],
|
|
217
|
+
queryFn: ({ pageParam = 1 }) =>
|
|
218
|
+
fetchMessages(selectedConversation?._id, userId, pageParam),
|
|
219
|
+
initialPageParam: 1,
|
|
220
|
+
getNextPageParam: (lastPage, allPages) => {
|
|
221
|
+
return lastPage.messages.length ? allPages.length + 1 : undefined;
|
|
222
|
+
},
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
// Handle merging paginated data with messages
|
|
226
|
+
useEffect(() => {
|
|
227
|
+
if (data) {
|
|
228
|
+
const allMessages = data.pages.flatMap(page => page.messages);
|
|
229
|
+
setMessages(allMessages);
|
|
230
|
+
}
|
|
231
|
+
}, [data, setMessages]);
|
|
232
|
+
|
|
233
|
+
// Handle scroll position when new messages are loaded
|
|
234
|
+
useEffect(() => {
|
|
235
|
+
if (!scrollContainerRef.current || initialLoad) return;
|
|
236
|
+
|
|
237
|
+
const container = scrollContainerRef.current;
|
|
238
|
+
if (isFetchingNextPage) {
|
|
239
|
+
// Store current scroll position before loading more messages
|
|
240
|
+
const scrollTopBefore = container.scrollTop;
|
|
241
|
+
const scrollHeightBefore = container.scrollHeight;
|
|
242
|
+
|
|
243
|
+
// After messages are loaded, adjust scroll position to maintain view
|
|
244
|
+
requestAnimationFrame(() => {
|
|
245
|
+
container.scrollTop = container.scrollHeight - scrollHeightBefore + scrollTopBefore;
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
}, [isFetchingNextPage, initialLoad]);
|
|
249
|
+
|
|
250
|
+
// Handle initial scroll to bottom
|
|
251
|
+
useEffect(() => {
|
|
252
|
+
if (scrollContainerRef.current && messages.length > 0 && initialLoad) {
|
|
253
|
+
scrollContainerRef.current.scrollTop = scrollContainerRef.current.scrollHeight;
|
|
254
|
+
setInitialLoad(false);
|
|
255
|
+
}
|
|
256
|
+
}, [messages.length, initialLoad]);
|
|
257
|
+
|
|
258
|
+
// Auto-scroll to bottom when new message arrives and user is near bottom
|
|
259
|
+
useEffect(() => {
|
|
260
|
+
if (!scrollContainerRef.current || isAutoScrolling) return;
|
|
261
|
+
|
|
262
|
+
const container = scrollContainerRef.current;
|
|
263
|
+
const isNearBottom = container.scrollHeight - container.scrollTop - container.clientHeight < 100;
|
|
264
|
+
|
|
265
|
+
if (isNearBottom) {
|
|
266
|
+
setIsAutoScrolling(true);
|
|
267
|
+
container.scrollTo({
|
|
268
|
+
top: container.scrollHeight,
|
|
269
|
+
behavior: "smooth"
|
|
270
|
+
});
|
|
271
|
+
setTimeout(() => setIsAutoScrolling(false), 500);
|
|
272
|
+
}
|
|
273
|
+
}, [messages.length, isAutoScrolling]);
|
|
274
|
+
|
|
275
|
+
// Socket event handlers
|
|
276
|
+
useEffect(() => {
|
|
277
|
+
if (!socket || !selectedConversation?._id) return;
|
|
278
|
+
|
|
279
|
+
const handleNewMessage = (newMessage: any) => {
|
|
280
|
+
newMessage.shouldShake = true;
|
|
281
|
+
setMessages((prevMessages) => {
|
|
282
|
+
// Prevent duplicates
|
|
283
|
+
if (prevMessages.some(msg => msg._id === newMessage._id)) {
|
|
284
|
+
return prevMessages;
|
|
285
|
+
}
|
|
286
|
+
return [...prevMessages, newMessage];
|
|
287
|
+
});
|
|
288
|
+
};
|
|
289
|
+
|
|
290
|
+
const handleStatusUpdate = ({
|
|
291
|
+
messageId,
|
|
292
|
+
status,
|
|
293
|
+
}: {
|
|
294
|
+
messageId: string;
|
|
295
|
+
status: string;
|
|
296
|
+
}) => {
|
|
297
|
+
setMessages((prev) =>
|
|
298
|
+
prev.map((msg) => (msg._id === messageId ? { ...msg, status } : msg))
|
|
299
|
+
);
|
|
300
|
+
};
|
|
301
|
+
|
|
302
|
+
socket.on("newMessage", handleNewMessage);
|
|
303
|
+
socket.on("messageStatusUpdated", handleStatusUpdate);
|
|
304
|
+
|
|
305
|
+
return () => {
|
|
306
|
+
socket.off("newMessage", handleNewMessage);
|
|
307
|
+
socket.off("messageStatusUpdated", handleStatusUpdate);
|
|
308
|
+
};
|
|
309
|
+
}, [socket, setMessages, selectedConversation?._id]);
|
|
310
|
+
|
|
311
|
+
// Delivery confirmation observer
|
|
312
|
+
useEffect(() => {
|
|
313
|
+
if (!socket || !messages.length) return;
|
|
314
|
+
|
|
315
|
+
const observer = new IntersectionObserver(
|
|
316
|
+
(entries) => {
|
|
317
|
+
entries.forEach((entry) => {
|
|
318
|
+
if (entry.isIntersecting) {
|
|
319
|
+
const messageId = entry.target.getAttribute("data-message-id");
|
|
320
|
+
if (messageId) {
|
|
321
|
+
socket.emit("confirmDelivery", { messageId });
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
});
|
|
325
|
+
},
|
|
326
|
+
{ threshold: 0.5 }
|
|
327
|
+
);
|
|
328
|
+
|
|
329
|
+
const messageElements = document.querySelectorAll("[data-message-id]");
|
|
330
|
+
messageElements.forEach((el) => observer.observe(el));
|
|
331
|
+
|
|
332
|
+
return () => observer.disconnect();
|
|
333
|
+
}, [messages, socket]);
|
|
334
|
+
|
|
335
|
+
// Scroll handler for infinite loading
|
|
336
|
+
const handleScroll = useCallback(() => {
|
|
337
|
+
if (!scrollContainerRef.current || isFetchingNextPage || !hasNextPage) return;
|
|
338
|
+
|
|
339
|
+
const container = scrollContainerRef.current;
|
|
340
|
+
const scrollTop = container.scrollTop;
|
|
341
|
+
|
|
342
|
+
// Load more messages when scrolled near the top
|
|
343
|
+
if (scrollTop < 100 && !isFetchingNextPage) {
|
|
344
|
+
fetchNextPage();
|
|
345
|
+
}
|
|
346
|
+
}, [fetchNextPage, isFetchingNextPage, hasNextPage]);
|
|
347
|
+
|
|
348
|
+
useEffect(() => {
|
|
349
|
+
const scrollContainer = scrollContainerRef.current;
|
|
350
|
+
if (scrollContainer) {
|
|
351
|
+
scrollContainer.addEventListener("scroll", handleScroll);
|
|
352
|
+
return () => scrollContainer.removeEventListener("scroll", handleScroll);
|
|
353
|
+
}
|
|
354
|
+
}, [handleScroll]);
|
|
355
|
+
|
|
356
|
+
if (isLoading && !messages.length) {
|
|
357
|
+
return <LoadingSpinner />;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
return (
|
|
361
|
+
<div
|
|
362
|
+
ref={scrollContainerRef}
|
|
363
|
+
className="chatMessages"
|
|
364
|
+
style={{ overflowY: "auto", height: "100%", position: "relative" }}
|
|
365
|
+
>
|
|
366
|
+
{isFetchingNextPage && (
|
|
367
|
+
<div className="loading-indicator">
|
|
368
|
+
loading
|
|
369
|
+
</div>
|
|
370
|
+
)}
|
|
371
|
+
|
|
101
372
|
{messages?.length > 0 ? (
|
|
102
|
-
messages
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
373
|
+
messages.map((message: any) => (
|
|
374
|
+
message && (
|
|
375
|
+
<div
|
|
376
|
+
key={message._id}
|
|
377
|
+
data-message-id={message._id}
|
|
378
|
+
ref={messages.indexOf(message) === messages.length - 1 ? lastMessageRef : null}
|
|
379
|
+
>
|
|
106
380
|
<Message message={message} />
|
|
107
381
|
</div>
|
|
108
|
-
)
|
|
109
|
-
)
|
|
382
|
+
)
|
|
383
|
+
))
|
|
110
384
|
) : (
|
|
111
385
|
<p style={{ textAlign: "center" }}>
|
|
112
386
|
Send a message to start the conversation
|
|
113
387
|
</p>
|
|
114
388
|
)}
|
|
115
389
|
</div>
|
|
116
|
-
|
|
390
|
+
);
|
|
117
391
|
};
|
|
118
|
-
export default Messages;
|
|
119
392
|
|
|
393
|
+
export default Messages;
|
|
@@ -13,16 +13,15 @@ console.log(conversation);
|
|
|
13
13
|
const handleSelectConversation = async () => {
|
|
14
14
|
setSelectedConversation(conversation);
|
|
15
15
|
|
|
16
|
-
const
|
|
16
|
+
const unreadMessages = conversation.unreadMessageIds || []; // Get all unread message IDs
|
|
17
|
+
|
|
18
|
+
if (unreadMessages.length > 0) {
|
|
19
|
+
console.log("Emitting messageRead for messages:", unreadMessages);
|
|
17
20
|
|
|
18
|
-
if (lastMessageId) {
|
|
19
|
-
// ✅ Notify server via socket
|
|
20
21
|
socket.emit("messageRead", {
|
|
21
|
-
|
|
22
|
-
receiverId: conversation.participantDetails._id,
|
|
22
|
+
messageIds: unreadMessages, // Send all unread message IDs
|
|
23
|
+
receiverId: conversation.participantDetails._id,
|
|
23
24
|
});
|
|
24
|
-
|
|
25
|
-
|
|
26
25
|
}
|
|
27
26
|
};
|
|
28
27
|
|
|
@@ -34,7 +33,7 @@ const handleSelectConversation = async () => {
|
|
|
34
33
|
<div
|
|
35
34
|
className={` chatSidebarConversationMain
|
|
36
35
|
`}
|
|
37
|
-
onClick={
|
|
36
|
+
onClick={handleSelectConversation}
|
|
38
37
|
>
|
|
39
38
|
<img
|
|
40
39
|
className="chatSidebarConversationImg"
|
package/src/declarations.d.ts
CHANGED
|
@@ -1,16 +1,22 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
1
2
|
// src/declarations.d.ts
|
|
2
3
|
declare module '*.css' {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
const content: string;
|
|
5
|
+
export default content;
|
|
6
|
+
}
|
|
6
7
|
|
|
7
8
|
declare module '*.png' {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
const content: string;
|
|
10
|
+
export default content;
|
|
11
|
+
}
|
|
11
12
|
|
|
12
13
|
declare module '*.svg' {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
14
|
+
const content: string;
|
|
15
|
+
export default content;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
declare module '@pubuduth-aplicy/chat-ui';
|
|
19
|
+
declare module '@pubuduth-aplicy/chat-ui' {
|
|
20
|
+
export function ChatUI(props: any): JSX.Element;
|
|
21
|
+
// Define other exports and types as needed
|
|
22
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
2
|
import { useQuery } from "@tanstack/react-query";
|
|
3
3
|
import { getAllConversationData } from "../../service/sidebarApi";
|
|
4
|
-
import { fetchMessages } from "../../service/messageService";
|
|
4
|
+
// import { fetchMessages } from "../../service/messageService";
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
export const useGetConversations = (id: any) => {
|
|
@@ -15,12 +15,12 @@ export const useGetConversations = (id: any) => {
|
|
|
15
15
|
});
|
|
16
16
|
};
|
|
17
17
|
|
|
18
|
-
export const useMessages = (chatId: string| undefined, userid: string) => {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
};
|
|
18
|
+
// export const useMessages = (chatId: string| undefined, userid: string) => {
|
|
19
|
+
// return useQuery({
|
|
20
|
+
// queryKey: ['messages', chatId, userid],
|
|
21
|
+
// queryFn: () => {
|
|
22
|
+
// console.log('Fetching messages for:', chatId, userid);
|
|
23
|
+
// return fetchMessages(chatId, userid);
|
|
24
|
+
// },
|
|
25
|
+
// });
|
|
26
|
+
// };
|
|
@@ -10,9 +10,11 @@ export const sendMessage = async ({ chatId,senderId, message }: { chatId: any; s
|
|
|
10
10
|
};
|
|
11
11
|
|
|
12
12
|
|
|
13
|
-
export const fetchMessages = async (chatId: string|undefined, userid: string) => {
|
|
13
|
+
export const fetchMessages = async (chatId: string|undefined, userid: string,pagenum:number) => {
|
|
14
14
|
try {
|
|
15
|
-
const response = await apiClient.get(`${Path.getmessage}/${chatId}/${userid}
|
|
15
|
+
const response = await apiClient.get(`${Path.getmessage}/${chatId}/${userid}`,{
|
|
16
|
+
params: { pagenum, limit: 20 },
|
|
17
|
+
});
|
|
16
18
|
console.log(response); // Check the full response
|
|
17
19
|
return response.data; // Ensure 'data' exists or adjust accordingly
|
|
18
20
|
} catch (error) {
|