@pubuduth-aplicy/chat-ui 2.1.26 → 2.1.28
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,46 +1,64 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
-
import React, { useState } from
|
|
3
|
-
import { useMessageMutation } from
|
|
4
|
-
import { useChatContext } from
|
|
5
|
-
import useChatUIStore from
|
|
6
|
-
import paperplane from
|
|
2
|
+
import React, { useCallback, useState } from "react";
|
|
3
|
+
import { useMessageMutation } from "../../hooks/mutations/useSendMessage";
|
|
4
|
+
import { useChatContext } from "../../providers/ChatProvider";
|
|
5
|
+
import useChatUIStore from "../../stores/Zustant";
|
|
6
|
+
import paperplane from "../../assets/icons8-send-50.png";
|
|
7
7
|
// import { PaperPlaneRight } from '@phosphor-icons/react'; // Assuming you're using icons from Phosphor Icons library
|
|
8
8
|
// import useSendMessage from '../../hooks/useSendMessage'; // Importing the useSendMessage hook
|
|
9
9
|
|
|
10
10
|
const MessageInput = () => {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
const { socket } = useChatContext();
|
|
12
|
+
const { userId } = useChatContext();
|
|
13
|
+
const { selectedConversation } = useChatUIStore();
|
|
14
14
|
const [message, setMessage] = useState(""); // State for storing the message input
|
|
15
15
|
const { mutate: sendMessage } = useMessageMutation();
|
|
16
16
|
|
|
17
|
-
const
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
17
|
+
const [isSending, setIsSending] = useState(false);
|
|
18
|
+
|
|
19
|
+
const handleSubmit = useCallback(
|
|
20
|
+
async (e: any) => {
|
|
21
|
+
e.preventDefault();
|
|
22
|
+
if (!message || isSending) return;
|
|
23
|
+
|
|
24
|
+
setIsSending(true);
|
|
25
|
+
try {
|
|
26
|
+
console.log("📤 Sending message:", message);
|
|
27
|
+
|
|
28
|
+
if (selectedConversation?._id) {
|
|
29
|
+
sendMessage({
|
|
30
|
+
chatId: selectedConversation.participantDetails._id,
|
|
31
|
+
senderId: userId,
|
|
32
|
+
message,
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
socket.emit("sendMessage", {
|
|
36
|
+
chatId: selectedConversation._id,
|
|
37
|
+
message,
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
} catch (error) {
|
|
41
|
+
console.error("❌ Error sending message:", error);
|
|
42
|
+
} finally {
|
|
43
|
+
setIsSending(false);
|
|
44
|
+
setMessage("");
|
|
27
45
|
}
|
|
28
|
-
|
|
29
|
-
|
|
46
|
+
},
|
|
47
|
+
[message, selectedConversation, userId, isSending]
|
|
48
|
+
);
|
|
30
49
|
|
|
31
50
|
return (
|
|
32
|
-
<form className=
|
|
33
|
-
|
|
34
|
-
<div className='chatMessageInputdiv' >
|
|
51
|
+
<form className="chatMessageInputform" onSubmit={handleSubmit}>
|
|
52
|
+
<div className="chatMessageInputdiv">
|
|
35
53
|
<input
|
|
36
|
-
type=
|
|
37
|
-
className=
|
|
38
|
-
placeholder=
|
|
54
|
+
type="text"
|
|
55
|
+
className="chatMessageInput"
|
|
56
|
+
placeholder="Send a message"
|
|
39
57
|
value={message}
|
|
40
58
|
onChange={(e) => setMessage(e.target.value)} // Update message state as the user types
|
|
41
59
|
/>
|
|
42
|
-
<button type=
|
|
43
|
-
<img src={paperplane} alt="send" />
|
|
60
|
+
<button type="submit" className="chatMessageInputSubmit">
|
|
61
|
+
<img width={10} height={10} src={paperplane} alt="send" />
|
|
44
62
|
{/* {loading ? <div className='loading loading-spinner'></div> : <PaperPlaneRight />} Show loading spinner if loading */}
|
|
45
63
|
</button>
|
|
46
64
|
</div>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
-
import { useEffect, useRef } from "react";
|
|
2
|
+
import { useEffect, useRef, useState } from "react";
|
|
3
3
|
// import useGetMessages from "../../hooks/useGetMessages";
|
|
4
4
|
// import MessageSkeleton from "../skeletons/MessageSkeleton";
|
|
5
5
|
import Message from "./Message";
|
|
@@ -10,22 +10,47 @@ import useChatUIStore from "../../stores/Zustant";
|
|
|
10
10
|
|
|
11
11
|
const Messages = () => {
|
|
12
12
|
const { selectedConversation } = useChatUIStore()
|
|
13
|
-
const {userId}=useChatContext()
|
|
14
|
-
console.log(userId);
|
|
13
|
+
const {userId,socket}=useChatContext()
|
|
15
14
|
const { data: messages, isLoading, isError, error } = useMessages(selectedConversation?._id, userId);
|
|
16
|
-
|
|
17
|
-
console.log("isLoading",isLoading);
|
|
18
|
-
console.log("error",error);
|
|
19
|
-
console.log("messages",messages);
|
|
15
|
+
const [localMessages, setLocalMessages] = useState<any[]>([]);
|
|
20
16
|
|
|
21
17
|
const lastMessageRef = useRef<HTMLDivElement>(null);
|
|
22
18
|
|
|
19
|
+
useEffect(() => {
|
|
20
|
+
if (messages?.messages) {
|
|
21
|
+
setLocalMessages(messages.messages);
|
|
22
|
+
}
|
|
23
|
+
}, [messages]);
|
|
24
|
+
|
|
25
|
+
// Listen for new messages from the server
|
|
26
|
+
useEffect(() => {
|
|
27
|
+
if (!socket) return;
|
|
28
|
+
|
|
29
|
+
const handleNewMessage = (newMessage: any) => {
|
|
30
|
+
setLocalMessages((prevMessages) => [...prevMessages, newMessage]);
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
socket.on("newMessage", handleNewMessage);
|
|
34
|
+
|
|
35
|
+
return () => {
|
|
36
|
+
socket.off("newMessage", handleNewMessage);
|
|
37
|
+
};
|
|
38
|
+
}, [socket]);
|
|
39
|
+
|
|
23
40
|
useEffect(() => {
|
|
24
41
|
setTimeout(() => {
|
|
25
42
|
lastMessageRef.current?.scrollIntoView({ behavior: "smooth" });
|
|
26
43
|
}, 100);
|
|
27
44
|
}, [messages]);
|
|
28
45
|
|
|
46
|
+
if (isLoading) {
|
|
47
|
+
return <p>Loading messages...</p>;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (isError) {
|
|
51
|
+
return <p>Error: {error?.message}</p>;
|
|
52
|
+
}
|
|
53
|
+
|
|
29
54
|
return (
|
|
30
55
|
// <div className='px-4 flex-1 overflow-auto'>
|
|
31
56
|
// {!loading &&
|
|
@@ -42,19 +67,33 @@ console.log(userId);
|
|
|
42
67
|
// )}
|
|
43
68
|
// </div>
|
|
44
69
|
|
|
45
|
-
<div className='chatMessages'>
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
</div>
|
|
70
|
+
// <div className='chatMessages'>
|
|
71
|
+
// {messages?.messages.length > 0 &&
|
|
72
|
+
// messages?.messages.map((message: any) => (
|
|
73
|
+
// <div key={message._id} ref={lastMessageRef}>
|
|
74
|
+
// <Message message={message} />
|
|
75
|
+
// </div>
|
|
76
|
+
// ))}
|
|
77
|
+
|
|
78
|
+
// {/* {loading && [...Array(3)].map((_, idx) => <MessageSkeleton key={idx} />)} */}
|
|
79
|
+
// {messages?.length === 0 && (
|
|
80
|
+
// <p style={{textAlign:"center"}}>Send a message to start the conversation</p>
|
|
81
|
+
// )}
|
|
82
|
+
// </div>
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
<div className="chatMessages">
|
|
86
|
+
{localMessages.length > 0 ? (
|
|
87
|
+
localMessages.map((message: any) => (
|
|
88
|
+
<div key={message._id} ref={lastMessageRef}>
|
|
89
|
+
<Message message={message} />
|
|
90
|
+
</div>
|
|
91
|
+
))
|
|
92
|
+
) : (
|
|
93
|
+
<p style={{ textAlign: "center" }}>Send a message to start the conversation</p>
|
|
94
|
+
)}
|
|
95
|
+
</div>
|
|
96
|
+
|
|
58
97
|
);
|
|
59
98
|
};
|
|
60
99
|
export default Messages;
|
|
@@ -8,7 +8,7 @@ export const useMessageMutation = () => {
|
|
|
8
8
|
mutationFn: sendMessage,
|
|
9
9
|
onSuccess: () => {
|
|
10
10
|
console.log("Service submitted successfully!", "success");
|
|
11
|
-
queryClient.invalidateQueries({ queryKey: ['
|
|
11
|
+
queryClient.invalidateQueries({ queryKey: ['messages'] });
|
|
12
12
|
},
|
|
13
13
|
onError: (error: any) => {
|
|
14
14
|
console.error("Failed to submit service data:", error);
|
|
@@ -1,48 +1,65 @@
|
|
|
1
|
-
import React, {
|
|
2
|
-
|
|
1
|
+
import React, {
|
|
2
|
+
createContext,
|
|
3
|
+
useContext,
|
|
4
|
+
ReactNode,
|
|
5
|
+
useEffect,
|
|
6
|
+
useState,
|
|
7
|
+
useRef,
|
|
8
|
+
} from "react";
|
|
9
|
+
import { Socket, io } from "socket.io-client";
|
|
3
10
|
// import { apiClient } from '../lib/api/apiClient';
|
|
4
11
|
// import { S3Client } from '../lib/storage/s3Client';
|
|
5
12
|
// import { CryptoUtils } from '../lib/encryption/cryptoUtils';
|
|
6
13
|
|
|
7
14
|
interface ChatProviderProps {
|
|
8
|
-
// apiUrl: string;
|
|
9
|
-
// s3Config: {
|
|
10
|
-
// bucket: string;
|
|
11
|
-
// region: string;
|
|
12
|
-
// accessKeyId: string;
|
|
13
|
-
// secretAccessKey: string;
|
|
14
|
-
// };
|
|
15
|
+
// apiUrl: string;
|
|
16
|
+
// s3Config: {
|
|
17
|
+
// bucket: string;
|
|
18
|
+
// region: string;
|
|
19
|
+
// accessKeyId: string;
|
|
20
|
+
// secretAccessKey: string;
|
|
21
|
+
// };
|
|
15
22
|
userId: string; // User ID for identification
|
|
16
23
|
children: ReactNode;
|
|
17
24
|
}
|
|
18
25
|
|
|
19
26
|
interface ChatContextType {
|
|
20
|
-
// s3Client: S3Client;
|
|
27
|
+
// s3Client: S3Client;
|
|
21
28
|
socket: Socket;
|
|
22
|
-
// cryptoUtils: CryptoUtils;
|
|
29
|
+
// cryptoUtils: CryptoUtils;
|
|
23
30
|
userId: string;
|
|
24
31
|
}
|
|
25
32
|
|
|
26
33
|
const ChatContext = createContext<ChatContextType | null>(null);
|
|
27
34
|
|
|
28
|
-
export const ChatProvider: React.FC<ChatProviderProps> = ({
|
|
35
|
+
export const ChatProvider: React.FC<ChatProviderProps> = ({
|
|
36
|
+
userId,
|
|
37
|
+
children,
|
|
38
|
+
}) => {
|
|
39
|
+
const socketRef = useRef<Socket | null>(null);
|
|
29
40
|
const [socket, setSocket] = useState<Socket | null>(null);
|
|
30
|
-
const apiUrl=import.meta.env.VITE_APP_BACKEND_PORT
|
|
41
|
+
const apiUrl = import.meta.env.VITE_APP_BACKEND_PORT;
|
|
31
42
|
|
|
32
43
|
useEffect(() => {
|
|
33
|
-
|
|
34
|
-
|
|
44
|
+
if (!socketRef.current) {
|
|
45
|
+
console.log("🔌 Creating new socket connection...");
|
|
46
|
+
const socketInstance = io(apiUrl, { auth: { userId } });
|
|
47
|
+
socketRef.current = socketInstance;
|
|
48
|
+
setSocket(socketInstance);
|
|
49
|
+
}
|
|
35
50
|
|
|
36
51
|
return () => {
|
|
37
|
-
|
|
52
|
+
console.log("❌ Disconnecting socket...");
|
|
53
|
+
socketRef.current?.disconnect();
|
|
54
|
+
socketRef.current = null;
|
|
38
55
|
};
|
|
39
56
|
}, [apiUrl, userId]);
|
|
40
57
|
|
|
41
58
|
if (!socket) return null;
|
|
42
59
|
|
|
43
|
-
// const apiClient = new ApiClient(apiUrl);
|
|
44
|
-
// const s3Client = new S3Client(s3Config);
|
|
45
|
-
// const cryptoUtils = new CryptoUtils();
|
|
60
|
+
// const apiClient = new ApiClient(apiUrl);
|
|
61
|
+
// const s3Client = new S3Client(s3Config);
|
|
62
|
+
// const cryptoUtils = new CryptoUtils();
|
|
46
63
|
|
|
47
64
|
return (
|
|
48
65
|
<ChatContext.Provider value={{ socket, userId }}>
|
|
@@ -54,7 +71,7 @@ const apiUrl=import.meta.env.VITE_APP_BACKEND_PORT
|
|
|
54
71
|
export const useChatContext = () => {
|
|
55
72
|
const context = useContext(ChatContext);
|
|
56
73
|
if (!context) {
|
|
57
|
-
throw new Error(
|
|
74
|
+
throw new Error("useChatContext must be used within a ChatProvider");
|
|
58
75
|
}
|
|
59
76
|
return context;
|
|
60
|
-
};
|
|
77
|
+
};
|
package/src/style/style.css
CHANGED
|
@@ -299,11 +299,13 @@
|
|
|
299
299
|
.chatMessageInputform {
|
|
300
300
|
position: sticky;
|
|
301
301
|
bottom: 0;
|
|
302
|
-
background: #
|
|
302
|
+
background: #dbdbdb;
|
|
303
303
|
padding-left: 1rem;
|
|
304
304
|
padding-right: 1rem;
|
|
305
|
+
padding-top: 0.25rem;
|
|
306
|
+
padding-bottom: 0.25rem;
|
|
305
307
|
margin-top: 0.75rem;
|
|
306
|
-
margin-bottom: 0.75rem;
|
|
308
|
+
/* margin-bottom: 0.75rem; */
|
|
307
309
|
}
|
|
308
310
|
.chatMessageInputdiv {
|
|
309
311
|
display: flex;
|
|
@@ -335,6 +337,7 @@
|
|
|
335
337
|
bottom: 0;
|
|
336
338
|
align-items: center; */
|
|
337
339
|
padding: 8px;
|
|
340
|
+
border-radius: 100%;
|
|
338
341
|
background: #12bbb5;
|
|
339
342
|
}
|
|
340
343
|
|