@pubuduth-aplicy/chat-ui 2.1.42 → 2.1.43
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
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
-
import {
|
|
2
|
+
import { useEffect, useRef } from "react";
|
|
3
3
|
import Message from "./Message";
|
|
4
4
|
import { useChatContext } from "../../providers/ChatProvider";
|
|
5
|
-
import { useMessages } from "../../hooks/queries/useChatApi";
|
|
6
5
|
import useChatUIStore from "../../stores/Zustant";
|
|
7
6
|
import { useInfiniteQuery } from "@tanstack/react-query";
|
|
8
7
|
import { fetchMessages } from "../../service/messageService";
|
|
@@ -13,16 +12,11 @@ const Messages = () => {
|
|
|
13
12
|
const { selectedConversation, setMessages, messages } = useChatUIStore();
|
|
14
13
|
const { userId, socket } = useChatContext();
|
|
15
14
|
const { ref, inView } = useInView();
|
|
16
|
-
const scrollContainerRef = useRef<HTMLDivElement>(null);
|
|
17
|
-
const [isInitialLoad, setIsInitialLoad] = useState(true);
|
|
18
|
-
const [isAutoScrolling, setIsAutoScrolling] = useState(false);
|
|
19
|
-
const [prevMessagesLength, setPrevMessagesLength] = useState(0);
|
|
20
|
-
const loadingRef = useRef(false);
|
|
21
15
|
// const { data, isLoading, isError, error } = useMessages(selectedConversation?._id, userId);
|
|
22
16
|
|
|
23
17
|
const lastMessageRef = useRef<HTMLDivElement>(null);
|
|
24
18
|
|
|
25
|
-
const { data, fetchNextPage,
|
|
19
|
+
const { data, fetchNextPage, isFetchingNextPage } =
|
|
26
20
|
useInfiniteQuery({
|
|
27
21
|
queryKey: ["messages", selectedConversation?._id, userId],
|
|
28
22
|
queryFn: ({ pageParam = 1 }) =>
|
|
@@ -31,120 +25,8 @@ const Messages = () => {
|
|
|
31
25
|
return lastPage.nextPage; // Use the nextPage from API response
|
|
32
26
|
},
|
|
33
27
|
initialPageParam: 1,
|
|
34
|
-
})
|
|
28
|
+
})
|
|
35
29
|
|
|
36
|
-
const [isLoadingMore, setIsLoadingMore] = useState(false);
|
|
37
|
-
const scrollHeightBeforeLoad = useRef(0);
|
|
38
|
-
|
|
39
|
-
const handleScroll = useCallback(() => {
|
|
40
|
-
if (!scrollContainerRef.current || isFetchingNextPage || !hasNextPage) return;
|
|
41
|
-
|
|
42
|
-
const { scrollTop, scrollHeight, clientHeight } = scrollContainerRef.current;
|
|
43
|
-
|
|
44
|
-
// Load more when scrolled near the top (100px threshold)
|
|
45
|
-
if (scrollTop < 100) {
|
|
46
|
-
// Save current scroll height before loading
|
|
47
|
-
scrollHeightBeforeLoad.current = scrollHeight;
|
|
48
|
-
setIsLoadingMore(true);
|
|
49
|
-
fetchNextPage().finally(() => setIsLoadingMore(false));
|
|
50
|
-
}
|
|
51
|
-
}, [fetchNextPage, isFetchingNextPage, hasNextPage]);
|
|
52
|
-
|
|
53
|
-
useEffect(() => {
|
|
54
|
-
if (isLoadingMore && scrollContainerRef.current && scrollHeightBeforeLoad.current) {
|
|
55
|
-
// After new messages are loaded, adjust scroll position to maintain the same view
|
|
56
|
-
const container = scrollContainerRef.current;
|
|
57
|
-
const newScrollHeight = container.scrollHeight;
|
|
58
|
-
container.scrollTop = newScrollHeight - scrollHeightBeforeLoad.current;
|
|
59
|
-
}
|
|
60
|
-
}, [messages.length, isLoadingMore]);
|
|
61
|
-
|
|
62
|
-
// Scroll to bottom for new messages
|
|
63
|
-
useEffect(() => {
|
|
64
|
-
if (messages.length > 0 && !isLoadingMore) {
|
|
65
|
-
setTimeout(() => {
|
|
66
|
-
lastMessageRef.current?.scrollIntoView({ behavior: "smooth" });
|
|
67
|
-
}, 100);
|
|
68
|
-
}
|
|
69
|
-
}, [messages.length, isLoadingMore]);
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
// const {
|
|
73
|
-
// data,
|
|
74
|
-
// fetchNextPage,
|
|
75
|
-
// hasNextPage,
|
|
76
|
-
// isFetchingNextPage,
|
|
77
|
-
// isLoading,
|
|
78
|
-
// } = useInfiniteQuery({
|
|
79
|
-
// queryKey: ["messages", selectedConversation?._id, userId],
|
|
80
|
-
// queryFn: ({ pageParam = 1 }) =>
|
|
81
|
-
// fetchMessages(selectedConversation?._id, userId, pageParam),
|
|
82
|
-
// getNextPageParam: (lastPage) => lastPage.nextPage ?? undefined,
|
|
83
|
-
// onSuccess: (data) => {
|
|
84
|
-
// const allMessages = data.pages.flatMap(page => page.messages);
|
|
85
|
-
// setMessages(allMessages);
|
|
86
|
-
|
|
87
|
-
// // Scroll to bottom on initial load
|
|
88
|
-
// if (isInitialLoad && scrollContainerRef.current) {
|
|
89
|
-
// setTimeout(() => {
|
|
90
|
-
// scrollContainerRef.current?.scrollTo({
|
|
91
|
-
// top: scrollContainerRef.current.scrollHeight,
|
|
92
|
-
// behavior: 'auto'
|
|
93
|
-
// });
|
|
94
|
-
// setIsInitialLoad(false);
|
|
95
|
-
// }, 100);
|
|
96
|
-
// }
|
|
97
|
-
// },
|
|
98
|
-
// });
|
|
99
|
-
|
|
100
|
-
// Maintain scroll position when loading older messages
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
// useEffect(() => {
|
|
104
|
-
// console.log('scrollContainerRef',scrollContainerRef.current);
|
|
105
|
-
|
|
106
|
-
// if (!scrollContainerRef.current || isInitialLoad) return;
|
|
107
|
-
|
|
108
|
-
// if (isFetchingNextPage) {
|
|
109
|
-
// // Store current scroll position before loading
|
|
110
|
-
// const container = scrollContainerRef.current;
|
|
111
|
-
// const scrollTopBefore = container.scrollTop;
|
|
112
|
-
// const scrollHeightBefore = container.scrollHeight;
|
|
113
|
-
// console.log(container,'scrollHeightBefore',scrollHeightBefore,'container',scrollTopBefore);
|
|
114
|
-
|
|
115
|
-
// loadingRef.current = true;
|
|
116
|
-
|
|
117
|
-
// return () => {
|
|
118
|
-
// // After messages are loaded, adjust scroll position
|
|
119
|
-
// requestAnimationFrame(() => {
|
|
120
|
-
// container.scrollTop = container.scrollHeight - scrollHeightBefore + scrollTopBefore;
|
|
121
|
-
// loadingRef.current = false;
|
|
122
|
-
// });
|
|
123
|
-
// };
|
|
124
|
-
// }
|
|
125
|
-
// }, [isFetchingNextPage, isInitialLoad]);
|
|
126
|
-
|
|
127
|
-
// Add this useEffect to handle new messages
|
|
128
|
-
// useEffect(() => {
|
|
129
|
-
// if (!scrollContainerRef.current || loadingRef.current) return;
|
|
130
|
-
|
|
131
|
-
// const container = scrollContainerRef.current;
|
|
132
|
-
// console.log("container",container);
|
|
133
|
-
|
|
134
|
-
// const isNearBottom = container.scrollHeight - container.scrollTop - container.clientHeight < 100;
|
|
135
|
-
|
|
136
|
-
// // Only auto-scroll if we're near bottom or it's a new message
|
|
137
|
-
// if (isNearBottom || messages.length > prevMessagesLength) {
|
|
138
|
-
// setIsAutoScrolling(true);
|
|
139
|
-
// container.scrollTo({
|
|
140
|
-
// top: container.scrollHeight,
|
|
141
|
-
// behavior: messages.length > prevMessagesLength ? 'smooth' : 'auto'
|
|
142
|
-
// });
|
|
143
|
-
// setTimeout(() => setIsAutoScrolling(false), 500);
|
|
144
|
-
// }
|
|
145
|
-
|
|
146
|
-
// setPrevMessagesLength(messages.length);
|
|
147
|
-
// }, [messages.length]);
|
|
148
30
|
|
|
149
31
|
useEffect(() => {
|
|
150
32
|
if (inView) {
|
|
@@ -152,13 +34,6 @@ const Messages = () => {
|
|
|
152
34
|
}
|
|
153
35
|
}, [fetchNextPage, inView]);
|
|
154
36
|
|
|
155
|
-
// useEffect(() => {
|
|
156
|
-
// if (data) {
|
|
157
|
-
// console.log(data,'message data');
|
|
158
|
-
|
|
159
|
-
// setMessages(data.messages);
|
|
160
|
-
// }
|
|
161
|
-
// }, [selectedConversation?._id, data]);
|
|
162
37
|
|
|
163
38
|
useEffect(() => {
|
|
164
39
|
if (data) {
|
|
@@ -173,20 +48,20 @@ useEffect(() => {
|
|
|
173
48
|
useEffect(() => {
|
|
174
49
|
if (!socket || !selectedConversation?._id) return;
|
|
175
50
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
51
|
+
const handleNewMessage = (newMessage: any) => {
|
|
52
|
+
newMessage.shouldShake = true;
|
|
53
|
+
console.log("📩 New message received:", newMessage);
|
|
54
|
+
setMessages((prevMessages) => [...prevMessages, newMessage[1]]);
|
|
55
|
+
};
|
|
181
56
|
|
|
182
|
-
const handleNewMessage = (newMessage: any) => {
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
57
|
+
// const handleNewMessage = (newMessage: any) => {
|
|
58
|
+
// newMessage.shouldShake = true;
|
|
59
|
+
// console.log("📩 New message received:", newMessage);
|
|
60
|
+
// setMessages((prevMessages) => {
|
|
61
|
+
// const updatedMessages = [...prevMessages, newMessage];
|
|
62
|
+
// return [...new Map(updatedMessages.map(m => [m._id, m])).values()]; // Prevent duplicates
|
|
63
|
+
// });
|
|
64
|
+
// };
|
|
190
65
|
|
|
191
66
|
|
|
192
67
|
const handleStatusUpdate = ({
|
|
@@ -197,7 +72,7 @@ useEffect(() => {
|
|
|
197
72
|
status: string;
|
|
198
73
|
}) => {
|
|
199
74
|
setMessages((prev) =>
|
|
200
|
-
prev.map((msg) => (msg.
|
|
75
|
+
prev.map((msg) => (msg.id === messageId ? { ...msg, status } : msg))
|
|
201
76
|
);
|
|
202
77
|
};
|
|
203
78
|
|
|
@@ -275,7 +150,7 @@ console.log("📩 Messages:", messages);
|
|
|
275
150
|
|
|
276
151
|
return (
|
|
277
152
|
<div className="chatMessages"
|
|
278
|
-
|
|
153
|
+
|
|
279
154
|
style={{ overflowY: 'auto', height: '100%', position: 'relative' }}
|
|
280
155
|
>
|
|
281
156
|
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
// import { useSocketContext } from "../../context/SocketContext";
|
|
2
2
|
// import useConversation from "../../zustand/useConversation";
|
|
3
3
|
|
|
4
|
+
import { useEffect } from "react";
|
|
4
5
|
import { useChatContext } from "../../providers/ChatProvider";
|
|
5
6
|
import useChatUIStore from "../../stores/Zustant";
|
|
6
7
|
import { ConversationProps } from "../../types/type";
|
|
7
8
|
|
|
8
9
|
const Conversation = ({ conversation, lastIdx }: ConversationProps) => {
|
|
9
|
-
const { setSelectedConversation } = useChatUIStore();
|
|
10
|
+
const { setSelectedConversation, setOnlineUsers,onlineUsers } = useChatUIStore();
|
|
10
11
|
const { socket } = useChatContext();
|
|
11
12
|
console.log(conversation);
|
|
12
13
|
|
|
@@ -25,9 +26,22 @@ const handleSelectConversation = async () => {
|
|
|
25
26
|
}
|
|
26
27
|
};
|
|
27
28
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
29
|
+
useEffect(() => {
|
|
30
|
+
if (!socket) return;
|
|
31
|
+
|
|
32
|
+
const handleOnlineUsers = (users: string[]) => {
|
|
33
|
+
setOnlineUsers(users);
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
socket.on("getOnlineUsers", handleOnlineUsers);
|
|
37
|
+
|
|
38
|
+
return () => {
|
|
39
|
+
socket.off("getOnlineUsers", handleOnlineUsers);
|
|
40
|
+
};
|
|
41
|
+
}, [socket, setOnlineUsers]);
|
|
42
|
+
|
|
43
|
+
const isUserOnline = conversation?.participantDetails?._id &&
|
|
44
|
+
onlineUsers?.includes(conversation.participantDetails._id);
|
|
31
45
|
return (
|
|
32
46
|
<>
|
|
33
47
|
<div
|
|
@@ -39,17 +53,22 @@ const handleSelectConversation = async () => {
|
|
|
39
53
|
className="chatSidebarConversationImg"
|
|
40
54
|
src={conversation.participantDetails?.profilePic|| conversation.participantDetails?.idpic}
|
|
41
55
|
/>
|
|
56
|
+
<p className="text-sm text-[#12bbb5]">
|
|
57
|
+
{isUserOnline ? "Online" : "Offline"}
|
|
58
|
+
</p>
|
|
42
59
|
<div className="chatSidebarConversationContainer">
|
|
43
60
|
{/* <div className="chatSidebarConversationInnerDiv"> */}
|
|
44
61
|
<p className="text-sm text-gray-500">
|
|
45
62
|
{conversation.participantDetails?.firstname}
|
|
46
63
|
</p>
|
|
47
64
|
<p className="chatSidebarConversationOuterDiv">
|
|
48
|
-
|
|
65
|
+
{conversation.lastMessage.message}
|
|
49
66
|
</p>
|
|
50
67
|
{/* </div> */}
|
|
51
68
|
</div>
|
|
52
|
-
<span className="text-xs text-gray-500">
|
|
69
|
+
<span className="text-xs text-gray-500">
|
|
70
|
+
{new Date(conversation.lastMessage.createdAt).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })}
|
|
71
|
+
</span>
|
|
53
72
|
</div>
|
|
54
73
|
|
|
55
74
|
{!lastIdx && <div className="divider my-0 py-0 h-1" />}
|