@pubuduth-aplicy/chat-ui 2.1.75 → 2.1.77
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/README.md +143 -40
- package/package.json +1 -1
- package/src/Chat.config.ts +1 -0
- package/src/components/Chat.tsx +0 -7
- package/src/components/messages/Message.tsx +0 -1
- package/src/components/messages/MessageContainer.tsx +14 -59
- package/src/components/messages/MessageInput.tsx +16 -14
- package/src/components/messages/Messages.tsx +8 -9
- package/src/components/sidebar/Conversation.tsx +8 -8
- package/src/components/sidebar/Conversations.tsx +9 -13
- package/src/declarations.d.ts +1 -0
- package/src/hooks/mutations/useDeleteMessage.ts +5 -5
- package/src/hooks/mutations/useEditMessage.ts +5 -5
- package/src/hooks/mutations/useSendMessage.ts +5 -5
- package/src/providers/ChatProvider.tsx +13 -13
- package/src/service/messageService.ts +2 -1
- package/src/service/sidebarApi.ts +2 -2
package/README.md
CHANGED
|
@@ -1,50 +1,153 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @pubuduth-aplicy/chat-ui
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
A flexible and easy-to-use React chat UI component.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
## Description
|
|
6
6
|
|
|
7
|
-
-
|
|
8
|
-
- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
|
|
7
|
+
`@pubuduth-aplicy/chat-ui` provides a complete chat interface that can be easily integrated into any React application. It includes features like real-time messaging, user presence, and a customizable interface. The component is built with TypeScript, React, and Zustand for state management.
|
|
9
8
|
|
|
10
|
-
##
|
|
9
|
+
## Installation
|
|
11
10
|
|
|
12
|
-
|
|
11
|
+
To install the package, use npm or yarn:
|
|
13
12
|
|
|
14
|
-
|
|
13
|
+
```bash
|
|
14
|
+
npm install @pubuduth-aplicy/chat-ui
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
or
|
|
15
18
|
|
|
16
|
-
```
|
|
17
|
-
|
|
18
|
-
languageOptions: {
|
|
19
|
-
// other options...
|
|
20
|
-
parserOptions: {
|
|
21
|
-
project: ['./tsconfig.node.json', './tsconfig.app.json'],
|
|
22
|
-
tsconfigRootDir: import.meta.dirname,
|
|
23
|
-
},
|
|
24
|
-
},
|
|
25
|
-
})
|
|
19
|
+
```bash
|
|
20
|
+
yarn add @pubuduth-aplicy/chat-ui
|
|
26
21
|
```
|
|
27
22
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
23
|
+
## Usage
|
|
24
|
+
|
|
25
|
+
To use the chat component, you need to initialize the configuration, wrap your application with the `ChatProvider`, and then render the `Chat` component.
|
|
26
|
+
|
|
27
|
+
### 1. Initialize the Configuration
|
|
28
|
+
|
|
29
|
+
First, you need to initialize the chat configuration at the entry point of your application (e.g., `index.tsx` or `main.tsx`).
|
|
30
|
+
|
|
31
|
+
```tsx
|
|
32
|
+
// src/main.tsx
|
|
33
|
+
import React from 'react';
|
|
34
|
+
import ReactDOM from 'react-dom/client';
|
|
35
|
+
import App from './App';
|
|
36
|
+
import { initChatConfig } from '@pubuduth-aplicy/chat-ui';
|
|
37
|
+
|
|
38
|
+
// Initialize the chat configuration
|
|
39
|
+
initChatConfig({
|
|
40
|
+
apiUrl: 'YOUR_API_URL', // Your backend API URL
|
|
41
|
+
role: 'user', // Optional: 'user' or 'admin'
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
ReactDOM.createRoot(document.getElementById('root')!).render(
|
|
45
|
+
<React.StrictMode>
|
|
46
|
+
<App />
|
|
47
|
+
</React.StrictMode>,
|
|
48
|
+
);
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### 2. Wrap with ChatProvider
|
|
52
|
+
|
|
53
|
+
Next, wrap your component tree with `ChatProvider`. This provider manages the chat state and WebSocket connection.
|
|
54
|
+
|
|
55
|
+
```tsx
|
|
56
|
+
// src/App.tsx
|
|
57
|
+
import { ChatProvider, Chat } from '@pubuduth-aplicy/chat-ui';
|
|
58
|
+
|
|
59
|
+
function App() {
|
|
60
|
+
const userId = 'CURRENT_USER_ID'; // The ID of the currently logged-in user
|
|
61
|
+
|
|
62
|
+
return (
|
|
63
|
+
<ChatProvider userId={userId}>
|
|
64
|
+
<div className="App">
|
|
65
|
+
{/* Your other components */}
|
|
66
|
+
<Chat />
|
|
67
|
+
</div>
|
|
68
|
+
</ChatProvider>
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export default App;
|
|
50
73
|
```
|
|
74
|
+
|
|
75
|
+
### 3. Render the Chat Component
|
|
76
|
+
|
|
77
|
+
Finally, render the `<Chat />` component wherever you want the chat interface to appear.
|
|
78
|
+
|
|
79
|
+
## Configuration
|
|
80
|
+
|
|
81
|
+
### `initChatConfig(config)`
|
|
82
|
+
|
|
83
|
+
This function initializes the chat component's configuration. It must be called once before any chat components are rendered.
|
|
84
|
+
|
|
85
|
+
**Parameters:**
|
|
86
|
+
|
|
87
|
+
* `config` (object):
|
|
88
|
+
* `apiUrl` (string, required): The base URL of your chat backend. The WebSocket connection will be derived from this URL.
|
|
89
|
+
* `role` (string, optional): The role of the user, e.g., 'user' or 'admin'.
|
|
90
|
+
|
|
91
|
+
## API Reference
|
|
92
|
+
|
|
93
|
+
### `<ChatProvider />`
|
|
94
|
+
|
|
95
|
+
This component provides the chat context to its children.
|
|
96
|
+
|
|
97
|
+
**Props:**
|
|
98
|
+
|
|
99
|
+
* `userId` (string, required): The unique identifier for the current user.
|
|
100
|
+
* `children` (ReactNode, required): The child components. The `<Chat />` component must be a descendant of `ChatProvider`.
|
|
101
|
+
|
|
102
|
+
### `<Chat />`
|
|
103
|
+
|
|
104
|
+
This component renders the main chat interface. It takes no props.
|
|
105
|
+
|
|
106
|
+
## Development
|
|
107
|
+
|
|
108
|
+
To set up the project for local development:
|
|
109
|
+
|
|
110
|
+
1. **Clone the repository:**
|
|
111
|
+
```bash
|
|
112
|
+
git clone https://github.com/pubuduth-aplicy/chat-ui.git
|
|
113
|
+
cd chat-ui
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
2. **Install dependencies:**
|
|
117
|
+
```bash
|
|
118
|
+
npm install
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
3. **Run the development server:**
|
|
122
|
+
This project uses Vite. To run the development server, you can add a `dev` script to your `package.json`:
|
|
123
|
+
```json
|
|
124
|
+
"scripts": {
|
|
125
|
+
"dev": "vite",
|
|
126
|
+
"build": "tsc",
|
|
127
|
+
"prepare": "npm run build"
|
|
128
|
+
}
|
|
129
|
+
```
|
|
130
|
+
Then run:
|
|
131
|
+
```bash
|
|
132
|
+
npm run dev
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
## Building
|
|
136
|
+
|
|
137
|
+
To build the component for production, run the following command. This will transpile the TypeScript code.
|
|
138
|
+
|
|
139
|
+
```bash
|
|
140
|
+
npm run build
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
For a full production build, you should use `vite build`. You can add this to your `package.json`:
|
|
144
|
+
|
|
145
|
+
```json
|
|
146
|
+
"scripts": {
|
|
147
|
+
"build:vite": "vite build"
|
|
148
|
+
}
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
## License
|
|
152
|
+
|
|
153
|
+
This project is licensed under the [ISC License](LICENSE).
|
package/package.json
CHANGED
package/src/Chat.config.ts
CHANGED
package/src/components/Chat.tsx
CHANGED
|
@@ -15,16 +15,9 @@ export const Chat = () => {
|
|
|
15
15
|
const handleMessage = (event: MessageEvent) => {
|
|
16
16
|
try {
|
|
17
17
|
const parsed = JSON.parse(event.data);
|
|
18
|
-
console.log("Parsed WebSocket message:", parsed);
|
|
19
18
|
|
|
20
19
|
if (parsed.event === "newMessage") {
|
|
21
20
|
const message = parsed.data;
|
|
22
|
-
console.log(
|
|
23
|
-
"📨 Message received at:",
|
|
24
|
-
message.createdAt,
|
|
25
|
-
"from:",
|
|
26
|
-
message
|
|
27
|
-
);
|
|
28
21
|
// Send delivery confirmation
|
|
29
22
|
// Update UI immediately
|
|
30
23
|
setMessages((prev) => [...prev, message]);
|
|
@@ -114,7 +114,6 @@ const Message = ({ message }: MessageProps) => {
|
|
|
114
114
|
// const handleDownload = (url: string, name: string) => {
|
|
115
115
|
// saveAs(url, name);
|
|
116
116
|
// };
|
|
117
|
-
console.log("check message status", message.status);
|
|
118
117
|
|
|
119
118
|
const [downloadingIndex, setDownloadingIndex] = useState<number | null>(null);
|
|
120
119
|
const [downloadProgress, setDownloadProgress] = useState<number>(0);
|
|
@@ -8,56 +8,11 @@ import { useChatContext } from "../../providers/ChatProvider";
|
|
|
8
8
|
import { getChatConfig } from "../../Chat.config";
|
|
9
9
|
|
|
10
10
|
const MessageContainer = () => {
|
|
11
|
+
const { userId } = useChatContext();
|
|
11
12
|
const { selectedConversation, setSelectedConversation, setOnlineUsers } =
|
|
12
13
|
useChatUIStore();
|
|
13
14
|
const { socket, isUserOnline } = useChatContext();
|
|
14
15
|
const { role } = getChatConfig();
|
|
15
|
-
// useEffect(() => {
|
|
16
|
-
// if (!socket) return;
|
|
17
|
-
|
|
18
|
-
// const handleMessage = (event) => {
|
|
19
|
-
// try {
|
|
20
|
-
// const parsed = JSON.parse(event.data);
|
|
21
|
-
|
|
22
|
-
// if (parsed.event === 'newMessage') {
|
|
23
|
-
// const message = parsed.data;
|
|
24
|
-
// console.log('Received message:', message);
|
|
25
|
-
|
|
26
|
-
// if (selectedConversation?._id !== message.chatId) return;
|
|
27
|
-
|
|
28
|
-
// const messageId = message._id || message.messageId;
|
|
29
|
-
// console.log('Message ID for unread:', messageId);
|
|
30
|
-
|
|
31
|
-
// if (!messageId) {
|
|
32
|
-
// console.warn('Message has no _id or messageId, skipping unread tracking');
|
|
33
|
-
// return;
|
|
34
|
-
// }
|
|
35
|
-
|
|
36
|
-
// const updatedUnread = [
|
|
37
|
-
// ...(selectedConversation?.unreadMessageIds || []),
|
|
38
|
-
// messageId,
|
|
39
|
-
// ];
|
|
40
|
-
|
|
41
|
-
// console.log('Updated unreadMessageIds:', updatedUnread);
|
|
42
|
-
|
|
43
|
-
// setSelectedConversation({
|
|
44
|
-
// ...selectedConversation,
|
|
45
|
-
// unreadMessageIds: updatedUnread,
|
|
46
|
-
// });
|
|
47
|
-
// }
|
|
48
|
-
|
|
49
|
-
// // Handle other events...
|
|
50
|
-
|
|
51
|
-
// } catch (error) {
|
|
52
|
-
// console.error("WebSocket message parse error:", error);
|
|
53
|
-
// }
|
|
54
|
-
// };
|
|
55
|
-
|
|
56
|
-
// socket.addEventListener("message", handleMessage);
|
|
57
|
-
// return () => socket.removeEventListener("message", handleMessage);
|
|
58
|
-
// }, [socket, setMessages, selectedConversation, setSelectedConversation]);
|
|
59
|
-
|
|
60
|
-
// Join chat room when conversation is selected
|
|
61
16
|
|
|
62
17
|
useEffect(() => {
|
|
63
18
|
if (selectedConversation?._id && socket?.readyState === WebSocket.OPEN) {
|
|
@@ -67,6 +22,7 @@ const MessageContainer = () => {
|
|
|
67
22
|
event: "joinChat",
|
|
68
23
|
data: {
|
|
69
24
|
chatId: selectedConversation._id,
|
|
25
|
+
userId: userId
|
|
70
26
|
},
|
|
71
27
|
})
|
|
72
28
|
);
|
|
@@ -79,7 +35,6 @@ const MessageContainer = () => {
|
|
|
79
35
|
const handleMessage = (event: MessageEvent) => {
|
|
80
36
|
try {
|
|
81
37
|
const data = JSON.parse(event.data);
|
|
82
|
-
console.log("Parsed WebSocket message in mc:", data);
|
|
83
38
|
|
|
84
39
|
if (data.event === "getOnlineUsers") {
|
|
85
40
|
setOnlineUsers(data.payload); // payload should be an array of user IDs
|
|
@@ -98,19 +53,19 @@ const MessageContainer = () => {
|
|
|
98
53
|
|
|
99
54
|
// Listen for online users updates
|
|
100
55
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
// const participantDetails = Array.isArray(selectedConversation?.participantDetails)
|
|
104
|
-
// ? selectedConversation?.participantDetails
|
|
105
|
-
// : [selectedConversation?.participantDetails].filter(Boolean);
|
|
56
|
+
|
|
106
57
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
58
|
+
const participantDetails = Array.isArray(selectedConversation?.participantDetails)
|
|
59
|
+
? selectedConversation?.participantDetails
|
|
60
|
+
: [selectedConversation?.participantDetails].filter(Boolean);
|
|
110
61
|
|
|
111
|
-
const participant =
|
|
62
|
+
const participant = participantDetails.find(
|
|
112
63
|
(p: any) => p._id !== userId
|
|
113
64
|
);
|
|
65
|
+
|
|
66
|
+
// const participant = selectedConversation?.participantDetails?.find(
|
|
67
|
+
// (p: any) => p._id !== userId
|
|
68
|
+
// );
|
|
114
69
|
|
|
115
70
|
const isOnline = isUserOnline(participant?._id || "");
|
|
116
71
|
|
|
@@ -120,13 +75,13 @@ const MessageContainer = () => {
|
|
|
120
75
|
}, [setSelectedConversation]);
|
|
121
76
|
|
|
122
77
|
return (
|
|
123
|
-
<div className="chatMessageContainer
|
|
78
|
+
<div className="chatMessageContainer">
|
|
124
79
|
{!selectedConversation ? (
|
|
125
80
|
<EmptyInbox />
|
|
126
81
|
) : (
|
|
127
82
|
<>
|
|
128
|
-
<div className="chatMessageContainerInner
|
|
129
|
-
<div className="chatMessageContainerInnerDiv
|
|
83
|
+
<div className="chatMessageContainerInner">
|
|
84
|
+
<div className="chatMessageContainerInnerDiv">
|
|
130
85
|
<button className="chatMessageContainerInnerDiv_button">
|
|
131
86
|
{/* <CaretLeft size={25} /> */}
|
|
132
87
|
</button>
|
|
@@ -57,6 +57,15 @@ const MessageInput = () => {
|
|
|
57
57
|
const generateTempId = () =>
|
|
58
58
|
`temp-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
59
59
|
// Join chat room when conversation is selected
|
|
60
|
+
|
|
61
|
+
const participantDetails = Array.isArray(selectedConversation?.participantDetails)
|
|
62
|
+
? selectedConversation?.participantDetails
|
|
63
|
+
: [selectedConversation?.participantDetails].filter(Boolean);
|
|
64
|
+
|
|
65
|
+
const otherParticipant = participantDetails.find(
|
|
66
|
+
(p: any) => p._id !== userId
|
|
67
|
+
);
|
|
68
|
+
|
|
60
69
|
useEffect(() => {
|
|
61
70
|
if (selectedConversation?._id && socket?.readyState === WebSocket.OPEN) {
|
|
62
71
|
sendMessage({
|
|
@@ -67,7 +76,6 @@ const MessageInput = () => {
|
|
|
67
76
|
});
|
|
68
77
|
}
|
|
69
78
|
}, [selectedConversation?._id, socket, sendMessage]);
|
|
70
|
-
console.log('selected', selectedConversation);
|
|
71
79
|
|
|
72
80
|
useEffect(() => {
|
|
73
81
|
// Clear all input state when conversation changes
|
|
@@ -94,6 +102,7 @@ const MessageInput = () => {
|
|
|
94
102
|
data: {
|
|
95
103
|
chatId: selectedConversation._id,
|
|
96
104
|
userId,
|
|
105
|
+
reciverId: otherParticipant?._id,
|
|
97
106
|
},
|
|
98
107
|
});
|
|
99
108
|
}
|
|
@@ -106,6 +115,7 @@ const MessageInput = () => {
|
|
|
106
115
|
data: {
|
|
107
116
|
chatId: selectedConversation._id,
|
|
108
117
|
userId,
|
|
118
|
+
reciverId: otherParticipant?._id,
|
|
109
119
|
},
|
|
110
120
|
});
|
|
111
121
|
}
|
|
@@ -125,12 +135,10 @@ const MessageInput = () => {
|
|
|
125
135
|
const handleMessage = (event: MessageEvent) => {
|
|
126
136
|
try {
|
|
127
137
|
const data = JSON.parse(event.data);
|
|
128
|
-
console.log("Received WebSocket message:", data);
|
|
129
138
|
if (
|
|
130
139
|
data.event === "typing" &&
|
|
131
140
|
data.data.chatId === selectedConversation._id
|
|
132
141
|
) {
|
|
133
|
-
console.log("Setting typing user:", data.data.userId);
|
|
134
142
|
setTypingUser(data.data.userId);
|
|
135
143
|
} else if (
|
|
136
144
|
data.event === "stopTyping" &&
|
|
@@ -227,13 +235,7 @@ const MessageInput = () => {
|
|
|
227
235
|
});
|
|
228
236
|
};
|
|
229
237
|
|
|
230
|
-
|
|
231
|
-
? selectedConversation?.participantDetails
|
|
232
|
-
: [selectedConversation?.participantDetails].filter(Boolean);
|
|
233
|
-
|
|
234
|
-
const otherParticipant = participantDetails.find(
|
|
235
|
-
(p: any) => p._id !== userId
|
|
236
|
-
);
|
|
238
|
+
|
|
237
239
|
|
|
238
240
|
// const otherParticipant = selectedConversation?.participantDetails?.find(
|
|
239
241
|
// (p:any) => p._id !== userId
|
|
@@ -533,7 +535,7 @@ const MessageInput = () => {
|
|
|
533
535
|
};
|
|
534
536
|
|
|
535
537
|
return (
|
|
536
|
-
<div className="message-input-container
|
|
538
|
+
<div className="message-input-container">
|
|
537
539
|
{attachments.length > 0 && (
|
|
538
540
|
<div className="attachments-preview-container">
|
|
539
541
|
<button
|
|
@@ -576,12 +578,12 @@ const MessageInput = () => {
|
|
|
576
578
|
</div>
|
|
577
579
|
)}
|
|
578
580
|
|
|
579
|
-
<form className="chatMessageInputform
|
|
581
|
+
<form className="chatMessageInputform" onSubmit={handleSubmit}>
|
|
580
582
|
{inputError && (
|
|
581
583
|
<p style={{ color: "red", fontSize: "12px" }}>{inputError}</p>
|
|
582
584
|
)}
|
|
583
585
|
|
|
584
|
-
<div className="chatMessageInputdiv
|
|
586
|
+
<div className="chatMessageInputdiv">
|
|
585
587
|
<input
|
|
586
588
|
type="file"
|
|
587
589
|
ref={fileInputRef}
|
|
@@ -681,7 +683,7 @@ const MessageInput = () => {
|
|
|
681
683
|
</div>
|
|
682
684
|
|
|
683
685
|
<textarea
|
|
684
|
-
className="chatMessageInput
|
|
686
|
+
className="chatMessageInput"
|
|
685
687
|
placeholder="Send a message"
|
|
686
688
|
value={message}
|
|
687
689
|
onChange={handleChange}
|
|
@@ -44,14 +44,13 @@ const Messages = () => {
|
|
|
44
44
|
const handleMessage = (event: MessageEvent) => {
|
|
45
45
|
try {
|
|
46
46
|
const parsed = JSON.parse(event.data);
|
|
47
|
-
console.log("Parsed WebSocket message1:", parsed);
|
|
48
47
|
if (parsed.type === "newMessage" || parsed.event === "newMessage") {
|
|
49
48
|
const newMessage = parsed.data;
|
|
50
49
|
if (!newMessage) {
|
|
51
|
-
console.warn(
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
);
|
|
50
|
+
// console.warn(
|
|
51
|
+
// "Received newMessage event without a message payload",
|
|
52
|
+
// parsed
|
|
53
|
+
// );
|
|
55
54
|
return;
|
|
56
55
|
}
|
|
57
56
|
|
|
@@ -74,7 +73,7 @@ const Messages = () => {
|
|
|
74
73
|
if (parsed.event === "messageStatusUpdated") {
|
|
75
74
|
const { messageId, status } = parsed.data || {};
|
|
76
75
|
if (!messageId) {
|
|
77
|
-
console.error("Missing messageId in status update", parsed);
|
|
76
|
+
// console.error("Missing messageId in status update", parsed);
|
|
78
77
|
return;
|
|
79
78
|
}
|
|
80
79
|
|
|
@@ -88,7 +87,7 @@ const Messages = () => {
|
|
|
88
87
|
return msg;
|
|
89
88
|
|
|
90
89
|
if (newIdx > currentIdx) {
|
|
91
|
-
console.log(`Updating status for ${messageId} to ${status}`);
|
|
90
|
+
// console.log(`Updating status for ${messageId} to ${status}`);
|
|
92
91
|
return { ...msg, status };
|
|
93
92
|
}
|
|
94
93
|
|
|
@@ -98,7 +97,7 @@ const Messages = () => {
|
|
|
98
97
|
}
|
|
99
98
|
|
|
100
99
|
if (parsed.event === "messageEdited") {
|
|
101
|
-
console.log("Received messageEdited event:", parsed);
|
|
100
|
+
// console.log("Received messageEdited event:", parsed);
|
|
102
101
|
|
|
103
102
|
const updatedMessage = parsed.data;
|
|
104
103
|
if (!updatedMessage || !updatedMessage.messageId) return;
|
|
@@ -113,7 +112,7 @@ const Messages = () => {
|
|
|
113
112
|
}
|
|
114
113
|
|
|
115
114
|
if (parsed.event === "messageDeleted") {
|
|
116
|
-
console.log("Received messageDeleted event:", parsed);
|
|
115
|
+
// console.log("Received messageDeleted event:", parsed);
|
|
117
116
|
|
|
118
117
|
const { messageId } = parsed.data || {};
|
|
119
118
|
if (!messageId) return;
|
|
@@ -21,14 +21,14 @@ const Conversation = ({ conversation }: ConversationProps) => {
|
|
|
21
21
|
);
|
|
22
22
|
|
|
23
23
|
const handleSelectConversation = () => {
|
|
24
|
-
console.log(
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
);
|
|
24
|
+
// console.log(
|
|
25
|
+
// "Selected Conversation Data:",
|
|
26
|
+
// JSON.stringify(conversation, null, 2)
|
|
27
|
+
// );
|
|
28
28
|
setSelectedConversation(conversation);
|
|
29
29
|
const unreadMessageIds = conversation.unreadMessageIds || [];
|
|
30
30
|
if (unreadMessageIds.length > 0 && socket?.readyState === WebSocket.OPEN) {
|
|
31
|
-
console.log("unread messages", unreadMessageIds);
|
|
31
|
+
// console.log("unread messages", unreadMessageIds);
|
|
32
32
|
|
|
33
33
|
const message = {
|
|
34
34
|
event: "messageRead",
|
|
@@ -64,9 +64,9 @@ const Conversation = ({ conversation }: ConversationProps) => {
|
|
|
64
64
|
};
|
|
65
65
|
}, [socket, setOnlineUsers]);
|
|
66
66
|
|
|
67
|
-
useEffect(() => {
|
|
68
|
-
|
|
69
|
-
}, [conversation]);
|
|
67
|
+
// useEffect(() => {
|
|
68
|
+
// // console.log("Current conversation state:", conversation);
|
|
69
|
+
// }, [conversation]);
|
|
70
70
|
|
|
71
71
|
const isOnline = isUserOnline(participant?._id || "");
|
|
72
72
|
const isSelected = selectedConversation?._id === conversation._id;
|
|
@@ -35,6 +35,8 @@ const Conversations = () => {
|
|
|
35
35
|
const allServiceChatsMap = new Map<string, GroupedServiceChats[string]>();
|
|
36
36
|
|
|
37
37
|
groups.forEach((group) => {
|
|
38
|
+
// console.log("group", group.personalConversation);
|
|
39
|
+
|
|
38
40
|
if (group.personalConversation) {
|
|
39
41
|
allGeneralChats.push(group.personalConversation);
|
|
40
42
|
}
|
|
@@ -225,7 +227,7 @@ const Conversations = () => {
|
|
|
225
227
|
convo.participantDetails?.some((p:any) =>
|
|
226
228
|
typeof p === "string"
|
|
227
229
|
? p.toLowerCase().includes(lowerSearch)
|
|
228
|
-
: p.
|
|
230
|
+
: p.name?.toLowerCase().includes(lowerSearch)
|
|
229
231
|
)
|
|
230
232
|
);
|
|
231
233
|
|
|
@@ -244,8 +246,11 @@ const Conversations = () => {
|
|
|
244
246
|
.filter(([_, group]) => group.conversations.length > 0) // Remove empty groups
|
|
245
247
|
);
|
|
246
248
|
|
|
249
|
+
// console.log("filteredGeneralChats",filteredGeneralChats);
|
|
250
|
+
// console.log("filteredGroupedServiceChats");
|
|
251
|
+
|
|
247
252
|
return (
|
|
248
|
-
<div className="chatSidebarConversations"
|
|
253
|
+
<div className="chatSidebarConversations">
|
|
249
254
|
{isEmpty ? (
|
|
250
255
|
<div className="flex flex-col items-center justify-center p-8 text-center">
|
|
251
256
|
<h3 className="text-xl font-semibold mb-1">No Conversations</h3>
|
|
@@ -255,14 +260,7 @@ const Conversations = () => {
|
|
|
255
260
|
</div>
|
|
256
261
|
) : (
|
|
257
262
|
<>
|
|
258
|
-
|
|
259
|
-
className="overflow-y-auto"
|
|
260
|
-
style={{
|
|
261
|
-
maxHeight: 'calc(5 * 5rem)', // Adjust 3.5rem to match your chat item height
|
|
262
|
-
scrollbarWidth: 'thin'
|
|
263
|
-
}}
|
|
264
|
-
>
|
|
265
|
-
{filteredGeneralChats.length > 0 && (
|
|
263
|
+
{filteredGeneralChats.length > 0 && (
|
|
266
264
|
<CollapsibleSection title="General Chats">
|
|
267
265
|
<VirtualizedChatList conversations={filteredGeneralChats} />
|
|
268
266
|
</CollapsibleSection>
|
|
@@ -285,9 +283,7 @@ const Conversations = () => {
|
|
|
285
283
|
)
|
|
286
284
|
)}
|
|
287
285
|
</CollapsibleSection>
|
|
288
|
-
)}
|
|
289
|
-
</div>
|
|
290
|
-
|
|
286
|
+
)}
|
|
291
287
|
</>
|
|
292
288
|
)}
|
|
293
289
|
</div>
|
package/src/declarations.d.ts
CHANGED
|
@@ -8,7 +8,7 @@ export const useDeleteMessageMutation = () => {
|
|
|
8
8
|
return useMutation({
|
|
9
9
|
mutationFn: deleteMessage,
|
|
10
10
|
onSuccess: () => {
|
|
11
|
-
console.log("Message deleted successfully!", "success");
|
|
11
|
+
// console.log("Message deleted successfully!", "success");
|
|
12
12
|
// Invalidate both messages and conversations queries
|
|
13
13
|
queryClient.invalidateQueries({ queryKey: ['messages'] });
|
|
14
14
|
queryClient.invalidateQueries({ queryKey: ['conversations'] });
|
|
@@ -16,11 +16,11 @@ export const useDeleteMessageMutation = () => {
|
|
|
16
16
|
onError: (error: any) => {
|
|
17
17
|
console.error("Failed to delete message:", error);
|
|
18
18
|
|
|
19
|
-
const errorMessage =
|
|
20
|
-
|
|
21
|
-
|
|
19
|
+
// const errorMessage =
|
|
20
|
+
// error?.response?.data?.errors[0]?.msg ||
|
|
21
|
+
// "An error occurred while deleting the message.";
|
|
22
22
|
|
|
23
|
-
console.log("useDeleteMessageMutation error:", errorMessage);
|
|
23
|
+
// console.log("useDeleteMessageMutation error:", errorMessage);
|
|
24
24
|
},
|
|
25
25
|
});
|
|
26
26
|
};
|
|
@@ -8,15 +8,15 @@ export const useEditMessageMutation = () => {
|
|
|
8
8
|
return useMutation({
|
|
9
9
|
mutationFn: setEditMessage,
|
|
10
10
|
onSuccess: () => {
|
|
11
|
-
console.log("Message edited successfully!", "success");
|
|
11
|
+
// console.log("Message edited successfully!", "success");
|
|
12
12
|
queryClient.invalidateQueries({ queryKey: ['messages'] });
|
|
13
13
|
},
|
|
14
14
|
onError: (error: any) => {
|
|
15
15
|
console.error("Failed to edit message:", error);
|
|
16
|
-
const errorMessage =
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
console.log("useMessageMutation edit error:", errorMessage);
|
|
16
|
+
// const errorMessage =
|
|
17
|
+
// error?.response?.data?.errors[0]?.msg ||
|
|
18
|
+
// "An error occurred while editing the message.";
|
|
19
|
+
// console.log("useMessageMutation edit error:", errorMessage);
|
|
20
20
|
},
|
|
21
21
|
});
|
|
22
22
|
|
|
@@ -7,17 +7,17 @@ export const useMessageMutation = () => {
|
|
|
7
7
|
return useMutation({
|
|
8
8
|
mutationFn: sendMessage,
|
|
9
9
|
onSuccess: () => {
|
|
10
|
-
console.log("Service submitted successfully!", "success");
|
|
10
|
+
// console.log("Service submitted successfully!", "success");
|
|
11
11
|
queryClient.invalidateQueries({ queryKey: ['messages'] });
|
|
12
12
|
},
|
|
13
13
|
onError: (error: any) => {
|
|
14
14
|
console.error("Failed to submit service data:", error);
|
|
15
15
|
|
|
16
|
-
const errorMessage =
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
// const errorMessage =
|
|
17
|
+
// error?.response?.data?.errors[0]?.msg ||
|
|
18
|
+
// "An error occurred while submitting service data.";
|
|
19
19
|
|
|
20
|
-
console.log("useSumbitServiceMutation :", errorMessage);
|
|
20
|
+
// console.log("useSumbitServiceMutation :", errorMessage);
|
|
21
21
|
},
|
|
22
22
|
});
|
|
23
23
|
};
|
|
@@ -41,19 +41,19 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({
|
|
|
41
41
|
const reconnectAttempts = useRef(0);
|
|
42
42
|
const maxReconnectAttempts = 5;
|
|
43
43
|
const reconnectInterval = 5000; // 5 seconds
|
|
44
|
-
const {
|
|
44
|
+
const { webSocketUrl } = getChatConfig();
|
|
45
45
|
|
|
46
46
|
const connectWebSocket = useCallback(() => {
|
|
47
|
-
console.log("🔌 Creating new WebSocket connection...");
|
|
47
|
+
// console.log("🔌 Creating new WebSocket connection...");
|
|
48
48
|
|
|
49
49
|
// Convert HTTP URL to WebSocket URL
|
|
50
|
-
const wsUrl =
|
|
50
|
+
const wsUrl = webSocketUrl.replace(/^http:/, "ws:").replace(/^https:/, "wss:");
|
|
51
51
|
const socketInstance = new WebSocket(
|
|
52
52
|
`${wsUrl}?userId=${encodeURIComponent(userId)}`
|
|
53
53
|
);
|
|
54
54
|
|
|
55
55
|
socketInstance.onopen = () => {
|
|
56
|
-
console.log("✅ WebSocket connected");
|
|
56
|
+
// console.log("✅ WebSocket connected");
|
|
57
57
|
setIsConnected(true);
|
|
58
58
|
reconnectAttempts.current = 0;
|
|
59
59
|
|
|
@@ -71,12 +71,12 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({
|
|
|
71
71
|
const data = JSON.parse(event.data);
|
|
72
72
|
|
|
73
73
|
if (data.event === "getOnlineUsers") {
|
|
74
|
-
console.log("Online users update:", data.data);
|
|
74
|
+
// console.log("Online users update:", data.data);
|
|
75
75
|
setOnlineUsers(new Set(data.data));
|
|
76
76
|
}
|
|
77
77
|
|
|
78
78
|
// Handle other message types here
|
|
79
|
-
console.log("Received message:", data);
|
|
79
|
+
// console.log("Received message:", data);
|
|
80
80
|
} catch (error) {
|
|
81
81
|
console.error("Error parsing message:", error);
|
|
82
82
|
}
|
|
@@ -87,23 +87,23 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({
|
|
|
87
87
|
};
|
|
88
88
|
|
|
89
89
|
socketInstance.onclose = (event) => {
|
|
90
|
-
console.log("🔌 WebSocket connection closed", event);
|
|
91
|
-
console.log("❌ WebSocket disconnected:", event.code, event.reason);
|
|
90
|
+
// console.log("🔌 WebSocket connection closed", event);
|
|
91
|
+
// console.log("❌ WebSocket disconnected:", event.code, event.reason);
|
|
92
92
|
setIsConnected(false);
|
|
93
93
|
|
|
94
94
|
// Attempt reconnection
|
|
95
95
|
if (reconnectAttempts.current < maxReconnectAttempts) {
|
|
96
96
|
reconnectAttempts.current += 1;
|
|
97
|
-
console.log(
|
|
98
|
-
|
|
99
|
-
);
|
|
97
|
+
// console.log(
|
|
98
|
+
// `Attempting to reconnect (${reconnectAttempts.current}/${maxReconnectAttempts})...`
|
|
99
|
+
// );
|
|
100
100
|
setTimeout(connectWebSocket, reconnectInterval);
|
|
101
101
|
}
|
|
102
102
|
};
|
|
103
103
|
|
|
104
104
|
socketRef.current = socketInstance;
|
|
105
105
|
setSocket(socketInstance);
|
|
106
|
-
}, [
|
|
106
|
+
}, [webSocketUrl, userId]);
|
|
107
107
|
|
|
108
108
|
const sendMessage = useCallback((data: any) => {
|
|
109
109
|
if (socketRef.current?.readyState === WebSocket.OPEN) {
|
|
@@ -117,7 +117,7 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({
|
|
|
117
117
|
connectWebSocket();
|
|
118
118
|
|
|
119
119
|
return () => {
|
|
120
|
-
console.log("❌ Closing WebSocket connection...");
|
|
120
|
+
// console.log("❌ Closing WebSocket connection...");
|
|
121
121
|
if (socketRef.current) {
|
|
122
122
|
socketRef.current.close(1000, "Component unmounted");
|
|
123
123
|
socketRef.current = null;
|
|
@@ -34,6 +34,7 @@ export const sendMessage = async (params: {
|
|
|
34
34
|
serviceTitle,
|
|
35
35
|
type,
|
|
36
36
|
serviceId,
|
|
37
|
+
messageType: "user"
|
|
37
38
|
}
|
|
38
39
|
);
|
|
39
40
|
return response.data;
|
|
@@ -46,7 +47,7 @@ export const fetchMessages = async (chatId: string | undefined, userid: string,
|
|
|
46
47
|
const response = await apiClient.get(`${Path.getmessage}/${chatId}/${userid}`, {
|
|
47
48
|
params: { pagenum, limit: 20 },
|
|
48
49
|
});
|
|
49
|
-
console.log(response);
|
|
50
|
+
// console.log(response);
|
|
50
51
|
return response.data;
|
|
51
52
|
} catch (error) {
|
|
52
53
|
console.error("Error fetching messages:", error);
|
|
@@ -16,11 +16,11 @@ export const getAllConversationData = async (userid: string) => {
|
|
|
16
16
|
|
|
17
17
|
const res = await apiClient.get<ApiResponse>(endpoint);
|
|
18
18
|
if (res.data) {
|
|
19
|
-
console.log("API Response: ", res.data);
|
|
19
|
+
// console.log("API Response: ", res.data);
|
|
20
20
|
|
|
21
21
|
}
|
|
22
22
|
const conversationsWithParticipantDetails = res.data.serviceInfo;
|
|
23
|
-
console.log("conversationsWithParticipantDetails", res.data.serviceInfo);
|
|
23
|
+
// console.log("conversationsWithParticipantDetails", res.data.serviceInfo);
|
|
24
24
|
|
|
25
25
|
// If needed, you can map the conversations in the specific structure
|
|
26
26
|
// const formattedConversations = conversationsWithParticipantDetails?.map((conversation) => ({
|