@pubuduth-aplicy/chat-ui 2.1.58 → 2.1.60

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.58",
3
+ "version": "2.1.60",
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": "",
@@ -0,0 +1,17 @@
1
+ const SystemNotice = () => (
2
+ <div style={{
3
+ padding: "1rem",
4
+ border: "1px solid #ddd",
5
+ borderRadius: "8px",
6
+ margin: "1rem",
7
+ backgroundColor: "#f9f9f9",
8
+ fontSize: "14px",
9
+ }}>
10
+ <strong style={{ display: "block", marginBottom: "0.5rem", textAlign:"center", fontSize:"smaller" }}>🛡 WE HAVE YOUR BACK</strong>
11
+ <p style={{fontSize:"x-small"}}>For added safety and your protection, keep payments and communications within Gigmosaic.
12
+ {/* <a href="#">Learn more</a> */}
13
+ </p>
14
+ </div>
15
+ );
16
+ export default SystemNotice;
17
+
@@ -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);
@@ -83,39 +83,41 @@ const MessageInput = () => {
83
83
  // Check for email
84
84
  const emailRegex = /\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}\b/i;
85
85
  if (emailRegex.test(text)) {
86
- return "Email addresses are not allowed.";
86
+ return "To protect your account, make sure not to share any personal or sensitive information.";
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
- return "Phone numbers are not allowed.";
92
+ return "To protect your account, make sure not to share any personal or sensitive information.";
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
+ setMessage(newValue);
112
+ setMessage1(newValue);
111
113
  } else {
112
114
  setInputError(null);
113
115
  setMessage(newValue);
114
116
  setMessage1(newValue);
115
-
117
+
116
118
  }
117
119
  };
118
-
120
+
119
121
 
120
122
  useEffect(() => {
121
123
  if (!socket || !selectedConversation?._id) return;
@@ -148,15 +150,15 @@ const MessageInput = () => {
148
150
  return null;
149
151
  };
150
152
 
151
- const uploadToS3 = async (file: File, onProgress?:(progress:number)=> void): Promise<{ url: string, name: string, size: number, type: FileType }> => {
153
+ const uploadToS3 = async (file: File, onProgress?: (progress: number) => void): Promise<{ url: string, name: string, size: number, type: FileType }> => {
152
154
  const response = await apiClient.post(`${Path.preSignUrl}`, {
153
- fileName: file.name,
154
- fileType: file.type,
155
- }
155
+ fileName: file.name,
156
+ fileType: file.type,
157
+ }
156
158
  );
157
-
159
+
158
160
  const { signedUrl, fileUrl } = await response.data;
159
-
161
+
160
162
  // const uploadResponse = await fetch(signedUrl, {
161
163
  // method: 'PUT',
162
164
  // body: file,
@@ -194,11 +196,11 @@ const MessageInput = () => {
194
196
  xhr.onerror = () => reject(new Error('Upload failed'));
195
197
  xhr.send(file);
196
198
  });
197
-
199
+
198
200
  // if (!uploadResponse.ok) {
199
201
  // throw new Error('Upload failed');
200
202
  // }
201
-
203
+
202
204
  // return {
203
205
  // url: fileUrl,
204
206
  // name: file.name,
@@ -241,11 +243,11 @@ const MessageInput = () => {
241
243
  try {
242
244
 
243
245
  const uploadedFiles = await Promise.all(
244
- attachmentsRef.current.map(async (attachment,index) => {
246
+ attachmentsRef.current.map(async (attachment, index) => {
245
247
  try {
246
- const result = await uploadToS3(attachment.file,(progress)=>{
247
- setMessages(prev => prev.map(msg =>{
248
- if(msg._id === tempId){
248
+ const result = await uploadToS3(attachment.file, (progress) => {
249
+ setMessages(prev => prev.map(msg => {
250
+ if (msg._id === tempId) {
249
251
  const updatedMedia = [...msg.media!];
250
252
  updatedMedia[index] = {
251
253
  ...updatedMedia[index],
@@ -270,7 +272,7 @@ const MessageInput = () => {
270
272
  } catch (error) {
271
273
  console.error(`Error uploading file ${attachment.file.name}:`, error);
272
274
  setMessages(prev => prev.map(msg => {
273
- if(msg._id === tempId){
275
+ if (msg._id === tempId) {
274
276
  const updatedMedia = [...msg.media!];
275
277
  updatedMedia[index] = {
276
278
  ...updatedMedia[index],
@@ -287,8 +289,8 @@ const MessageInput = () => {
287
289
  }
288
290
  })
289
291
  );
290
-
291
-
292
+
293
+
292
294
  const successfulUploads = uploadedFiles.filter(file => file !== null);
293
295
 
294
296
  console.log("📤 Sending message:", successfulUploads);
@@ -300,33 +302,34 @@ const MessageInput = () => {
300
302
  }, {
301
303
  onSuccess: (data) => {
302
304
  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
305
  setMessages(prev => {
313
306
  console.log("Removing optimistic message:", prev);
314
-
307
+
315
308
  // Definitely remove the optimistic message
316
309
  const filtered = prev.filter(msg => msg._id !== tempMessageId);
317
310
  // Add the real message from server
318
311
  console.log("Adding real message:", filtered);
319
-
312
+
320
313
  return [...filtered, {
321
314
  ...data[1],
322
- isUploading: false,
323
- isOptimistic: false}
324
- ];
315
+ isUploading: false,
316
+ isOptimistic: false
317
+ }
318
+ ];
319
+ });
320
+ socket.emit("sendMessage", {
321
+ chatId: selectedConversation?._id,
322
+ message: message1,
323
+ messageId: data[1]._id,
324
+ attachments: successfulUploads,
325
+ senderId: userId,
326
+ receiverId: selectedConversation?.participantDetails._id,
325
327
  });
328
+
326
329
  },
327
330
  onError: (error) => {
328
331
  console.error("❌ Error in sending message:", error);
329
- setMessages(prev => prev.map(msg =>
332
+ setMessages(prev => prev.map(msg =>
330
333
  msg._id === tempId ? { ...msg, status: 'failed' } : msg
331
334
  ));
332
335
  },
@@ -334,7 +337,7 @@ const MessageInput = () => {
334
337
 
335
338
  } catch (error) {
336
339
  console.error("❌ Error sending message:", error);
337
- setMessages(prev => prev.map(msg =>
340
+ setMessages(prev => prev.map(msg =>
338
341
  msg._id === tempId ? { ...msg, status: 'failed' } : msg
339
342
  ));
340
343
  } finally {
@@ -398,7 +401,7 @@ const MessageInput = () => {
398
401
  // Calculate total size of new files
399
402
  const newFilesSize = Array.from(files).reduce((total, file) => total + file.size, 0);
400
403
  const currentAttachmentsSize = attachments.reduce((total, att) => total + att.file.size, 0);
401
-
404
+
402
405
  // Check if total size would exceed the limit
403
406
  if (currentAttachmentsSize + newFilesSize > MAX_FILE_SIZE_MB * 1024 * 1024) {
404
407
  alert(`Total file size cannot exceed ${MAX_FILE_SIZE_MB}MB`);
@@ -421,7 +424,7 @@ const MessageInput = () => {
421
424
  continue;
422
425
  }
423
426
 
424
- const previewUrl = fileType === 'document'
427
+ const previewUrl = fileType === 'document'
425
428
  ? URL.createObjectURL(new Blob([''], { type: 'application/pdf' })) // Placeholder for documents
426
429
  : URL.createObjectURL(file);
427
430
 
@@ -437,7 +440,7 @@ const MessageInput = () => {
437
440
  fileInputRef.current.value = '';
438
441
  }
439
442
  };
440
-
443
+
441
444
  const scrollAttachments = (direction: 'left' | 'right') => {
442
445
  if (attachmentsContainerRef.current) {
443
446
  const scrollAmount = direction === 'right' ? 200 : -200;
@@ -459,148 +462,149 @@ const MessageInput = () => {
459
462
 
460
463
  return (
461
464
  <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' }}>
465
+ {/* Preview area for attachments */}
466
+ {attachments.length > 0 && (
467
+ <div className="attachments-preview-container">
515
468
  <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
- }}
469
+ className="scroll-button left"
470
+ onClick={() => scrollAttachments('left')}
471
+ disabled={attachments.length <= 3}
525
472
  >
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>
473
+ &lt;
531
474
  </button>
532
475
 
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
- )}
476
+ <div className="attachments-preview" ref={attachmentsContainerRef}>
477
+ {attachments.map((attachment, index) => (
478
+ <FilePreview
479
+ key={index}
480
+ file={attachment.file}
481
+ type={attachment.type}
482
+ previewUrl={attachment.previewUrl}
483
+ onRemove={() => removeAttachment(index)}
484
+ />
485
+ ))}
486
+
487
+ {attachments.length < MAX_FILE_COUNT && (
488
+ <div className="add-more-files" onClick={() => fileInputRef.current?.click()}>
489
+ <div className="plus-icon">+</div>
490
+ <div className="add-more-text">Add more</div>
491
+ </div>
492
+ )}
493
+ </div>
494
+
495
+ <button
496
+ className="scroll-button right"
497
+ onClick={() => scrollAttachments('right')}
498
+ disabled={attachments.length <= 3}
499
+ >
500
+ &gt;
501
+ </button>
565
502
  </div>
503
+ )}
566
504
 
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
505
+ <form className="chatMessageInputform" onSubmit={handleSubmit}>
506
+ {inputError && <p style={{ color: 'red', fontSize: '12px' }}>{inputError}</p>}
507
+
508
+ <div className="chatMessageInputdiv">
509
+ {/* Hidden file input */}
510
+ <input
511
+ type="file"
512
+ ref={fileInputRef}
513
+ style={{ display: 'none' }}
514
+ onChange={handleFileChange}
515
+ multiple
516
+ />
517
+
518
+ {/* Attachment button and options */}
519
+ <div className="attachment-container" style={{ position: 'relative' }}>
520
+ <button
521
+ type="button"
522
+ className="attachment-button"
523
+ onClick={handleAttachmentClick}
524
+ style={{
525
+ background: 'none',
526
+ border: 'none',
527
+ cursor: 'pointer',
528
+ padding: '8px',
529
+ }}
530
+ >
531
+ <div className="attachment-icon">
532
+ <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">
533
+ <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>
534
+ </svg>
535
+ </div>
536
+ </button>
537
+
538
+ {showAttachmentOptions && (
539
+ <div className="attachment-options">
540
+ <button
541
+ type="button"
542
+ onClick={() => handleFileSelect('image')}
543
+ >
544
+ <div className="icon">
545
+ <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">
546
+ <rect x="3" y="3" width="18" height="18" rx="2" ry="2"></rect>
547
+ <circle cx="8.5" cy="8.5" r="1.5"></circle>
548
+ <polyline points="21 15 16 10 5 21"></polyline>
549
+ </svg>
550
+ </div>
551
+ <span>Photos & videos</span>
552
+ </button>
553
+ <button
554
+ type="button"
555
+ onClick={() => handleFileSelect('document')}
556
+ >
557
+ <div className="icon">
558
+ <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">
559
+ <path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path>
560
+ <polyline points="14 2 14 8 20 8"></polyline>
561
+ <line x1="16" y1="13" x2="8" y2="13"></line>
562
+ <line x1="16" y1="17" x2="8" y2="17"></line>
563
+ <polyline points="10 9 9 9 8 9"></polyline>
564
+ </svg>
565
+ </div>
566
+ <span>Document</span>
567
+ </button>
568
+ </div>
569
+ )}
599
570
  </div>
571
+
572
+ <textarea
573
+ className="chatMessageInput"
574
+ placeholder="Send a message"
575
+ value={message}
576
+ // onChange={(e) => {
577
+ // setMessage(e.target.value)
578
+ // autoResizeTextarea(e.target)
579
+ // }}
580
+ onChange={handleChange}
581
+ rows={1}
582
+ style={{ resize: "none" }}
583
+ onKeyDown={(e) => {
584
+ if (e.key === "Enter" && !e.shiftKey) {
585
+ e.preventDefault()
586
+ handleSubmit(e)
587
+ }
588
+ }}
589
+ />
590
+
591
+ <button type="submit" className="chatMessageInputSubmit" disabled={!!inputError || isSending}>
592
+ <img width={10} height={10} src={paperplane} alt="send" />
593
+ </button>
600
594
  </div>
601
- )}
602
- </form>
603
- </div>
595
+
596
+ {typingUser && typingUser !== userId && typingUser === selectedConversation?.participantDetails?._id && !isSending && (
597
+ <div className="typingIndicator">
598
+ <div className="typing-loader">
599
+ <div className="ball" />
600
+ <div className="ball" />
601
+ <div className="ball" />
602
+ typing
603
+ </div>
604
+ </div>
605
+ )}
606
+ </form>
607
+ </div>
604
608
  );
605
609
  };
606
610
 
@@ -7,6 +7,7 @@ import { useInfiniteQuery } from "@tanstack/react-query";
7
7
  import { fetchMessages } from "../../service/messageService";
8
8
  import { useInView } from "react-intersection-observer";
9
9
  import Loader from "../Loader";
10
+ import SystemNotice from "../common/SystemNotice";
10
11
 
11
12
  const Messages = () => {
12
13
  const { selectedConversation, setMessages, messages } = useChatUIStore();
@@ -164,6 +165,7 @@ const Messages = () => {
164
165
  className="chatMessages"
165
166
  style={{ overflowY: "auto", height: "100%", position: "relative" }}
166
167
  >
168
+ <SystemNotice/>
167
169
  <div ref={ref} className="my-8">
168
170
  {isFetchingNextPage ? <Loader /> : null}
169
171
  </div>
@@ -83,9 +83,17 @@ const Conversation = ({ conversation, lastIdx }: ConversationProps) => {
83
83
  </span>
84
84
  </div>
85
85
  <p className="conversation-message">
86
- {conversation.lastMessage.message.length > 50
86
+ {conversation.lastMessage.message.length > 50
87
87
  ? conversation.lastMessage.message.slice(0, 50) + "..."
88
- : conversation.lastMessage.message}
88
+ :conversation.lastMessage.media.length > 0 ?
89
+ <div style={{display:"flex",alignItems:"center", gap:"5px"}}>
90
+ <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">
91
+ <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>
92
+ </svg>
93
+ attachment
94
+ </div>
95
+
96
+ :conversation.lastMessage.message}
89
97
  </p>
90
98
  </div>
91
99
  </div>
@@ -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">
@@ -73,7 +73,7 @@
73
73
  padding-bottom: 3px;
74
74
  }
75
75
 
76
- .loader-wrapper{
76
+ .loader-wrapper {
77
77
  display: flex;
78
78
  align-items: center;
79
79
  justify-content: center;
@@ -82,22 +82,24 @@
82
82
  }
83
83
 
84
84
  .chatSidebarInput {
85
- outline: none;
86
- padding: 8px 4px; /* Keep original padding */
87
- font-size: 1rem;
88
- border-radius: 4px;
89
- line-height: 1.5rem;
90
- font-weight: 400;
91
- border: 1px solid #ccc;
92
- width: 100%; /* Ensure full width */
93
- /* min-width: 400px; */
94
- 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;
95
97
  }
96
98
 
97
99
  .chatSidebarInput:focus {
98
- border: 1px solid #12bbb5 !important;
99
- box-shadow: 0 0 5px rgba(18, 187, 181, 0.5);
100
- 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;
101
103
  }
102
104
 
103
105
  .chatSidebarConversations {
@@ -122,7 +124,7 @@ transition: border-color 0.3s ease-in-out;
122
124
  /* height: 72px; */
123
125
 
124
126
  :hover {
125
- background-color: transparent;
127
+ background-color: transparent;
126
128
  }
127
129
  }
128
130
 
@@ -210,8 +212,8 @@ transition: border-color 0.3s ease-in-out;
210
212
 
211
213
  .chatMessageContainerOutter {
212
214
  display: inline-flex;
213
- flex-basis: 0px;
214
- flex-direction: column;
215
+ /* flex-basis: 0px;
216
+ flex-direction: column; */
215
217
  shrink: 1;
216
218
  gap: 0.25rem;
217
219
  justify-content: flex-start;
@@ -266,7 +268,7 @@ transition: border-color 0.3s ease-in-out;
266
268
  .chatMessagesBubble_me {
267
269
  float: right;
268
270
  color: white;
269
- background-color: #076663;
271
+ background-color: #076663;
270
272
  padding: 0.5rem 0.875rem;
271
273
  }
272
274
 
@@ -274,7 +276,7 @@ transition: border-color 0.3s ease-in-out;
274
276
  float: left;
275
277
  background-color: #f3f4f6;
276
278
  color: #374151;
277
- padding: 0.5rem 0.875rem;
279
+ padding: 0.5rem 0.875rem;
278
280
  }
279
281
 
280
282
  .chatMessage {
@@ -309,10 +311,10 @@ transition: border-color 0.3s ease-in-out;
309
311
 
310
312
  .chatMessagesBubble_Time {
311
313
  display: block;
312
- text-align: right;
313
- font-size: 10px;
314
- color: #d1d1d1;
315
- margin-top: 5px;
314
+ text-align: right;
315
+ font-size: 10px;
316
+ color: #d1d1d1;
317
+ margin-top: 5px;
316
318
  }
317
319
 
318
320
  .chatMessageInputform {
@@ -326,6 +328,7 @@ margin-top: 5px;
326
328
  margin-top: 0.75rem;
327
329
  /* margin-bottom: 0.75rem; */
328
330
  }
331
+
329
332
  .chatMessageInputdiv {
330
333
  display: flex;
331
334
  align-items: center;
@@ -350,7 +353,8 @@ margin-top: 5px;
350
353
  line-height: 1.25rem;
351
354
  overflow-y: auto; */
352
355
  outline: none;
353
- padding: 8px 4px; /* Keep original padding */
356
+ padding: 8px 4px;
357
+ /* Keep original padding */
354
358
  font-size: 1rem;
355
359
  border-radius: 4px;
356
360
  line-height: 1.5rem;
@@ -361,17 +365,18 @@ margin-top: 5px;
361
365
  min-height: 1.47em;
362
366
  white-space: pre-wrap;
363
367
  word-break: break-all;
364
- overflow-y: auto; /* Allow vertical scrolling if needed */
368
+ overflow-y: auto;
369
+ /* Allow vertical scrolling if needed */
365
370
  }
366
371
 
367
372
  .chatMessageInput:focus {
368
- border: 1px solid #12bbb5 !important;
369
- box-shadow: 0 0 5px rgba(18, 187, 181, 0.5);
370
- 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;
371
376
  }
372
377
 
373
378
  .chatMessageInput::-webkit-scrollbar {
374
- display: none;
379
+ display: none;
375
380
  }
376
381
 
377
382
  .chatMessageInputSubmit {
@@ -386,54 +391,54 @@ display: none;
386
391
  }
387
392
 
388
393
  .chat-container {
389
- width: 100%;
390
- font-family: Arial, sans-serif;
394
+ width: 100%;
395
+ font-family: Arial, sans-serif;
391
396
  }
392
397
 
393
398
  .message-row {
394
- display: flex;
395
- align-items: flex-end;
396
- margin-bottom: 16px;
397
- gap: 10px;
398
- word-break: break-all;
399
- 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%;
400
405
 
401
406
  }
402
407
 
403
408
  .message-row.incoming {
404
- justify-content: flex-start;
409
+ justify-content: flex-start;
405
410
  }
406
411
 
407
412
  .message-row.outgoing {
408
- justify-content: flex-end;
413
+ justify-content: flex-end;
409
414
  }
410
415
 
411
416
 
412
417
  .bubble-container {
413
- display: flex;
414
- flex-direction: column;
415
- max-width: 70%;
418
+ display: flex;
419
+ flex-direction: column;
420
+ max-width: 70%;
416
421
  }
417
422
 
418
423
  .chat-bubble {
419
424
 
420
- background-color: #f3f4f6;
421
- border-radius: 0.5rem;
422
- padding: 0.5rem;
423
- font-size: 14px;
424
- max-width: 20rem;
425
- 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;
426
431
  }
427
432
 
428
433
  .outgoing .chat-bubble {
429
- background-color: #12bbb5;
430
- color: white;
434
+ background-color: #12bbb5;
435
+ color: white;
431
436
 
432
437
  }
433
438
 
434
439
  .incoming .chat-bubble {
435
- background-color: #dedee4b9;
436
- color: black;
440
+ background-color: #dedee4b9;
441
+ color: black;
437
442
  }
438
443
 
439
444
  .timestamp_incomeing {
@@ -446,35 +451,35 @@ color: black;
446
451
  float: left;
447
452
  position: relative;
448
453
  justify-content: start;
449
- }
450
-
451
-
452
- .timestamp_outgoing {
453
- font-size: 11px;
454
- color: #888;
455
- margin-top: 4px;
456
- text-align: right;
457
- display: flex;
458
- align-items: center;
459
- float: right;
460
- position: relative;
461
- justify-content: end;
462
- }
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
+ }
463
468
 
464
469
  .status-icon {
465
470
 
466
- bottom: 5px;
467
- margin-left: 10px;
468
- right: 10px;
469
- font-size: 12px;
471
+ bottom: 5px;
472
+ margin-left: 10px;
473
+ right: 10px;
474
+ font-size: 12px;
470
475
  }
471
476
 
472
477
  .read {
473
- color: blue;
478
+ color: blue;
474
479
  }
475
480
 
476
- .text-sm{
477
- font-size: .875rem;
481
+ .text-sm {
482
+ font-size: .875rem;
478
483
  }
479
484
 
480
485
  /* @media (min-width: 640px) {
@@ -500,47 +505,47 @@ font-size: .875rem;
500
505
 
501
506
  @media (min-width: 768px) {
502
507
  .grid-container {
503
- height: 550px;
504
- grid-template-columns: repeat(9, minmax(0, 1fr));
508
+ height: 550px;
509
+ grid-template-columns: repeat(9, minmax(0, 1fr));
505
510
  }
506
511
 
507
512
  .sidebarContainer {
508
- /* display: grid; */
509
- grid-column: span 4 ;
513
+ /* display: grid; */
514
+ grid-column: span 4;
510
515
  }
511
516
 
512
517
  .messageContainer {
513
- display: grid;
514
- grid-column: span 5;
518
+ display: grid;
519
+ grid-column: span 5;
515
520
  }
516
521
 
517
522
  .chatMessageContainerInnerDiv_button {
518
- display: none;
523
+ display: none;
519
524
  }
520
525
 
521
526
  .chatMessages {
522
- padding-left: 2rem;
523
- padding-right: 2rem;
527
+ padding-left: 2rem;
528
+ padding-right: 2rem;
524
529
  }
525
530
 
526
531
  }
527
532
 
528
- .typingIndicator{
533
+ .typingIndicator {
529
534
  display: flex;
530
535
  align-items: center;
531
- gap: 0.5rem;
536
+ gap: 0.2rem;
532
537
  }
533
538
 
534
- /* From Uiverse.io by ashish-yadv */
539
+ /* From Uiverse.io by ashish-yadv */
535
540
  .typing-loader {
536
541
  width: 60px;
537
542
  display: flex;
538
543
  align-items: center;
539
- height: 100%;
540
- margin-right: 10px;
541
- width: 100%;
544
+ height: 100%;
545
+ margin-right: 10px;
546
+ width: 100%;
542
547
  font-size: smaller;
543
- gap: 0.5rem;
548
+ gap: 0.3rem;
544
549
  }
545
550
 
546
551
  .ball {
@@ -580,7 +585,7 @@ width: 100%;
580
585
  }
581
586
  }
582
587
 
583
- /* From Uiverse.io by abrahamcalsin */
588
+ /* From Uiverse.io by abrahamcalsin */
584
589
  .dot-spinner {
585
590
  --uib-size: 2.8rem;
586
591
  --uib-speed: .9s;
@@ -674,166 +679,168 @@ width: 100%;
674
679
 
675
680
  /* Sidebar Container */
676
681
  .chatSidebar {
677
- background: #ffffff;
678
- padding: 15px;
679
- border-radius: 10px;
680
- box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1);
681
- 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;
682
687
  }
683
688
 
684
689
  /* Chat List */
685
690
  .chatItem {
686
- display: flex;
687
- align-items: center;
688
- padding: 12px;
689
- border-radius: 8px;
690
- transition: background 0.3s;
691
+ display: flex;
692
+ align-items: center;
693
+ padding: 12px;
694
+ border-radius: 8px;
695
+ transition: background 0.3s;
691
696
  }
692
697
 
693
698
  .chatItem:hover {
694
- background: #f0f0f0;
695
- cursor: pointer;
699
+ background: #f0f0f0;
700
+ cursor: pointer;
696
701
  }
697
702
 
698
703
  /* Profile Images */
699
704
  .chatAvatar {
700
- width: 40px;
701
- height: 40px;
702
- border-radius: 50%;
703
- margin-right: 12px;
704
- border: 2px solid #ccc;
705
- 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;
706
711
  }
707
712
 
708
713
  .chatAvatar:hover {
709
- transform: scale(1.1);
714
+ transform: scale(1.1);
710
715
  }
711
716
 
712
717
  /* Chat Details */
713
718
  .chatDetails {
714
- flex-grow: 1;
719
+ flex-grow: 1;
715
720
  }
716
721
 
717
722
  .chatName {
718
- font-weight: 600;
719
- color: #333;
723
+ font-weight: 600;
724
+ color: #333;
720
725
  }
721
726
 
722
727
  .chatMessage {
723
- font-size: 0.9rem;
724
- color: #777;
728
+ font-size: 0.9rem;
729
+ color: #777;
725
730
  }
726
731
 
727
732
  /* Chat Time */
728
733
  .chatTime {
729
- font-size: 0.8rem;
730
- color: #aaa;
734
+ font-size: 0.8rem;
735
+ color: #aaa;
731
736
  }
732
737
 
733
738
 
734
739
 
735
740
  /* Position the status dot on the corner of the profile picture */
736
741
  .chatSidebarConversationImg {
737
- position: relative;
738
- width: 3rem;
739
- height: 3rem;
740
- border-radius: 100%;
742
+ position: relative;
743
+ width: 3rem;
744
+ height: 3rem;
745
+ border-radius: 100%;
741
746
  }
742
747
 
743
748
  /* The status dot */
744
749
  .chatSidebarStatusDot {
745
- position: absolute;
746
- bottom: 0;
747
- right: 0;
748
- width: 12px;
749
- height: 12px;
750
- border-radius: 50%;
751
- 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 */
752
758
  }
753
759
 
754
760
 
755
761
  /* For online status */
756
762
  .chatSidebarStatusDot.online {
757
- background-color: green;
763
+ background-color: green;
758
764
  }
759
765
 
760
766
  /* For offline status */
761
767
  .chatSidebarStatusDot.offline {
762
- background-color: rgba(179, 170, 170, 0.712);
768
+ background-color: rgba(179, 170, 170, 0.712);
763
769
  }
764
770
 
765
771
  .conversation-container {
766
- display: flex;
767
- align-items: center;
768
- gap: 12px;
769
- padding: 12px;
770
- /* border-radius: 8px; */
771
- border-bottom: .5px solid lightgray;
772
- background-color: white;
773
- /* box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); */
774
- cursor: pointer;
775
- 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;
776
782
  }
777
783
 
778
784
  .conversation-container:hover {
779
- background-color: #f5f5f5;
785
+ background-color: #f5f5f5;
780
786
  }
781
787
 
782
788
  .conversation-avatar {
783
- position: relative;
789
+ position: relative;
784
790
  }
785
791
 
786
792
  .conversation-img {
787
- width: 48px;
788
- height: 48px;
789
- border-radius: 50%;
790
- border: 2px solid #ccc;
791
- 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;
792
798
  }
793
799
 
794
800
  .conversation-img:hover {
795
- border-color: #12bbb5;
801
+ border-color: #12bbb5;
796
802
  }
797
803
 
798
804
 
799
805
  .conversation-info {
800
- flex-grow: 1;
801
- display: flex;
802
- flex-direction: column;
806
+ flex-grow: 1;
807
+ display: flex;
808
+ flex-direction: column;
803
809
  }
804
810
 
805
811
  .conversation-header {
806
- display: flex;
807
- justify-content: space-between;
808
- align-items: center;
812
+ display: flex;
813
+ justify-content: space-between;
814
+ align-items: center;
809
815
  }
810
816
 
811
817
  .conversation-name {
812
- font-size: 14px;
813
- font-weight: bold;
814
- color: #333;
818
+ font-size: 14px;
819
+ font-weight: bold;
820
+ color: #333;
815
821
  }
816
822
 
817
823
  .conversation-time {
818
- font-size: 12px;
819
- color: #777;
824
+ font-size: 12px;
825
+ color: #777;
820
826
  }
821
827
 
822
828
  .conversation-message {
823
- font-size: 12px;
824
- color: #777;
825
- white-space: nowrap;
826
- overflow: hidden;
827
- text-overflow: ellipsis;
829
+ font-size: 12px;
830
+ color: #777;
831
+ white-space: nowrap;
832
+ overflow: hidden;
833
+ text-overflow: ellipsis;
828
834
  }
829
835
 
830
836
  .divider {
831
- background-color: #ccc;
837
+ background-color: #ccc;
832
838
 
833
839
  }
834
840
 
835
841
 
836
842
  @keyframes pulse0112 {
843
+
837
844
  0%,
838
845
  100% {
839
846
  transform: scale(0);
@@ -874,7 +881,8 @@ background-color: #ccc;
874
881
  }
875
882
 
876
883
  .attachments-preview::-webkit-scrollbar {
877
- display: none; /* Hide scrollbar for Chrome/Safari */
884
+ display: none;
885
+ /* Hide scrollbar for Chrome/Safari */
878
886
  }
879
887
 
880
888
  .file-preview-wrapper {
@@ -897,7 +905,8 @@ background-color: #ccc;
897
905
  .file-preview {
898
906
  position: relative;
899
907
  /* width: 246px; */
900
- height: 100px; /* Increased height to accommodate filename */
908
+ height: 100px;
909
+ /* Increased height to accommodate filename */
901
910
  border-radius: 8px;
902
911
  overflow: hidden;
903
912
  background: linear-gradient(135deg, #f9f9f9, #e9ecef);
@@ -940,7 +949,7 @@ background-color: #ccc;
940
949
 
941
950
  .add-more-files:hover {
942
951
  border-color: #999;
943
- background: rgba(0,0,0,0.02);
952
+ background: rgba(0, 0, 0, 0.02);
944
953
  }
945
954
 
946
955
  .plus-icon {
@@ -979,6 +988,7 @@ background-color: #ccc;
979
988
  object-fit: cover;
980
989
  border-radius: 8px;
981
990
  }
991
+
982
992
  .file-preview-document span,
983
993
  .file-name {
984
994
  display: block;
@@ -1109,7 +1119,7 @@ background-color: #ccc;
1109
1119
  left: 0;
1110
1120
  background-color: white;
1111
1121
  border-radius: 8px;
1112
- box-shadow: 0 2px 10px rgba(0,0,0,0.2);
1122
+ box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);
1113
1123
  padding: 8px;
1114
1124
  z-index: 1000;
1115
1125
  display: flex;
@@ -1142,7 +1152,8 @@ background-color: #ccc;
1142
1152
 
1143
1153
  .media-item {
1144
1154
  background: #f3f4f6;
1145
- border-radius: 0.375rem; /* reduced from 0.75rem */
1155
+ border-radius: 0.375rem;
1156
+ /* reduced from 0.75rem */
1146
1157
  padding: 0.5rem;
1147
1158
  overflow: hidden;
1148
1159
  display: flex;
@@ -1151,7 +1162,7 @@ background-color: #ccc;
1151
1162
  width: 246px;
1152
1163
  }
1153
1164
 
1154
- .media-content{
1165
+ .media-content {
1155
1166
  width: 100%;
1156
1167
  object-fit: cover;
1157
1168
  }
@@ -1159,7 +1170,8 @@ background-color: #ccc;
1159
1170
  .media-preview {
1160
1171
  max-width: 100%;
1161
1172
  max-height: 200px;
1162
- border-radius: 0.375rem; /* reduced from 0.5rem */
1173
+ border-radius: 0.375rem;
1174
+ /* reduced from 0.5rem */
1163
1175
  object-fit: cover;
1164
1176
  }
1165
1177
 
@@ -1202,7 +1214,8 @@ background-color: #ccc;
1202
1214
  .document-preview {
1203
1215
  position: relative;
1204
1216
  width: 246px;
1205
- height: 60px; /* Increased height to accommodate filename */
1217
+ height: 60px;
1218
+ /* Increased height to accommodate filename */
1206
1219
  border-radius: 12px;
1207
1220
  overflow: hidden;
1208
1221
  background: linear-gradient(135deg, #f9f9f9, #e9ecef);
@@ -1231,8 +1244,13 @@ background-color: #ccc;
1231
1244
  }
1232
1245
 
1233
1246
  @keyframes spin {
1234
- 0% { transform: rotate(0deg); }
1235
- 100% { transform: rotate(360deg); }
1247
+ 0% {
1248
+ transform: rotate(0deg);
1249
+ }
1250
+
1251
+ 100% {
1252
+ transform: rotate(360deg);
1253
+ }
1236
1254
  }
1237
1255
 
1238
1256
 
package/src/types/type.ts CHANGED
@@ -51,6 +51,7 @@ export interface ConversationProps {
51
51
  _id: string;
52
52
  senderId: string;
53
53
  message: string;
54
+ media:string[];
54
55
  chatId: string;
55
56
  createdAt: string;
56
57
  updatedAt: string;