@pubuduth-aplicy/chat-ui 2.1.57 → 2.1.59

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.57",
3
+ "version": "2.1.59",
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,7 +1,7 @@
1
1
  const Loader = () => {
2
2
  return (
3
-
4
- <div className="dot-spinner">
3
+ <div className="loader-wrapper">
4
+ <div className="dot-spinner">
5
5
  <div className="dot-spinner__dot" />
6
6
  <div className="dot-spinner__dot" />
7
7
  <div className="dot-spinner__dot" />
@@ -11,6 +11,8 @@ const Loader = () => {
11
11
  <div className="dot-spinner__dot" />
12
12
  <div className="dot-spinner__dot" />
13
13
  </div>
14
+ </div>
15
+
14
16
  )
15
17
  }
16
18
 
@@ -11,8 +11,8 @@ import { getApiClient } from "../../lib/api/apiClient";
11
11
  import { MessageStatus } from "../../types/type";
12
12
  import { Path } from "../../lib/api/endpoint";
13
13
  const MAX_FILE_SIZE_MB = 5; // 5MB max file size
14
- const MAX_FILE_COUNT = 5;
15
- const ACCEPTED_IMAGE_TYPES = ['image/jpeg', 'image/png', 'image/gif', 'image/webp','video/mp4', 'video/webm', 'video/ogg'];
14
+ const MAX_FILE_COUNT = 5;
15
+ const ACCEPTED_IMAGE_TYPES = ['image/jpeg', 'image/png', 'image/gif', 'image/webp', 'video/mp4', 'video/webm', 'video/ogg'];
16
16
  const ACCEPTED_VIDEO_TYPES = ['video/mp4', 'video/webm', 'video/ogg'];
17
17
  const ACCEPTED_DOCUMENT_TYPES = ['application/pdf', 'application/msword', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'text/plain'];
18
18
 
@@ -28,14 +28,14 @@ const MessageInput = () => {
28
28
  const apiClient = getApiClient();
29
29
  const { socket } = useChatContext();
30
30
  const { userId } = useChatContext();
31
- const { selectedConversation,setMessages } = useChatUIStore();
32
- const [message, setMessage] = useState("");
33
- const [message1, setMessage1] = useState("");
34
- const mutation = useMessageMutation();
31
+ const { selectedConversation, setMessages } = useChatUIStore();
32
+ const [message, setMessage] = useState("");
33
+ const [message1, setMessage1] = useState("");
34
+ const mutation = useMessageMutation();
35
35
  const [typingUser, setTypingUser] = useState<string | null>(null);
36
36
  const [isSending, setIsSending] = useState(false);
37
37
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
38
- const [isTyping, setIsTyping] = useState(false);
38
+ const [isTyping, setIsTyping] = useState(false);
39
39
  const [attachments, setAttachments] = useState<Attachment[]>([]);
40
40
  const [showAttachmentOptions, setShowAttachmentOptions] = useState(false);
41
41
  const fileInputRef = useRef<HTMLInputElement>(null);
@@ -85,37 +85,37 @@ const MessageInput = () => {
85
85
  if (emailRegex.test(text)) {
86
86
  return "Email addresses are not allowed.";
87
87
  }
88
-
88
+
89
89
  // Check for phone number (very basic)
90
90
  const phoneRegex = /(\+?\d{1,4}[\s-]?)?(\(?\d{3}\)?[\s-]?)?\d{3}[\s-]?\d{4}/;
91
91
  if (phoneRegex.test(text)) {
92
92
  return "Phone numbers are not allowed.";
93
93
  }
94
-
94
+
95
95
  // // Check for bad words
96
96
  // for (const word of badWords) {
97
97
  // if (text.toLowerCase().includes(word)) {
98
98
  // return "Inappropriate language is not allowed.";
99
99
  // }
100
100
  // }
101
-
101
+
102
102
  return null; // No errors
103
103
  };
104
104
 
105
105
  const handleChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {
106
106
  const newValue = e.target.value;
107
107
  const validationError = validateInput(newValue);
108
-
108
+
109
109
  if (validationError) {
110
110
  setInputError(validationError);
111
111
  } else {
112
112
  setInputError(null);
113
113
  setMessage(newValue);
114
114
  setMessage1(newValue);
115
-
115
+
116
116
  }
117
117
  };
118
-
118
+
119
119
 
120
120
  useEffect(() => {
121
121
  if (!socket || !selectedConversation?._id) return;
@@ -148,15 +148,15 @@ const MessageInput = () => {
148
148
  return null;
149
149
  };
150
150
 
151
- const uploadToS3 = async (file: File, onProgress?:(progress:number)=> void): Promise<{ url: string, name: string, size: number, type: FileType }> => {
151
+ const uploadToS3 = async (file: File, onProgress?: (progress: number) => void): Promise<{ url: string, name: string, size: number, type: FileType }> => {
152
152
  const response = await apiClient.post(`${Path.preSignUrl}`, {
153
- fileName: file.name,
154
- fileType: file.type,
155
- }
153
+ fileName: file.name,
154
+ fileType: file.type,
155
+ }
156
156
  );
157
-
157
+
158
158
  const { signedUrl, fileUrl } = await response.data;
159
-
159
+
160
160
  // const uploadResponse = await fetch(signedUrl, {
161
161
  // method: 'PUT',
162
162
  // body: file,
@@ -194,11 +194,11 @@ const MessageInput = () => {
194
194
  xhr.onerror = () => reject(new Error('Upload failed'));
195
195
  xhr.send(file);
196
196
  });
197
-
197
+
198
198
  // if (!uploadResponse.ok) {
199
199
  // throw new Error('Upload failed');
200
200
  // }
201
-
201
+
202
202
  // return {
203
203
  // url: fileUrl,
204
204
  // name: file.name,
@@ -241,11 +241,11 @@ const MessageInput = () => {
241
241
  try {
242
242
 
243
243
  const uploadedFiles = await Promise.all(
244
- attachmentsRef.current.map(async (attachment,index) => {
244
+ attachmentsRef.current.map(async (attachment, index) => {
245
245
  try {
246
- const result = await uploadToS3(attachment.file,(progress)=>{
247
- setMessages(prev => prev.map(msg =>{
248
- if(msg._id === tempId){
246
+ const result = await uploadToS3(attachment.file, (progress) => {
247
+ setMessages(prev => prev.map(msg => {
248
+ if (msg._id === tempId) {
249
249
  const updatedMedia = [...msg.media!];
250
250
  updatedMedia[index] = {
251
251
  ...updatedMedia[index],
@@ -270,7 +270,7 @@ const MessageInput = () => {
270
270
  } catch (error) {
271
271
  console.error(`Error uploading file ${attachment.file.name}:`, error);
272
272
  setMessages(prev => prev.map(msg => {
273
- if(msg._id === tempId){
273
+ if (msg._id === tempId) {
274
274
  const updatedMedia = [...msg.media!];
275
275
  updatedMedia[index] = {
276
276
  ...updatedMedia[index],
@@ -287,8 +287,8 @@ const MessageInput = () => {
287
287
  }
288
288
  })
289
289
  );
290
-
291
-
290
+
291
+
292
292
  const successfulUploads = uploadedFiles.filter(file => file !== null);
293
293
 
294
294
  console.log("📤 Sending message:", successfulUploads);
@@ -300,33 +300,34 @@ const MessageInput = () => {
300
300
  }, {
301
301
  onSuccess: (data) => {
302
302
  console.log('Response from sendMessage:', data);
303
-
304
- socket.emit("sendMessage", {
305
- chatId: selectedConversation?._id,
306
- message: message1,
307
- messageId: data[1]._id,
308
- attachments: successfulUploads,
309
- senderId: userId,
310
- receiverId: selectedConversation?.participantDetails._id,
311
- });
312
303
  setMessages(prev => {
313
304
  console.log("Removing optimistic message:", prev);
314
-
305
+
315
306
  // Definitely remove the optimistic message
316
307
  const filtered = prev.filter(msg => msg._id !== tempMessageId);
317
308
  // Add the real message from server
318
309
  console.log("Adding real message:", filtered);
319
-
310
+
320
311
  return [...filtered, {
321
312
  ...data[1],
322
- isUploading: false,
323
- isOptimistic: false}
324
- ];
313
+ isUploading: false,
314
+ isOptimistic: false
315
+ }
316
+ ];
317
+ });
318
+ socket.emit("sendMessage", {
319
+ chatId: selectedConversation?._id,
320
+ message: message1,
321
+ messageId: data[1]._id,
322
+ attachments: successfulUploads,
323
+ senderId: userId,
324
+ receiverId: selectedConversation?.participantDetails._id,
325
325
  });
326
+
326
327
  },
327
328
  onError: (error) => {
328
329
  console.error("❌ Error in sending message:", error);
329
- setMessages(prev => prev.map(msg =>
330
+ setMessages(prev => prev.map(msg =>
330
331
  msg._id === tempId ? { ...msg, status: 'failed' } : msg
331
332
  ));
332
333
  },
@@ -334,7 +335,7 @@ const MessageInput = () => {
334
335
 
335
336
  } catch (error) {
336
337
  console.error("❌ Error sending message:", error);
337
- setMessages(prev => prev.map(msg =>
338
+ setMessages(prev => prev.map(msg =>
338
339
  msg._id === tempId ? { ...msg, status: 'failed' } : msg
339
340
  ));
340
341
  } finally {
@@ -398,7 +399,7 @@ const MessageInput = () => {
398
399
  // Calculate total size of new files
399
400
  const newFilesSize = Array.from(files).reduce((total, file) => total + file.size, 0);
400
401
  const currentAttachmentsSize = attachments.reduce((total, att) => total + att.file.size, 0);
401
-
402
+
402
403
  // Check if total size would exceed the limit
403
404
  if (currentAttachmentsSize + newFilesSize > MAX_FILE_SIZE_MB * 1024 * 1024) {
404
405
  alert(`Total file size cannot exceed ${MAX_FILE_SIZE_MB}MB`);
@@ -421,7 +422,7 @@ const MessageInput = () => {
421
422
  continue;
422
423
  }
423
424
 
424
- const previewUrl = fileType === 'document'
425
+ const previewUrl = fileType === 'document'
425
426
  ? URL.createObjectURL(new Blob([''], { type: 'application/pdf' })) // Placeholder for documents
426
427
  : URL.createObjectURL(file);
427
428
 
@@ -437,7 +438,7 @@ const MessageInput = () => {
437
438
  fileInputRef.current.value = '';
438
439
  }
439
440
  };
440
-
441
+
441
442
  const scrollAttachments = (direction: 'left' | 'right') => {
442
443
  if (attachmentsContainerRef.current) {
443
444
  const scrollAmount = direction === 'right' ? 200 : -200;
@@ -459,148 +460,149 @@ const MessageInput = () => {
459
460
 
460
461
  return (
461
462
  <div className="message-input-container">
462
- {/* Preview area for attachments */}
463
- {attachments.length > 0 && (
464
- <div className="attachments-preview-container">
465
- <button
466
- className="scroll-button left"
467
- onClick={() => scrollAttachments('left')}
468
- disabled={attachments.length <= 3}
469
- >
470
- &lt;
471
- </button>
472
-
473
- <div className="attachments-preview" ref={attachmentsContainerRef}>
474
- {attachments.map((attachment, index) => (
475
- <FilePreview
476
- key={index}
477
- file={attachment.file}
478
- type={attachment.type}
479
- previewUrl={attachment.previewUrl}
480
- onRemove={() => removeAttachment(index)}
481
- />
482
- ))}
483
-
484
- {attachments.length < MAX_FILE_COUNT && (
485
- <div className="add-more-files" onClick={() => fileInputRef.current?.click()}>
486
- <div className="plus-icon">+</div>
487
- <div className="add-more-text">Add more</div>
488
- </div>
489
- )}
490
- </div>
491
-
492
- <button
493
- className="scroll-button right"
494
- onClick={() => scrollAttachments('right')}
495
- disabled={attachments.length <= 3}
496
- >
497
- &gt;
498
- </button>
499
- </div>
500
- )}
501
-
502
- <form className="chatMessageInputform" onSubmit={handleSubmit}>
503
- <div className="chatMessageInputdiv">
504
- {/* Hidden file input */}
505
- <input
506
- type="file"
507
- ref={fileInputRef}
508
- style={{ display: 'none' }}
509
- onChange={handleFileChange}
510
- multiple
511
- />
512
-
513
- {/* Attachment button and options */}
514
- <div className="attachment-container" style={{ position: 'relative' }}>
463
+ {/* Preview area for attachments */}
464
+ {attachments.length > 0 && (
465
+ <div className="attachments-preview-container">
515
466
  <button
516
- type="button"
517
- className="attachment-button"
518
- onClick={handleAttachmentClick}
519
- style={{
520
- background: 'none',
521
- border: 'none',
522
- cursor: 'pointer',
523
- padding: '8px',
524
- }}
467
+ className="scroll-button left"
468
+ onClick={() => scrollAttachments('left')}
469
+ disabled={attachments.length <= 3}
525
470
  >
526
- <div className="attachment-icon">
527
- <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
528
- <path d="M21.44 11.05l-9.19 9.19a6 6 0 0 1-8.49-8.49l9.19-9.19a4 4 0 0 1 5.66 5.66l-9.2 9.19a2 2 0 0 1-2.83-2.83l8.49-8.48"></path>
529
- </svg>
530
- </div>
471
+ &lt;
531
472
  </button>
532
473
 
533
- {showAttachmentOptions && (
534
- <div className="attachment-options">
535
- <button
536
- type="button"
537
- onClick={() => handleFileSelect('image')}
538
- >
539
- <div className="icon">
540
- <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
541
- <rect x="3" y="3" width="18" height="18" rx="2" ry="2"></rect>
542
- <circle cx="8.5" cy="8.5" r="1.5"></circle>
543
- <polyline points="21 15 16 10 5 21"></polyline>
544
- </svg>
545
- </div>
546
- <span>Photos & videos</span>
547
- </button>
548
- <button
549
- type="button"
550
- onClick={() => handleFileSelect('document')}
551
- >
552
- <div className="icon">
553
- <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
554
- <path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path>
555
- <polyline points="14 2 14 8 20 8"></polyline>
556
- <line x1="16" y1="13" x2="8" y2="13"></line>
557
- <line x1="16" y1="17" x2="8" y2="17"></line>
558
- <polyline points="10 9 9 9 8 9"></polyline>
559
- </svg>
560
- </div>
561
- <span>Document</span>
562
- </button>
563
- </div>
564
- )}
474
+ <div className="attachments-preview" ref={attachmentsContainerRef}>
475
+ {attachments.map((attachment, index) => (
476
+ <FilePreview
477
+ key={index}
478
+ file={attachment.file}
479
+ type={attachment.type}
480
+ previewUrl={attachment.previewUrl}
481
+ onRemove={() => removeAttachment(index)}
482
+ />
483
+ ))}
484
+
485
+ {attachments.length < MAX_FILE_COUNT && (
486
+ <div className="add-more-files" onClick={() => fileInputRef.current?.click()}>
487
+ <div className="plus-icon">+</div>
488
+ <div className="add-more-text">Add more</div>
489
+ </div>
490
+ )}
491
+ </div>
492
+
493
+ <button
494
+ className="scroll-button right"
495
+ onClick={() => scrollAttachments('right')}
496
+ disabled={attachments.length <= 3}
497
+ >
498
+ &gt;
499
+ </button>
565
500
  </div>
501
+ )}
566
502
 
567
- <textarea
568
- className="chatMessageInput"
569
- placeholder="Send a message"
570
- value={message}
571
- // onChange={(e) => {
572
- // setMessage(e.target.value)
573
- // autoResizeTextarea(e.target)
574
- // }}
575
- onChange={handleChange}
576
- rows={1}
577
- style={{ resize: "none" }}
578
- onKeyDown={(e) => {
579
- if (e.key === "Enter" && !e.shiftKey) {
580
- e.preventDefault()
581
- handleSubmit(e)
582
- }
583
- }}
584
- />
585
-
586
- {inputError && <p style={{ color: 'red', fontSize: '12px' }}>{inputError}</p>}
587
- <button type="submit" className="chatMessageInputSubmit" disabled={!!inputError || isSending}>
588
- <img width={10} height={10} src={paperplane} alt="send" />
589
- </button>
590
- </div>
591
-
592
- {typingUser && typingUser !== userId && typingUser === selectedConversation?.participantDetails?._id && !isSending && (
593
- <div className="typingIndicator">
594
- <div className="typing-loader">
595
- <div className="ball" />
596
- <div className="ball" />
597
- <div className="ball" />
598
- typing
503
+ <form className="chatMessageInputform" onSubmit={handleSubmit}>
504
+ {inputError && <p style={{ color: 'red', fontSize: '12px' }}>{inputError}</p>}
505
+
506
+ <div className="chatMessageInputdiv">
507
+ {/* Hidden file input */}
508
+ <input
509
+ type="file"
510
+ ref={fileInputRef}
511
+ style={{ display: 'none' }}
512
+ onChange={handleFileChange}
513
+ multiple
514
+ />
515
+
516
+ {/* Attachment button and options */}
517
+ <div className="attachment-container" style={{ position: 'relative' }}>
518
+ <button
519
+ type="button"
520
+ className="attachment-button"
521
+ onClick={handleAttachmentClick}
522
+ style={{
523
+ background: 'none',
524
+ border: 'none',
525
+ cursor: 'pointer',
526
+ padding: '8px',
527
+ }}
528
+ >
529
+ <div className="attachment-icon">
530
+ <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
531
+ <path d="M21.44 11.05l-9.19 9.19a6 6 0 0 1-8.49-8.49l9.19-9.19a4 4 0 0 1 5.66 5.66l-9.2 9.19a2 2 0 0 1-2.83-2.83l8.49-8.48"></path>
532
+ </svg>
533
+ </div>
534
+ </button>
535
+
536
+ {showAttachmentOptions && (
537
+ <div className="attachment-options">
538
+ <button
539
+ type="button"
540
+ onClick={() => handleFileSelect('image')}
541
+ >
542
+ <div className="icon">
543
+ <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
544
+ <rect x="3" y="3" width="18" height="18" rx="2" ry="2"></rect>
545
+ <circle cx="8.5" cy="8.5" r="1.5"></circle>
546
+ <polyline points="21 15 16 10 5 21"></polyline>
547
+ </svg>
548
+ </div>
549
+ <span>Photos & videos</span>
550
+ </button>
551
+ <button
552
+ type="button"
553
+ onClick={() => handleFileSelect('document')}
554
+ >
555
+ <div className="icon">
556
+ <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
557
+ <path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path>
558
+ <polyline points="14 2 14 8 20 8"></polyline>
559
+ <line x1="16" y1="13" x2="8" y2="13"></line>
560
+ <line x1="16" y1="17" x2="8" y2="17"></line>
561
+ <polyline points="10 9 9 9 8 9"></polyline>
562
+ </svg>
563
+ </div>
564
+ <span>Document</span>
565
+ </button>
566
+ </div>
567
+ )}
599
568
  </div>
569
+
570
+ <textarea
571
+ className="chatMessageInput"
572
+ placeholder="Send a message"
573
+ value={message}
574
+ // onChange={(e) => {
575
+ // setMessage(e.target.value)
576
+ // autoResizeTextarea(e.target)
577
+ // }}
578
+ onChange={handleChange}
579
+ rows={1}
580
+ style={{ resize: "none" }}
581
+ onKeyDown={(e) => {
582
+ if (e.key === "Enter" && !e.shiftKey) {
583
+ e.preventDefault()
584
+ handleSubmit(e)
585
+ }
586
+ }}
587
+ />
588
+
589
+ <button type="submit" className="chatMessageInputSubmit" disabled={!!inputError || isSending}>
590
+ <img width={10} height={10} src={paperplane} alt="send" />
591
+ </button>
600
592
  </div>
601
- )}
602
- </form>
603
- </div>
593
+
594
+ {typingUser && typingUser !== userId && typingUser === selectedConversation?.participantDetails?._id && !isSending && (
595
+ <div className="typingIndicator">
596
+ <div className="typing-loader">
597
+ <div className="ball" />
598
+ <div className="ball" />
599
+ <div className="ball" />
600
+ typing
601
+ </div>
602
+ </div>
603
+ )}
604
+ </form>
605
+ </div>
604
606
  );
605
607
  };
606
608
 
@@ -12,7 +12,7 @@ const Conversations = () => {
12
12
  // const { loading, conversations } = useGetConversations();
13
13
  return (
14
14
  <div className="chatSidebarConversations">
15
- <h2 className="text-lg font-semibold text-gray-700">All Messages</h2>
15
+ <h2 className="text-lg font-semibold text-gray-700" style={{paddingLeft:'1rem'}}>All Messages</h2>
16
16
  {(!conversations || conversations.length === 0) && (
17
17
  <div className="flex flex-col items-center justify-center p-8 text-center">
18
18
  <div className="flex h-16 w-16 items-center justify-center rounded-full bg-gray-100 mb-4">
@@ -34,8 +34,8 @@
34
34
 
35
35
  .chatSidebarSearchbar {
36
36
  display: inline-flex;
37
- padding-top: 2.4rem;
38
- padding-bottom: 2.5rem;
37
+ padding-top: 2.4125rem;
38
+ padding-bottom: 2.45rem;
39
39
  /* padding-left: 1rem; */
40
40
  padding-right: 1rem;
41
41
  gap: 1rem;
@@ -73,23 +73,33 @@
73
73
  padding-bottom: 3px;
74
74
  }
75
75
 
76
+ .loader-wrapper {
77
+ display: flex;
78
+ align-items: center;
79
+ justify-content: center;
80
+ height: 100%;
81
+ width: 100%;
82
+ }
83
+
76
84
  .chatSidebarInput {
77
- outline: none;
78
- padding: 8px 4px; /* Keep original padding */
79
- font-size: 1rem;
80
- border-radius: 4px;
81
- line-height: 1.5rem;
82
- font-weight: 400;
83
- border: 1px solid #ccc;
84
- width: 100%; /* Ensure full width */
85
- /* min-width: 400px; */
86
- max-width: 600px;
85
+ outline: none;
86
+ padding: 8px 4px;
87
+ /* Keep original padding */
88
+ font-size: 1rem;
89
+ border-radius: 4px;
90
+ line-height: 1.5rem;
91
+ font-weight: 400;
92
+ border: 1px solid #ccc;
93
+ width: 100%;
94
+ /* Ensure full width */
95
+ /* min-width: 400px; */
96
+ max-width: 600px;
87
97
  }
88
98
 
89
99
  .chatSidebarInput:focus {
90
- border: 1px solid #12bbb5 !important;
91
- box-shadow: 0 0 5px rgba(18, 187, 181, 0.5);
92
- transition: border-color 0.3s ease-in-out;
100
+ border: 1px solid #12bbb5 !important;
101
+ box-shadow: 0 0 5px rgba(18, 187, 181, 0.5);
102
+ transition: border-color 0.3s ease-in-out;
93
103
  }
94
104
 
95
105
  .chatSidebarConversations {
@@ -114,7 +124,7 @@ transition: border-color 0.3s ease-in-out;
114
124
  /* height: 72px; */
115
125
 
116
126
  :hover {
117
- background-color: transparent;
127
+ background-color: transparent;
118
128
  }
119
129
  }
120
130
 
@@ -202,8 +212,8 @@ transition: border-color 0.3s ease-in-out;
202
212
 
203
213
  .chatMessageContainerOutter {
204
214
  display: inline-flex;
205
- flex-basis: 0px;
206
- flex-direction: column;
215
+ /* flex-basis: 0px;
216
+ flex-direction: column; */
207
217
  shrink: 1;
208
218
  gap: 0.25rem;
209
219
  justify-content: flex-start;
@@ -258,7 +268,7 @@ transition: border-color 0.3s ease-in-out;
258
268
  .chatMessagesBubble_me {
259
269
  float: right;
260
270
  color: white;
261
- background-color: #076663;
271
+ background-color: #076663;
262
272
  padding: 0.5rem 0.875rem;
263
273
  }
264
274
 
@@ -266,7 +276,7 @@ transition: border-color 0.3s ease-in-out;
266
276
  float: left;
267
277
  background-color: #f3f4f6;
268
278
  color: #374151;
269
- padding: 0.5rem 0.875rem;
279
+ padding: 0.5rem 0.875rem;
270
280
  }
271
281
 
272
282
  .chatMessage {
@@ -301,10 +311,10 @@ transition: border-color 0.3s ease-in-out;
301
311
 
302
312
  .chatMessagesBubble_Time {
303
313
  display: block;
304
- text-align: right;
305
- font-size: 10px;
306
- color: #d1d1d1;
307
- margin-top: 5px;
314
+ text-align: right;
315
+ font-size: 10px;
316
+ color: #d1d1d1;
317
+ margin-top: 5px;
308
318
  }
309
319
 
310
320
  .chatMessageInputform {
@@ -318,6 +328,7 @@ margin-top: 5px;
318
328
  margin-top: 0.75rem;
319
329
  /* margin-bottom: 0.75rem; */
320
330
  }
331
+
321
332
  .chatMessageInputdiv {
322
333
  display: flex;
323
334
  align-items: center;
@@ -342,7 +353,8 @@ margin-top: 5px;
342
353
  line-height: 1.25rem;
343
354
  overflow-y: auto; */
344
355
  outline: none;
345
- padding: 8px 4px; /* Keep original padding */
356
+ padding: 8px 4px;
357
+ /* Keep original padding */
346
358
  font-size: 1rem;
347
359
  border-radius: 4px;
348
360
  line-height: 1.5rem;
@@ -353,17 +365,18 @@ margin-top: 5px;
353
365
  min-height: 1.47em;
354
366
  white-space: pre-wrap;
355
367
  word-break: break-all;
356
- overflow-y: auto; /* Allow vertical scrolling if needed */
368
+ overflow-y: auto;
369
+ /* Allow vertical scrolling if needed */
357
370
  }
358
371
 
359
372
  .chatMessageInput:focus {
360
- border: 1px solid #12bbb5 !important;
361
- box-shadow: 0 0 5px rgba(18, 187, 181, 0.5);
362
- transition: border-color 0.3s ease-in-out;
373
+ border: 1px solid #12bbb5 !important;
374
+ box-shadow: 0 0 5px rgba(18, 187, 181, 0.5);
375
+ transition: border-color 0.3s ease-in-out;
363
376
  }
364
377
 
365
378
  .chatMessageInput::-webkit-scrollbar {
366
- display: none;
379
+ display: none;
367
380
  }
368
381
 
369
382
  .chatMessageInputSubmit {
@@ -378,54 +391,54 @@ display: none;
378
391
  }
379
392
 
380
393
  .chat-container {
381
- width: 100%;
382
- font-family: Arial, sans-serif;
394
+ width: 100%;
395
+ font-family: Arial, sans-serif;
383
396
  }
384
397
 
385
398
  .message-row {
386
- display: flex;
387
- align-items: flex-end;
388
- margin-bottom: 16px;
389
- gap: 10px;
390
- word-break: break-all;
391
- max-width: 100%;
399
+ display: flex;
400
+ align-items: flex-end;
401
+ margin-bottom: 16px;
402
+ gap: 10px;
403
+ word-break: break-all;
404
+ max-width: 100%;
392
405
 
393
406
  }
394
407
 
395
408
  .message-row.incoming {
396
- justify-content: flex-start;
409
+ justify-content: flex-start;
397
410
  }
398
411
 
399
412
  .message-row.outgoing {
400
- justify-content: flex-end;
413
+ justify-content: flex-end;
401
414
  }
402
415
 
403
416
 
404
417
  .bubble-container {
405
- display: flex;
406
- flex-direction: column;
407
- max-width: 70%;
418
+ display: flex;
419
+ flex-direction: column;
420
+ max-width: 70%;
408
421
  }
409
422
 
410
423
  .chat-bubble {
411
424
 
412
- background-color: #f3f4f6;
413
- border-radius: 0.5rem;
414
- padding: 0.5rem;
415
- font-size: 14px;
416
- max-width: 20rem;
417
- margin-bottom: 5px;
425
+ background-color: #f3f4f6;
426
+ border-radius: 0.5rem;
427
+ padding: 0.5rem;
428
+ font-size: 14px;
429
+ max-width: 20rem;
430
+ margin-bottom: 5px;
418
431
  }
419
432
 
420
433
  .outgoing .chat-bubble {
421
- background-color: #12bbb5;
422
- color: white;
434
+ background-color: #12bbb5;
435
+ color: white;
423
436
 
424
437
  }
425
438
 
426
439
  .incoming .chat-bubble {
427
- background-color: #dedee4b9;
428
- color: black;
440
+ background-color: #dedee4b9;
441
+ color: black;
429
442
  }
430
443
 
431
444
  .timestamp_incomeing {
@@ -438,35 +451,35 @@ color: black;
438
451
  float: left;
439
452
  position: relative;
440
453
  justify-content: start;
441
- }
442
-
443
-
444
- .timestamp_outgoing {
445
- font-size: 11px;
446
- color: #888;
447
- margin-top: 4px;
448
- text-align: right;
449
- display: flex;
450
- align-items: center;
451
- float: right;
452
- position: relative;
453
- justify-content: end;
454
- }
454
+ }
455
+
456
+
457
+ .timestamp_outgoing {
458
+ font-size: 11px;
459
+ color: #888;
460
+ margin-top: 4px;
461
+ text-align: right;
462
+ display: flex;
463
+ align-items: center;
464
+ float: right;
465
+ position: relative;
466
+ justify-content: end;
467
+ }
455
468
 
456
469
  .status-icon {
457
470
 
458
- bottom: 5px;
459
- margin-left: 10px;
460
- right: 10px;
461
- font-size: 12px;
471
+ bottom: 5px;
472
+ margin-left: 10px;
473
+ right: 10px;
474
+ font-size: 12px;
462
475
  }
463
476
 
464
477
  .read {
465
- color: blue;
478
+ color: blue;
466
479
  }
467
480
 
468
- .text-sm{
469
- font-size: .875rem;
481
+ .text-sm {
482
+ font-size: .875rem;
470
483
  }
471
484
 
472
485
  /* @media (min-width: 640px) {
@@ -492,47 +505,47 @@ font-size: .875rem;
492
505
 
493
506
  @media (min-width: 768px) {
494
507
  .grid-container {
495
- height: 550px;
496
- grid-template-columns: repeat(9, minmax(0, 1fr));
508
+ height: 550px;
509
+ grid-template-columns: repeat(9, minmax(0, 1fr));
497
510
  }
498
511
 
499
512
  .sidebarContainer {
500
- /* display: grid; */
501
- grid-column: span 4 ;
513
+ /* display: grid; */
514
+ grid-column: span 4;
502
515
  }
503
516
 
504
517
  .messageContainer {
505
- display: grid;
506
- grid-column: span 5;
518
+ display: grid;
519
+ grid-column: span 5;
507
520
  }
508
521
 
509
522
  .chatMessageContainerInnerDiv_button {
510
- display: none;
523
+ display: none;
511
524
  }
512
525
 
513
526
  .chatMessages {
514
- padding-left: 2rem;
515
- padding-right: 2rem;
527
+ padding-left: 2rem;
528
+ padding-right: 2rem;
516
529
  }
517
530
 
518
531
  }
519
532
 
520
- .typingIndicator{
533
+ .typingIndicator {
521
534
  display: flex;
522
535
  align-items: center;
523
- gap: 0.5rem;
536
+ gap: 0.2rem;
524
537
  }
525
538
 
526
- /* From Uiverse.io by ashish-yadv */
539
+ /* From Uiverse.io by ashish-yadv */
527
540
  .typing-loader {
528
541
  width: 60px;
529
542
  display: flex;
530
543
  align-items: center;
531
- height: 100%;
532
- margin-right: 10px;
533
- width: 100%;
544
+ height: 100%;
545
+ margin-right: 10px;
546
+ width: 100%;
534
547
  font-size: smaller;
535
- gap: 0.5rem;
548
+ gap: 0.3rem;
536
549
  }
537
550
 
538
551
  .ball {
@@ -572,7 +585,7 @@ width: 100%;
572
585
  }
573
586
  }
574
587
 
575
- /* From Uiverse.io by abrahamcalsin */
588
+ /* From Uiverse.io by abrahamcalsin */
576
589
  .dot-spinner {
577
590
  --uib-size: 2.8rem;
578
591
  --uib-speed: .9s;
@@ -666,166 +679,168 @@ width: 100%;
666
679
 
667
680
  /* Sidebar Container */
668
681
  .chatSidebar {
669
- background: #ffffff;
670
- padding: 15px;
671
- border-radius: 10px;
672
- box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1);
673
- width: 300px;
682
+ background: #ffffff;
683
+ padding: 15px;
684
+ border-radius: 10px;
685
+ box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1);
686
+ width: 300px;
674
687
  }
675
688
 
676
689
  /* Chat List */
677
690
  .chatItem {
678
- display: flex;
679
- align-items: center;
680
- padding: 12px;
681
- border-radius: 8px;
682
- transition: background 0.3s;
691
+ display: flex;
692
+ align-items: center;
693
+ padding: 12px;
694
+ border-radius: 8px;
695
+ transition: background 0.3s;
683
696
  }
684
697
 
685
698
  .chatItem:hover {
686
- background: #f0f0f0;
687
- cursor: pointer;
699
+ background: #f0f0f0;
700
+ cursor: pointer;
688
701
  }
689
702
 
690
703
  /* Profile Images */
691
704
  .chatAvatar {
692
- width: 40px;
693
- height: 40px;
694
- border-radius: 50%;
695
- margin-right: 12px;
696
- border: 2px solid #ccc;
697
- transition: transform 0.3s ease-in-out;
705
+ width: 40px;
706
+ height: 40px;
707
+ border-radius: 50%;
708
+ margin-right: 12px;
709
+ border: 2px solid #ccc;
710
+ transition: transform 0.3s ease-in-out;
698
711
  }
699
712
 
700
713
  .chatAvatar:hover {
701
- transform: scale(1.1);
714
+ transform: scale(1.1);
702
715
  }
703
716
 
704
717
  /* Chat Details */
705
718
  .chatDetails {
706
- flex-grow: 1;
719
+ flex-grow: 1;
707
720
  }
708
721
 
709
722
  .chatName {
710
- font-weight: 600;
711
- color: #333;
723
+ font-weight: 600;
724
+ color: #333;
712
725
  }
713
726
 
714
727
  .chatMessage {
715
- font-size: 0.9rem;
716
- color: #777;
728
+ font-size: 0.9rem;
729
+ color: #777;
717
730
  }
718
731
 
719
732
  /* Chat Time */
720
733
  .chatTime {
721
- font-size: 0.8rem;
722
- color: #aaa;
734
+ font-size: 0.8rem;
735
+ color: #aaa;
723
736
  }
724
737
 
725
738
 
726
739
 
727
740
  /* Position the status dot on the corner of the profile picture */
728
741
  .chatSidebarConversationImg {
729
- position: relative;
730
- width: 3rem;
731
- height: 3rem;
732
- border-radius: 100%;
742
+ position: relative;
743
+ width: 3rem;
744
+ height: 3rem;
745
+ border-radius: 100%;
733
746
  }
734
747
 
735
748
  /* The status dot */
736
749
  .chatSidebarStatusDot {
737
- position: absolute;
738
- bottom: 0;
739
- right: 0;
740
- width: 12px;
741
- height: 12px;
742
- border-radius: 50%;
743
- border: 2px solid white; /* Border for a neat appearance */
750
+ position: absolute;
751
+ bottom: 0;
752
+ right: 0;
753
+ width: 12px;
754
+ height: 12px;
755
+ border-radius: 50%;
756
+ border: 2px solid white;
757
+ /* Border for a neat appearance */
744
758
  }
745
759
 
746
760
 
747
761
  /* For online status */
748
762
  .chatSidebarStatusDot.online {
749
- background-color: green;
763
+ background-color: green;
750
764
  }
751
765
 
752
766
  /* For offline status */
753
767
  .chatSidebarStatusDot.offline {
754
- background-color: rgba(179, 170, 170, 0.712);
768
+ background-color: rgba(179, 170, 170, 0.712);
755
769
  }
756
770
 
757
771
  .conversation-container {
758
- display: flex;
759
- align-items: center;
760
- gap: 12px;
761
- padding: 12px;
762
- /* border-radius: 8px; */
763
- border-bottom: .5px solid lightgray;
764
- background-color: white;
765
- /* box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); */
766
- cursor: pointer;
767
- transition: background-color 0.3s ease-in-out;
772
+ display: flex;
773
+ align-items: center;
774
+ gap: 12px;
775
+ padding: 12px;
776
+ /* border-radius: 8px; */
777
+ border-bottom: .5px solid lightgray;
778
+ background-color: white;
779
+ /* box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); */
780
+ cursor: pointer;
781
+ transition: background-color 0.3s ease-in-out;
768
782
  }
769
783
 
770
784
  .conversation-container:hover {
771
- background-color: #f5f5f5;
785
+ background-color: #f5f5f5;
772
786
  }
773
787
 
774
788
  .conversation-avatar {
775
- position: relative;
789
+ position: relative;
776
790
  }
777
791
 
778
792
  .conversation-img {
779
- width: 48px;
780
- height: 48px;
781
- border-radius: 50%;
782
- border: 2px solid #ccc;
783
- transition: border-color 0.3s;
793
+ width: 48px;
794
+ height: 48px;
795
+ border-radius: 50%;
796
+ border: 2px solid #ccc;
797
+ transition: border-color 0.3s;
784
798
  }
785
799
 
786
800
  .conversation-img:hover {
787
- border-color: #12bbb5;
801
+ border-color: #12bbb5;
788
802
  }
789
803
 
790
804
 
791
805
  .conversation-info {
792
- flex-grow: 1;
793
- display: flex;
794
- flex-direction: column;
806
+ flex-grow: 1;
807
+ display: flex;
808
+ flex-direction: column;
795
809
  }
796
810
 
797
811
  .conversation-header {
798
- display: flex;
799
- justify-content: space-between;
800
- align-items: center;
812
+ display: flex;
813
+ justify-content: space-between;
814
+ align-items: center;
801
815
  }
802
816
 
803
817
  .conversation-name {
804
- font-size: 14px;
805
- font-weight: bold;
806
- color: #333;
818
+ font-size: 14px;
819
+ font-weight: bold;
820
+ color: #333;
807
821
  }
808
822
 
809
823
  .conversation-time {
810
- font-size: 12px;
811
- color: #777;
824
+ font-size: 12px;
825
+ color: #777;
812
826
  }
813
827
 
814
828
  .conversation-message {
815
- font-size: 12px;
816
- color: #777;
817
- white-space: nowrap;
818
- overflow: hidden;
819
- text-overflow: ellipsis;
829
+ font-size: 12px;
830
+ color: #777;
831
+ white-space: nowrap;
832
+ overflow: hidden;
833
+ text-overflow: ellipsis;
820
834
  }
821
835
 
822
836
  .divider {
823
- background-color: #ccc;
837
+ background-color: #ccc;
824
838
 
825
839
  }
826
840
 
827
841
 
828
842
  @keyframes pulse0112 {
843
+
829
844
  0%,
830
845
  100% {
831
846
  transform: scale(0);
@@ -866,7 +881,8 @@ background-color: #ccc;
866
881
  }
867
882
 
868
883
  .attachments-preview::-webkit-scrollbar {
869
- display: none; /* Hide scrollbar for Chrome/Safari */
884
+ display: none;
885
+ /* Hide scrollbar for Chrome/Safari */
870
886
  }
871
887
 
872
888
  .file-preview-wrapper {
@@ -889,7 +905,8 @@ background-color: #ccc;
889
905
  .file-preview {
890
906
  position: relative;
891
907
  /* width: 246px; */
892
- height: 100px; /* Increased height to accommodate filename */
908
+ height: 100px;
909
+ /* Increased height to accommodate filename */
893
910
  border-radius: 8px;
894
911
  overflow: hidden;
895
912
  background: linear-gradient(135deg, #f9f9f9, #e9ecef);
@@ -932,7 +949,7 @@ background-color: #ccc;
932
949
 
933
950
  .add-more-files:hover {
934
951
  border-color: #999;
935
- background: rgba(0,0,0,0.02);
952
+ background: rgba(0, 0, 0, 0.02);
936
953
  }
937
954
 
938
955
  .plus-icon {
@@ -971,6 +988,7 @@ background-color: #ccc;
971
988
  object-fit: cover;
972
989
  border-radius: 8px;
973
990
  }
991
+
974
992
  .file-preview-document span,
975
993
  .file-name {
976
994
  display: block;
@@ -1101,12 +1119,13 @@ background-color: #ccc;
1101
1119
  left: 0;
1102
1120
  background-color: white;
1103
1121
  border-radius: 8px;
1104
- box-shadow: 0 2px 10px rgba(0,0,0,0.2);
1122
+ box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);
1105
1123
  padding: 8px;
1106
1124
  z-index: 1000;
1107
1125
  display: flex;
1108
1126
  flex-direction: column;
1109
1127
  gap: 4px;
1128
+ white-space: nowrap;
1110
1129
  }
1111
1130
 
1112
1131
  .attachment-options button {
@@ -1133,7 +1152,8 @@ background-color: #ccc;
1133
1152
 
1134
1153
  .media-item {
1135
1154
  background: #f3f4f6;
1136
- border-radius: 0.375rem; /* reduced from 0.75rem */
1155
+ border-radius: 0.375rem;
1156
+ /* reduced from 0.75rem */
1137
1157
  padding: 0.5rem;
1138
1158
  overflow: hidden;
1139
1159
  display: flex;
@@ -1142,7 +1162,7 @@ background-color: #ccc;
1142
1162
  width: 246px;
1143
1163
  }
1144
1164
 
1145
- .media-content{
1165
+ .media-content {
1146
1166
  width: 100%;
1147
1167
  object-fit: cover;
1148
1168
  }
@@ -1150,7 +1170,8 @@ background-color: #ccc;
1150
1170
  .media-preview {
1151
1171
  max-width: 100%;
1152
1172
  max-height: 200px;
1153
- border-radius: 0.375rem; /* reduced from 0.5rem */
1173
+ border-radius: 0.375rem;
1174
+ /* reduced from 0.5rem */
1154
1175
  object-fit: cover;
1155
1176
  }
1156
1177
 
@@ -1193,7 +1214,8 @@ background-color: #ccc;
1193
1214
  .document-preview {
1194
1215
  position: relative;
1195
1216
  width: 246px;
1196
- height: 60px; /* Increased height to accommodate filename */
1217
+ height: 60px;
1218
+ /* Increased height to accommodate filename */
1197
1219
  border-radius: 12px;
1198
1220
  overflow: hidden;
1199
1221
  background: linear-gradient(135deg, #f9f9f9, #e9ecef);
@@ -1222,8 +1244,13 @@ background-color: #ccc;
1222
1244
  }
1223
1245
 
1224
1246
  @keyframes spin {
1225
- 0% { transform: rotate(0deg); }
1226
- 100% { transform: rotate(360deg); }
1247
+ 0% {
1248
+ transform: rotate(0deg);
1249
+ }
1250
+
1251
+ 100% {
1252
+ transform: rotate(360deg);
1253
+ }
1227
1254
  }
1228
1255
 
1229
1256