@pubuduth-aplicy/chat-ui 2.1.75 → 2.1.76
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
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
|
@@ -8,6 +8,7 @@ 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();
|
|
@@ -67,6 +68,7 @@ const MessageContainer = () => {
|
|
|
67
68
|
event: "joinChat",
|
|
68
69
|
data: {
|
|
69
70
|
chatId: selectedConversation._id,
|
|
71
|
+
userId: userId
|
|
70
72
|
},
|
|
71
73
|
})
|
|
72
74
|
);
|
|
@@ -98,19 +100,19 @@ const MessageContainer = () => {
|
|
|
98
100
|
|
|
99
101
|
// Listen for online users updates
|
|
100
102
|
|
|
101
|
-
|
|
103
|
+
|
|
102
104
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
105
|
+
const participantDetails = Array.isArray(selectedConversation?.participantDetails)
|
|
106
|
+
? selectedConversation?.participantDetails
|
|
107
|
+
: [selectedConversation?.participantDetails].filter(Boolean);
|
|
106
108
|
|
|
107
|
-
|
|
108
|
-
// (p: any) => p._id !== userId
|
|
109
|
-
// );
|
|
110
|
-
|
|
111
|
-
const participant = selectedConversation?.participantDetails?.find(
|
|
109
|
+
const participant = participantDetails.find(
|
|
112
110
|
(p: any) => p._id !== userId
|
|
113
111
|
);
|
|
112
|
+
|
|
113
|
+
// const participant = selectedConversation?.participantDetails?.find(
|
|
114
|
+
// (p: any) => p._id !== userId
|
|
115
|
+
// );
|
|
114
116
|
|
|
115
117
|
const isOnline = isUserOnline(participant?._id || "");
|
|
116
118
|
|
|
@@ -120,13 +122,13 @@ const MessageContainer = () => {
|
|
|
120
122
|
}, [setSelectedConversation]);
|
|
121
123
|
|
|
122
124
|
return (
|
|
123
|
-
<div className="chatMessageContainer
|
|
125
|
+
<div className="chatMessageContainer">
|
|
124
126
|
{!selectedConversation ? (
|
|
125
127
|
<EmptyInbox />
|
|
126
128
|
) : (
|
|
127
129
|
<>
|
|
128
|
-
<div className="chatMessageContainerInner
|
|
129
|
-
<div className="chatMessageContainerInnerDiv
|
|
130
|
+
<div className="chatMessageContainerInner">
|
|
131
|
+
<div className="chatMessageContainerInnerDiv">
|
|
130
132
|
<button className="chatMessageContainerInnerDiv_button">
|
|
131
133
|
{/* <CaretLeft size={25} /> */}
|
|
132
134
|
</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({
|
|
@@ -94,6 +103,7 @@ const MessageInput = () => {
|
|
|
94
103
|
data: {
|
|
95
104
|
chatId: selectedConversation._id,
|
|
96
105
|
userId,
|
|
106
|
+
reciverId: otherParticipant?._id,
|
|
97
107
|
},
|
|
98
108
|
});
|
|
99
109
|
}
|
|
@@ -106,6 +116,7 @@ const MessageInput = () => {
|
|
|
106
116
|
data: {
|
|
107
117
|
chatId: selectedConversation._id,
|
|
108
118
|
userId,
|
|
119
|
+
reciverId: otherParticipant?._id,
|
|
109
120
|
},
|
|
110
121
|
});
|
|
111
122
|
}
|
|
@@ -227,13 +238,7 @@ const MessageInput = () => {
|
|
|
227
238
|
});
|
|
228
239
|
};
|
|
229
240
|
|
|
230
|
-
|
|
231
|
-
? selectedConversation?.participantDetails
|
|
232
|
-
: [selectedConversation?.participantDetails].filter(Boolean);
|
|
233
|
-
|
|
234
|
-
const otherParticipant = participantDetails.find(
|
|
235
|
-
(p: any) => p._id !== userId
|
|
236
|
-
);
|
|
241
|
+
|
|
237
242
|
|
|
238
243
|
// const otherParticipant = selectedConversation?.participantDetails?.find(
|
|
239
244
|
// (p:any) => p._id !== userId
|
|
@@ -533,7 +538,7 @@ const MessageInput = () => {
|
|
|
533
538
|
};
|
|
534
539
|
|
|
535
540
|
return (
|
|
536
|
-
<div className="message-input-container
|
|
541
|
+
<div className="message-input-container">
|
|
537
542
|
{attachments.length > 0 && (
|
|
538
543
|
<div className="attachments-preview-container">
|
|
539
544
|
<button
|
|
@@ -576,12 +581,12 @@ const MessageInput = () => {
|
|
|
576
581
|
</div>
|
|
577
582
|
)}
|
|
578
583
|
|
|
579
|
-
<form className="chatMessageInputform
|
|
584
|
+
<form className="chatMessageInputform" onSubmit={handleSubmit}>
|
|
580
585
|
{inputError && (
|
|
581
586
|
<p style={{ color: "red", fontSize: "12px" }}>{inputError}</p>
|
|
582
587
|
)}
|
|
583
588
|
|
|
584
|
-
<div className="chatMessageInputdiv
|
|
589
|
+
<div className="chatMessageInputdiv">
|
|
585
590
|
<input
|
|
586
591
|
type="file"
|
|
587
592
|
ref={fileInputRef}
|
|
@@ -681,7 +686,7 @@ const MessageInput = () => {
|
|
|
681
686
|
</div>
|
|
682
687
|
|
|
683
688
|
<textarea
|
|
684
|
-
className="chatMessageInput
|
|
689
|
+
className="chatMessageInput"
|
|
685
690
|
placeholder="Send a message"
|
|
686
691
|
value={message}
|
|
687
692
|
onChange={handleChange}
|
|
@@ -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>
|