@pubuduth-aplicy/chat-ui 2.1.73 → 2.1.75

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.73",
3
+ "version": "2.1.75",
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": "",
@@ -13,6 +13,7 @@
13
13
  },
14
14
  "dependencies": {
15
15
  "@tanstack/react-query": "^5.67.2",
16
+ "@tanstack/react-virtual": "^3.13.12",
16
17
  "axios": "^1.8.2",
17
18
  "lucide-react": "^0.514.0",
18
19
  "react": "^19.0.0",
@@ -2,6 +2,7 @@
2
2
  export interface ChatConfig {
3
3
  apiUrl: string;
4
4
  role?: string;
5
+ cdnUrl?: string;
5
6
  }
6
7
 
7
8
  let chatConfig: ChatConfig;
@@ -51,7 +51,7 @@ export const Chat = () => {
51
51
  return (
52
52
  <div className="container mx-auto mb-5">
53
53
  <div className="grid-container">
54
- <div className={`sidebarContainer`}>
54
+ <div className={`sidebarContainer dark:bg-gray-800`}>
55
55
  <Sidebar />
56
56
  </div>
57
57
  <div className="messageContainer">
@@ -0,0 +1,40 @@
1
+ import { useState } from "react";
2
+ import { ChevronDown } from "lucide-react";
3
+
4
+ interface CollapsibleSectionProps {
5
+ title: string;
6
+ children: React.ReactNode;
7
+ defaultOpen?: boolean;
8
+ }
9
+
10
+ const CollapsibleSection = ({
11
+ title,
12
+ children,
13
+ defaultOpen = true,
14
+ }: CollapsibleSectionProps) => {
15
+ const [isOpen, setIsOpen] = useState(defaultOpen);
16
+
17
+ const toggleOpen = () => {
18
+ setIsOpen(!isOpen);
19
+ };
20
+
21
+ return (
22
+ <div className="border-b border-gray-200">
23
+ <div
24
+ className="flex justify-between items-center p-2 cursor-pointer hover:bg-gray-50"
25
+ onClick={toggleOpen}
26
+ >
27
+ <p className="text-xs uppercase text-gray-900 dark:text-gray-200">{title}</p>
28
+ <ChevronDown
29
+ size={20}
30
+ className={`transform transition-transform duration-200 ${
31
+ isOpen ? "rotate-180" : ""
32
+ }`}
33
+ />
34
+ </div>
35
+ {isOpen && <div className="p-2 text-gray-900 dark:text-gray-200">{children}</div>}
36
+ </div>
37
+ );
38
+ };
39
+
40
+ export default CollapsibleSection;
@@ -0,0 +1,57 @@
1
+ import { useRef } from "react";
2
+ import { useVirtualizer } from "@tanstack/react-virtual";
3
+ import Conversation from "../sidebar/Conversation";
4
+ import { Conversation as ConversationType } from "../../types/type";
5
+
6
+ interface Props {
7
+ conversations: ConversationType[];
8
+ }
9
+
10
+ const ITEM_HEIGHT = 60;
11
+
12
+ const VirtualizedChatList = ({ conversations }: Props) => {
13
+ const parentRef = useRef<HTMLDivElement>(null);
14
+
15
+ const virtualizer = useVirtualizer({
16
+ count: conversations.length,
17
+ getScrollElement: () => parentRef.current,
18
+ estimateSize: () => ITEM_HEIGHT,
19
+ overscan: 5,
20
+ });
21
+
22
+ return (
23
+ <div
24
+ ref={parentRef}
25
+ style={{
26
+ height: `${virtualizer.getTotalSize()}px`,
27
+ width: "100%",
28
+ position: "relative",
29
+ overflow: "auto",
30
+ }}
31
+ >
32
+ {virtualizer.getVirtualItems().map((item) => {
33
+ const conversation = conversations[item.index];
34
+ return (
35
+ <div
36
+ key={item.key}
37
+ style={{
38
+ position: "absolute",
39
+ top: 0,
40
+ left: 0,
41
+ width: "100%",
42
+ height: `${item.size}px`,
43
+ transform: `translateY(${item.start}px)`,
44
+ }}
45
+ >
46
+ <Conversation
47
+ conversation={conversation}
48
+ lastIdx={item.index === conversations.length - 1}
49
+ />
50
+ </div>
51
+ );
52
+ })}
53
+ </div>
54
+ );
55
+ };
56
+
57
+ export default VirtualizedChatList;
@@ -34,6 +34,7 @@ interface MessageProps {
34
34
  type?: "user" | "system" | "system-completion";
35
35
  meta?: {
36
36
  bookingDetails?: {
37
+ status: string; // e.g., "confirmed", "pending", "cancelled"
37
38
  serviceId: string;
38
39
  date: string;
39
40
  time: string;
@@ -47,18 +48,30 @@ interface MessageProps {
47
48
 
48
49
  const Message = ({ message }: MessageProps) => {
49
50
  const { userId } = useChatContext();
50
- const { apiUrl } = getChatConfig();
51
+ const { apiUrl,cdnUrl } = getChatConfig();
51
52
 
52
53
  if (message.type === "system") {
53
54
  return (
54
55
  <div className="system-message booking-details">
55
- <h4>Booking Confirmed</h4>
56
+ <h4>{message.meta?.bookingDetails?.status || 'Unknown'}</h4>
56
57
  <div className="details">
57
58
  <p>Service: {message.meta?.bookingDetails?.serviceId}</p>
58
59
  <p>Date: {message.meta?.bookingDetails?.date}</p>
59
60
  <p>Time: {message.meta?.bookingDetails?.time}</p>
60
61
  <p>Price: ${message.meta?.bookingDetails?.price}</p>
61
62
  </div>
63
+ <button
64
+ className="confirm-button"
65
+ onClick={() => {
66
+ // Add your confirmation logic here
67
+ console.log('Booking confirmed!');
68
+ }}
69
+ >
70
+ Confirm Booking
71
+ <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16">
72
+ <path d="M12.736 3.97a.733.733 0 0 1 1.047 0c.286.289.29.756.01 1.05L7.88 12.01a.733.733 0 0 1-1.065.02L3.217 8.384a.757.757 0 0 1 0-1.06.733.733 0 0 1 1.047 0l3.052 3.093 5.4-6.425a.247.247 0 0 1 .02-.022Z" />
73
+ </svg>
74
+ </button>
62
75
  </div>
63
76
  );
64
77
  }
@@ -101,6 +114,7 @@ const Message = ({ message }: MessageProps) => {
101
114
  // const handleDownload = (url: string, name: string) => {
102
115
  // saveAs(url, name);
103
116
  // };
117
+ console.log("check message status", message.status);
104
118
 
105
119
  const [downloadingIndex, setDownloadingIndex] = useState<number | null>(null);
106
120
  const [downloadProgress, setDownloadProgress] = useState<number>(0);
@@ -193,27 +207,6 @@ const Message = ({ message }: MessageProps) => {
193
207
  }
194
208
  };
195
209
 
196
- // const handleDownload = async (url: string, name: string, index: number) => {
197
- // setDownloadingIndex(index);
198
- // try {
199
- // var xhr = new XMLHttpRequest()
200
- // xhr.open('HEAD', url, false)
201
- // xhr.send()
202
- // const blob = await response.blob();
203
- // const link = document.createElement("a");
204
- // link.href = URL.createObjectURL(blob);
205
- // link.download = name;
206
- // link.click();
207
- // URL.revokeObjectURL(link.href);
208
- // } catch (error) {
209
- // console.error("Download failed:", error);
210
- // } finally {
211
- // setDownloadingIndex(null);
212
- // }
213
- // };
214
-
215
- // const renderMedia = () => {
216
- // if (!message.media || message.media.length === 0) return null;
217
210
 
218
211
  const handleDownload = async (url: string, name: string, index: number) => {
219
212
  setDownloadingIndex(index);
@@ -223,7 +216,6 @@ const Message = ({ message }: MessageProps) => {
223
216
  setDownloadController(controller);
224
217
 
225
218
  try {
226
- // First try to download directly
227
219
  try {
228
220
  const response = await fetch(
229
221
  `${apiUrl}${Path.apiProxy}?url=${encodeURIComponent(
@@ -319,7 +311,7 @@ const Message = ({ message }: MessageProps) => {
319
311
  <div className="circular-progress-container">
320
312
  <div className="media-preview-background">
321
313
  <img
322
- src={media.url}
314
+ src={`${cdnUrl}${`${cdnUrl}${media.url}`}`}
323
315
  alt={media.name}
324
316
  className="blurred-preview"
325
317
  />
@@ -364,16 +356,16 @@ const Message = ({ message }: MessageProps) => {
364
356
  <>
365
357
  {media.type === "image" ? (
366
358
  <img
367
- src={media.url}
359
+ src={`${cdnUrl}${media.url}`}
368
360
  alt={media.name}
369
361
  className="media-content"
370
- onClick={() => window.open(media.url, "_blank")}
362
+ onClick={() => window.open(`${cdnUrl}${media.url}`, "_blank")}
371
363
  />
372
364
  ) : media.type === "video" ? (
373
365
  <video controls className="media-content">
374
366
  <source
375
- src={media.url}
376
- type={`video/${media.url.split(".").pop()}`}
367
+ src={`${cdnUrl}${media.url}`}
368
+ type={`video/${`${cdnUrl}${media.url}`.split(".").pop()}`}
377
369
  />
378
370
  </video>
379
371
  ) : (
@@ -396,7 +388,7 @@ const Message = ({ message }: MessageProps) => {
396
388
  if (downloadingIndex === index) {
397
389
  cancelDownload();
398
390
  } else {
399
- handleDownload(media.url, media.name, index);
391
+ handleDownload(`${cdnUrl}${media.url}`, media.name, index);
400
392
  }
401
393
  }}
402
394
  title={downloadingIndex === index ? "Cancel" : "Download"}
@@ -489,19 +481,28 @@ const Message = ({ message }: MessageProps) => {
489
481
  }
490
482
  };
491
483
 
484
+ const isMessageOlderThanOneDay = (createdAt: string | Date) => {
485
+ const messageDate = new Date(createdAt);
486
+ const now = new Date();
487
+ const oneDayInMs = 24 * 60 * 60 * 1000;
488
+ return now.getTime() - messageDate.getTime() > oneDayInMs;
489
+ };
490
+
491
+ const hasMedia = message.media && message.media.length > 0;
492
+
492
493
  return (
493
494
  <div className="chat-container">
494
495
  <div className={`message-row ${alignItems}`}>
495
496
  <div
496
497
  className="bubble-container"
497
- onMouseEnter={() => fromMe && setShowOptions(true)}
498
+ onMouseEnter={() => fromMe && !hasMedia && setShowOptions(true)}
498
499
  onMouseLeave={() =>
499
500
  fromMe && !showDeleteOption && setShowOptions(false)
500
501
  }
501
502
  >
502
- {message.isDeleted ? (
503
+ {message.status === "deleted" ? (
503
504
  <div className="chat-bubble compact-bubble deleted-message">
504
- <div className="message-text">This message was deleted</div>
505
+ <div className="message-text text-gray-900 dark:text-gray-100">This message was deleted</div>
505
506
  </div>
506
507
  ) : (
507
508
  (message.message ||
@@ -532,7 +533,7 @@ const Message = ({ message }: MessageProps) => {
532
533
  </div>
533
534
  ) : (
534
535
  message.message && (
535
- <div className="message-text">{message.message}</div>
536
+ <div className="message-text text-gray-900 dark:text-gray-100">{message.message}</div>
536
537
  )
537
538
  )}
538
539
 
@@ -540,7 +541,9 @@ const Message = ({ message }: MessageProps) => {
540
541
  {fromMe &&
541
542
  showOptions &&
542
543
  !isEditingMode &&
543
- !message.isDeleted && (
544
+ !message.isDeleted &&
545
+ !hasMedia &&
546
+ !isMessageOlderThanOneDay(message.createdAt) && (
544
547
  <div className="message-options">
545
548
  <button
546
549
  className="message-option-btn edit-btn"
@@ -1,22 +1,17 @@
1
- import { useEffect, useState } from "react";
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */
2
+ import { MessageSquare } from "lucide-react";
3
+ import { useEffect } from "react";
2
4
  import MessageInput from "./MessageInput";
3
5
  import Messages from "./Messages";
4
6
  import useChatUIStore from "../../stores/Zustant";
5
7
  import { useChatContext } from "../../providers/ChatProvider";
6
- import { getChatConfig } from "@pubuduth-aplicy/chat-ui";
8
+ import { getChatConfig } from "../../Chat.config";
7
9
 
8
10
  const MessageContainer = () => {
9
- const {
10
- selectedConversation,
11
- setSelectedConversation,
12
- onlineUsers,
13
- setOnlineUsers,
14
- setMessages,
15
- } = useChatUIStore();
16
- const { socket, sendMessage, isUserOnline } = useChatContext();
11
+ const { selectedConversation, setSelectedConversation, setOnlineUsers } =
12
+ useChatUIStore();
13
+ const { socket, isUserOnline } = useChatContext();
17
14
  const { role } = getChatConfig();
18
- const [joinedChats, setJoinedChats] = useState<Set<string>>(new Set());
19
-
20
15
  // useEffect(() => {
21
16
  // if (!socket) return;
22
17
 
@@ -66,42 +61,58 @@ const MessageContainer = () => {
66
61
 
67
62
  useEffect(() => {
68
63
  if (selectedConversation?._id && socket?.readyState === WebSocket.OPEN) {
69
- const chatId = selectedConversation._id;
70
- const unreadMessages = selectedConversation.unreadMessageIds || [];
71
-
72
- console.log("Unread messages:", unreadMessages);
73
-
74
- if (unreadMessages.length > 0) {
75
- sendMessage({
76
- event: "messageRead",
64
+ // Send joinChat command to server via WebSocket
65
+ socket.send(
66
+ JSON.stringify({
67
+ event: "joinChat",
77
68
  data: {
78
- messageIds: unreadMessages,
79
- chatId: chatId,
69
+ chatId: selectedConversation._id,
80
70
  },
81
- });
82
- }
83
- // }
71
+ })
72
+ );
84
73
  }
85
- }, [
86
- selectedConversation?._id,
87
- socket,
88
- selectedConversation?.unreadMessageIds,
89
- sendMessage,
90
- joinedChats,
91
- ]);
74
+ }, [selectedConversation?._id, socket]);
75
+
76
+ useEffect(() => {
77
+ if (!socket) return;
78
+
79
+ const handleMessage = (event: MessageEvent) => {
80
+ try {
81
+ const data = JSON.parse(event.data);
82
+ console.log("Parsed WebSocket message in mc:", data);
83
+
84
+ if (data.event === "getOnlineUsers") {
85
+ setOnlineUsers(data.payload); // payload should be an array of user IDs
86
+ }
87
+ } catch (err) {
88
+ console.error("Failed to parse WebSocket message", err);
89
+ }
90
+ };
91
+
92
+ socket.addEventListener("message", handleMessage);
93
+
94
+ return () => {
95
+ socket.removeEventListener("message", handleMessage);
96
+ };
97
+ }, [socket, setOnlineUsers]);
92
98
 
93
99
  // Listen for online users updates
94
100
 
95
- role === "admin" && Array.isArray(selectedConversation?.participantDetails)
96
- ? selectedConversation.participantDetails[1]?.profilePic
97
- : !Array.isArray(selectedConversation?.participantDetails)
98
- ? selectedConversation?.participantDetails?.profilePic
99
- : undefined;
101
+ const { userId } = useChatContext();
102
+
103
+ // const participantDetails = Array.isArray(selectedConversation?.participantDetails)
104
+ // ? selectedConversation?.participantDetails
105
+ // : [selectedConversation?.participantDetails].filter(Boolean);
100
106
 
101
- const isOnline =
102
- !Array.isArray(selectedConversation?.participantDetails) &&
103
- !!selectedConversation?.participantDetails?._id &&
104
- isUserOnline(selectedConversation.participantDetails._id);
107
+ // const participant = participantDetails.find(
108
+ // (p: any) => p._id !== userId
109
+ // );
110
+
111
+ const participant = selectedConversation?.participantDetails?.find(
112
+ (p: any) => p._id !== userId
113
+ );
114
+
115
+ const isOnline = isUserOnline(participant?._id || "");
105
116
 
106
117
  // Cleanup on unmount
107
118
  useEffect(() => {
@@ -109,39 +120,48 @@ const MessageContainer = () => {
109
120
  }, [setSelectedConversation]);
110
121
 
111
122
  return (
112
- <div className="chatMessageContainer">
123
+ <div className="chatMessageContainer bg-[#FFFFFF] dark:bg-gray-800 text-gray-900 dark:text-gray-100">
113
124
  {!selectedConversation ? (
114
125
  <EmptyInbox />
115
126
  ) : (
116
127
  <>
117
- <div className="chatMessageContainerInner">
118
- <div className="chatMessageContainerInnerDiv">
128
+ <div className="chatMessageContainerInner bg-[FFFFFF] dark:bg-gray-800">
129
+ <div className="chatMessageContainerInnerDiv text-gray-900 dark:text-gray-200">
119
130
  <button className="chatMessageContainerInnerDiv_button">
120
131
  {/* <CaretLeft size={25} /> */}
121
132
  </button>
122
- <img
123
- className="chatMessageContainerInnerImg"
124
- alt="Profile"
125
- src={
126
- role === "admin" &&
127
- Array.isArray(selectedConversation?.participantDetails)
128
- ? selectedConversation.participantDetails[1]?.profilePic
129
- : !Array.isArray(selectedConversation?.participantDetails)
130
- ? selectedConversation?.participantDetails?.profilePic
131
- : undefined
132
- }
133
- />
133
+ {selectedConversation.type === "service" ? (
134
+ <div className="w-10 h-10 rounded-full bg-gray-200 flex items-center justify-center">
135
+ <MessageSquare size={24} className="text-gray-600" />
136
+ </div>
137
+ ) : (
138
+ <img
139
+ className="chatMessageContainerInnerImg"
140
+ alt="Profile"
141
+ src={participant?.profilePicture}
142
+ />
143
+ )}
134
144
  <div className="chatMessageContainerOutter">
135
145
  <div className="chatMessageContainerOutterDiv">
136
- <p className="chatMessageContainerOutterDiv_name">
137
- {role === "admin" &&
138
- Array.isArray(selectedConversation?.participantDetails)
139
- ? selectedConversation.participantDetails[1]?.firstname
140
- : !Array.isArray(selectedConversation?.participantDetails)
141
- ? selectedConversation?.participantDetails?.firstname
142
- : undefined}
143
- </p>
144
- <p className="text-sm">{isOnline ? "Online" : "Offline"}</p>
146
+ {selectedConversation.type === "service" ? (
147
+ <>
148
+ <p className="chatMessageContainerOutterDiv_name">
149
+ {selectedConversation.serviceTitle}
150
+ </p>
151
+ <p className="text-sm">
152
+ Booking ID: #{selectedConversation.bookingId}
153
+ </p>
154
+ </>
155
+ ) : (
156
+ <>
157
+ <p className="chatMessageContainerOutterDiv_name">
158
+ {participant?.name || ""}
159
+ </p>
160
+ <p className="text-sm">
161
+ {isOnline ? "Online" : "Offline"}
162
+ </p>
163
+ </>
164
+ )}
145
165
  </div>
146
166
  </div>
147
167
  </div>
@@ -1,8 +1,8 @@
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */
1
2
  import React, { useCallback, useEffect, useRef, useState } from "react";
2
3
  import { useMessageMutation } from "../../hooks/mutations/useSendMessage";
3
4
  import { useChatContext } from "../../providers/ChatProvider";
4
5
  import useChatUIStore from "../../stores/Zustant";
5
- import paperplane from "../../assets/icons8-send-50.png";
6
6
  import { FilePreview, FileType } from "../common/FilePreview";
7
7
  import { getApiClient } from "../../lib/api/apiClient";
8
8
  import { MessageStatus } from "../../types/type";
@@ -44,6 +44,7 @@ const MessageInput = () => {
44
44
  const mutation = useMessageMutation();
45
45
  const [typingUser, setTypingUser] = useState<string | null>(null);
46
46
  const [isSending, setIsSending] = useState(false);
47
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
47
48
  const [isTyping, setIsTyping] = useState(false);
48
49
  const [attachments, setAttachments] = useState<Attachment[]>([]);
49
50
  const [showAttachmentOptions, setShowAttachmentOptions] = useState(false);
@@ -55,7 +56,6 @@ const MessageInput = () => {
55
56
  const typingTimeoutRef = useRef<number | null>(null);
56
57
  const generateTempId = () =>
57
58
  `temp-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
58
-
59
59
  // Join chat room when conversation is selected
60
60
  useEffect(() => {
61
61
  if (selectedConversation?._id && socket?.readyState === WebSocket.OPEN) {
@@ -67,6 +67,21 @@ const MessageInput = () => {
67
67
  });
68
68
  }
69
69
  }, [selectedConversation?._id, socket, sendMessage]);
70
+ console.log('selected', selectedConversation);
71
+
72
+ useEffect(() => {
73
+ // Clear all input state when conversation changes
74
+ setMessage("");
75
+ setMessage1("");
76
+ setAttachments([]);
77
+ setInputError(null);
78
+ setShowAttachmentOptions(false);
79
+
80
+ // Clean up any existing file input
81
+ if (fileInputRef.current) {
82
+ fileInputRef.current.value = "";
83
+ }
84
+ }, [selectedConversation?._id]);
70
85
 
71
86
  // Typing indicator logic
72
87
  useEffect(() => {
@@ -178,6 +193,7 @@ const MessageInput = () => {
178
193
  const response = await apiClient.post(`${Path.preSignUrl}`, {
179
194
  fileName: file.name,
180
195
  fileType: file.type,
196
+ conversationId: selectedConversation?._id
181
197
  });
182
198
 
183
199
  const { signedUrl, fileUrl } = await response.data;
@@ -211,6 +227,18 @@ const MessageInput = () => {
211
227
  });
212
228
  };
213
229
 
230
+ const participantDetails = Array.isArray(selectedConversation?.participantDetails)
231
+ ? selectedConversation?.participantDetails
232
+ : [selectedConversation?.participantDetails].filter(Boolean);
233
+
234
+ const otherParticipant = participantDetails.find(
235
+ (p: any) => p._id !== userId
236
+ );
237
+
238
+ // const otherParticipant = selectedConversation?.participantDetails?.find(
239
+ // (p:any) => p._id !== userId
240
+ // );
241
+
214
242
  const handleSubmit = useCallback(
215
243
  async (e: React.FormEvent) => {
216
244
  e.preventDefault();
@@ -294,14 +322,31 @@ const MessageInput = () => {
294
322
 
295
323
  const successfulUploads = uploadedFiles.filter((file) => file !== null);
296
324
 
325
+ if (!otherParticipant?._id) {
326
+ console.error("Cannot send message: receiver ID is missing.");
327
+ setIsSending(false);
328
+ return;
329
+ }
330
+
297
331
  mutation.mutate(
298
332
  {
299
- chatId:
300
- !Array.isArray(selectedConversation?.participantDetails) &&
301
- selectedConversation?.participantDetails._id,
333
+ receiverId: otherParticipant._id,
302
334
  senderId: userId,
303
335
  message: message1,
304
336
  attachments: successfulUploads,
337
+ bookingId:
338
+ selectedConversation?.type === "service"
339
+ ? selectedConversation?.bookingId
340
+ : undefined,
341
+ serviceTitle:
342
+ selectedConversation?.type === "service"
343
+ ? selectedConversation?.title
344
+ : undefined,
345
+ type: selectedConversation?.type,
346
+ serviceId:
347
+ selectedConversation?.type === "service"
348
+ ? selectedConversation?.serviceId
349
+ : undefined,
305
350
  },
306
351
  {
307
352
  onSuccess: (data) => {
@@ -328,9 +373,7 @@ const MessageInput = () => {
328
373
  messageId: data[1]._id,
329
374
  attachments: successfulUploads,
330
375
  senderId: userId,
331
- receiverId:
332
- !Array.isArray(selectedConversation?.participantDetails) &&
333
- selectedConversation?.participantDetails._id,
376
+ receiverId: otherParticipant._id,
334
377
  },
335
378
  });
336
379
  },
@@ -490,7 +533,7 @@ const MessageInput = () => {
490
533
  };
491
534
 
492
535
  return (
493
- <div className="message-input-container">
536
+ <div className="message-input-container bg-[#FFFFFF] dark:bg-gray-800 text-gray-900 dark:text-gray-200">
494
537
  {attachments.length > 0 && (
495
538
  <div className="attachments-preview-container">
496
539
  <button
@@ -533,12 +576,12 @@ const MessageInput = () => {
533
576
  </div>
534
577
  )}
535
578
 
536
- <form className="chatMessageInputform" onSubmit={handleSubmit}>
579
+ <form className="chatMessageInputform bg-[#FFFFFF] dark:bg-gray-800 text-gray-900 dark:text-gray-200" onSubmit={handleSubmit}>
537
580
  {inputError && (
538
581
  <p style={{ color: "red", fontSize: "12px" }}>{inputError}</p>
539
582
  )}
540
583
 
541
- <div className="chatMessageInputdiv">
584
+ <div className="chatMessageInputdiv bg-[#FFFFFF] dark:bg-gray-800 text-gray-900 dark:text-gray-200">
542
585
  <input
543
586
  type="file"
544
587
  ref={fileInputRef}
@@ -638,7 +681,7 @@ const MessageInput = () => {
638
681
  </div>
639
682
 
640
683
  <textarea
641
- className="chatMessageInput"
684
+ className="chatMessageInput bg-[#FFFFFF] dark:bg-gray-800 text-gray-900 dark:text-gray-300"
642
685
  placeholder="Send a message"
643
686
  value={message}
644
687
  onChange={handleChange}
@@ -677,9 +720,7 @@ const MessageInput = () => {
677
720
 
678
721
  {typingUser &&
679
722
  typingUser !== userId &&
680
- typingUser ===
681
- (!Array.isArray(selectedConversation?.participantDetails) &&
682
- selectedConversation?.participantDetails?._id) &&
723
+ typingUser === otherParticipant?._id &&
683
724
  !isSending && (
684
725
  <div className="typingIndicator">
685
726
  <div className="typing-loader">