@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,6 +1,6 @@
1
1
  {
2
2
  "name": "@pubuduth-aplicy/chat-ui",
3
- "version": "2.1.26",
3
+ "version": "2.1.28",
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": "",
@@ -1,46 +1,64 @@
1
1
  /* eslint-disable @typescript-eslint/no-explicit-any */
2
- import React, { 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'
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
- const { socket } = useChatContext();
12
- const {userId}=useChatContext()
13
- const { selectedConversation } = useChatUIStore();
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 handleSubmit = async (e:any) => {
18
- e.preventDefault();
19
- if (!message)
20
- return;
21
- if (selectedConversation?._id) {
22
- // Send message
23
- sendMessage({ chatId:selectedConversation.participantDetails._id,senderId:userId, message });
24
-
25
- // Emit message to socket
26
- socket.emit('sendMessage', { chatId: selectedConversation._id, message });
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
- setMessage("");
29
- };
46
+ },
47
+ [message, selectedConversation, userId, isSending]
48
+ );
30
49
 
31
50
  return (
32
- <form className='chatMessageInputform' onSubmit={handleSubmit}>
33
-
34
- <div className='chatMessageInputdiv' >
51
+ <form className="chatMessageInputform" onSubmit={handleSubmit}>
52
+ <div className="chatMessageInputdiv">
35
53
  <input
36
- type='text'
37
- className='chatMessageInput'
38
- placeholder='Send a message'
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='submit' className='chatMessageInputSubmit'>
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
- // useListenMessages();
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
- {messages?.messages.length > 0 &&
47
- messages?.messages.map((message: any) => (
48
- <div key={message._id} ref={lastMessageRef}>
49
- <Message message={message} />
50
- </div>
51
- ))}
52
-
53
- {/* {loading && [...Array(3)].map((_, idx) => <MessageSkeleton key={idx} />)} */}
54
- {messages?.length === 0 && (
55
- <p style={{textAlign:"center"}}>Send a message to start the conversation</p>
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: ['GET_ALL_CONVERSATION'] });
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, { createContext, useContext, ReactNode, useEffect, useState } from 'react';
2
- import { Socket, io } from 'socket.io-client';
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> = ({ userId, children }) => {
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
- const socketInstance = io(apiUrl, { auth: { userId } });
34
- setSocket(socketInstance);
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
- socketInstance.disconnect();
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('useChatContext must be used within a ChatProvider');
74
+ throw new Error("useChatContext must be used within a ChatProvider");
58
75
  }
59
76
  return context;
60
- };
77
+ };
@@ -299,11 +299,13 @@
299
299
  .chatMessageInputform {
300
300
  position: sticky;
301
301
  bottom: 0;
302
- background: #dbdbdbc0;
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