@pubuduth-aplicy/chat-ui 2.1.38 → 2.1.39
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/messages/Messages.tsx +84 -308
package/package.json
CHANGED
|
@@ -1,291 +1,74 @@
|
|
|
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
|
-
|
|
193
1
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
194
|
-
import { useCallback, useEffect, useRef
|
|
2
|
+
import { useCallback, useEffect, useRef } from "react";
|
|
195
3
|
import Message from "./Message";
|
|
196
4
|
import { useChatContext } from "../../providers/ChatProvider";
|
|
197
5
|
import { useMessages } from "../../hooks/queries/useChatApi";
|
|
198
6
|
import useChatUIStore from "../../stores/Zustant";
|
|
199
7
|
import { useInfiniteQuery } from "@tanstack/react-query";
|
|
200
|
-
import { fetchMessages } from "../../service/messageService"
|
|
8
|
+
import { fetchMessages } from "../../service/messageService";
|
|
9
|
+
import { useInView } from "react-intersection-observer";
|
|
201
10
|
|
|
202
11
|
const Messages = () => {
|
|
203
12
|
const { selectedConversation, setMessages, messages } = useChatUIStore();
|
|
204
13
|
const { userId, socket } = useChatContext();
|
|
14
|
+
const { ref, inView } = useInView();
|
|
205
15
|
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
16
|
|
|
233
|
-
//
|
|
234
|
-
useEffect(() => {
|
|
235
|
-
if (!scrollContainerRef.current || initialLoad) return;
|
|
17
|
+
// const { data, isLoading, isError, error } = useMessages(selectedConversation?._id, userId);
|
|
236
18
|
|
|
237
|
-
|
|
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]);
|
|
19
|
+
const lastMessageRef = useRef<HTMLDivElement>(null);
|
|
249
20
|
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
21
|
+
const { data, fetchNextPage, hasNextPage, isFetchingNextPage } =
|
|
22
|
+
useInfiniteQuery({
|
|
23
|
+
queryKey: ["messages", selectedConversation?._id, userId],
|
|
24
|
+
queryFn: ({ pageParam = 1 }) =>
|
|
25
|
+
fetchMessages(selectedConversation?._id, userId, pageParam),
|
|
26
|
+
initialPageParam: 1,
|
|
27
|
+
getNextPageParam: (lastPage, allPages) => {
|
|
28
|
+
return lastPage.messages.length ? allPages.length + 1: undefined;
|
|
29
|
+
},
|
|
30
|
+
});
|
|
257
31
|
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
32
|
+
useEffect(() => {
|
|
33
|
+
if (inView) {
|
|
34
|
+
fetchNextPage();
|
|
35
|
+
}
|
|
36
|
+
}, [fetchNextPage, inView]);
|
|
261
37
|
|
|
262
|
-
|
|
263
|
-
|
|
38
|
+
// useEffect(() => {
|
|
39
|
+
// if (data) {
|
|
40
|
+
// console.log(data,'message data');
|
|
41
|
+
|
|
42
|
+
// setMessages(data.messages);
|
|
43
|
+
// }
|
|
44
|
+
// }, [selectedConversation?._id, data]);
|
|
264
45
|
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
setTimeout(() => setIsAutoScrolling(false), 500);
|
|
272
|
-
}
|
|
273
|
-
}, [messages.length, isAutoScrolling]);
|
|
46
|
+
useEffect(() => {
|
|
47
|
+
if (data) {
|
|
48
|
+
const allMessages = data.pages.flatMap(page => page.messages);
|
|
49
|
+
setMessages(allMessages);
|
|
50
|
+
}
|
|
51
|
+
}, [data]);
|
|
274
52
|
|
|
275
|
-
//
|
|
53
|
+
// Listen for new messages from the server
|
|
276
54
|
useEffect(() => {
|
|
277
55
|
if (!socket || !selectedConversation?._id) return;
|
|
278
56
|
|
|
279
|
-
const handleNewMessage = (newMessage: any) => {
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
57
|
+
// const handleNewMessage = (newMessage: any) => {
|
|
58
|
+
// newMessage.shouldShake = true;
|
|
59
|
+
// console.log("📩 New message received:", newMessage);
|
|
60
|
+
// setMessages((prevMessages) => [...prevMessages, newMessage[1]]);
|
|
61
|
+
// };
|
|
62
|
+
|
|
63
|
+
const handleNewMessage = (newMessage: any) => {
|
|
64
|
+
newMessage.shouldShake = true;
|
|
65
|
+
console.log("📩 New message received:", newMessage);
|
|
66
|
+
setMessages((prevMessages) => {
|
|
67
|
+
const updatedMessages = [...prevMessages, newMessage];
|
|
68
|
+
return [...new Map(updatedMessages.map(m => [m._id, m])).values()]; // Prevent duplicates
|
|
69
|
+
});
|
|
70
|
+
};
|
|
71
|
+
|
|
289
72
|
|
|
290
73
|
const handleStatusUpdate = ({
|
|
291
74
|
messageId,
|
|
@@ -306,9 +89,16 @@ const Messages = () => {
|
|
|
306
89
|
socket.off("newMessage", handleNewMessage);
|
|
307
90
|
socket.off("messageStatusUpdated", handleStatusUpdate);
|
|
308
91
|
};
|
|
309
|
-
}, [socket, setMessages,
|
|
92
|
+
}, [socket, setMessages, messages]);
|
|
93
|
+
|
|
94
|
+
useEffect(() => {
|
|
95
|
+
if (messages.length > 0) {
|
|
96
|
+
setTimeout(() => {
|
|
97
|
+
lastMessageRef.current?.scrollIntoView({ behavior: "smooth" });
|
|
98
|
+
}, 100);
|
|
99
|
+
}
|
|
100
|
+
}, [messages.length]);
|
|
310
101
|
|
|
311
|
-
// Delivery confirmation observer
|
|
312
102
|
useEffect(() => {
|
|
313
103
|
if (!socket || !messages.length) return;
|
|
314
104
|
|
|
@@ -332,62 +122,48 @@ const Messages = () => {
|
|
|
332
122
|
return () => observer.disconnect();
|
|
333
123
|
}, [messages, socket]);
|
|
334
124
|
|
|
335
|
-
// Scroll handler for infinite loading
|
|
336
125
|
const handleScroll = useCallback(() => {
|
|
337
126
|
if (!scrollContainerRef.current || isFetchingNextPage || !hasNextPage) return;
|
|
338
|
-
|
|
339
|
-
const container = scrollContainerRef.current;
|
|
340
|
-
const scrollTop = container.scrollTop;
|
|
341
127
|
|
|
342
|
-
|
|
343
|
-
|
|
128
|
+
const { scrollTop } = scrollContainerRef.current;
|
|
129
|
+
|
|
130
|
+
if (scrollTop < 100) {
|
|
344
131
|
fetchNextPage();
|
|
345
132
|
}
|
|
346
133
|
}, [fetchNextPage, isFetchingNextPage, hasNextPage]);
|
|
347
134
|
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
return <LoadingSpinner />;
|
|
358
|
-
}
|
|
135
|
+
// useEffect(() => {
|
|
136
|
+
// const scrollContainer = scrollContainerRef.current;
|
|
137
|
+
// if (scrollContainer) {
|
|
138
|
+
// scrollContainer.addEventListener("scroll", handleScroll);
|
|
139
|
+
// return () => scrollContainer.removeEventListener("scroll", handleScroll);
|
|
140
|
+
// }
|
|
141
|
+
// }, [handleScroll]);
|
|
142
|
+
console.log("📩 Messages:", messages);
|
|
143
|
+
console.log("📩 Messages Length:", messages?.length);
|
|
359
144
|
|
|
360
145
|
return (
|
|
361
|
-
<div
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
{isFetchingNextPage && (
|
|
367
|
-
<div className="loading-indicator">
|
|
368
|
-
loading
|
|
369
|
-
</div>
|
|
370
|
-
)}
|
|
371
|
-
|
|
146
|
+
<div className="chatMessages">
|
|
147
|
+
|
|
148
|
+
<div ref={ref} className="my-8">
|
|
149
|
+
{isFetchingNextPage ? '<Loading isLoading={isFetchingNextPage} /> ': null}
|
|
150
|
+
</div>
|
|
372
151
|
{messages?.length > 0 ? (
|
|
373
|
-
messages
|
|
374
|
-
message
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
data-message-id={message._id}
|
|
378
|
-
ref={messages.indexOf(message) === messages.length - 1 ? lastMessageRef : null}
|
|
379
|
-
>
|
|
152
|
+
messages?.map((message: any) =>
|
|
153
|
+
// Check if the message object is valid and has an _id before rendering
|
|
154
|
+
message ? (
|
|
155
|
+
<div key={message._id} ref={lastMessageRef}>
|
|
380
156
|
<Message message={message} />
|
|
381
157
|
</div>
|
|
382
|
-
)
|
|
383
|
-
)
|
|
158
|
+
) : null
|
|
159
|
+
)
|
|
384
160
|
) : (
|
|
385
161
|
<p style={{ textAlign: "center" }}>
|
|
386
162
|
Send a message to start the conversation
|
|
387
163
|
</p>
|
|
388
164
|
)}
|
|
165
|
+
|
|
389
166
|
</div>
|
|
390
167
|
);
|
|
391
168
|
};
|
|
392
|
-
|
|
393
|
-
export default Messages;
|
|
169
|
+
export default Messages;
|