@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 +1 -1
- package/src/components/common/SystemNotice.tsx +17 -0
- package/src/components/messages/MessageInput.tsx +187 -183
- package/src/components/messages/Messages.tsx +2 -0
- package/src/components/sidebar/Conversation.tsx +10 -2
- package/src/components/sidebar/Conversations.tsx +1 -1
- package/src/style/style.css +192 -174
- package/src/types/type.ts +1 -0
package/package.json
CHANGED
|
@@ -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 "
|
|
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 "
|
|
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
|
-
|
|
154
|
-
|
|
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
|
-
|
|
323
|
-
|
|
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
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
<button
|
|
466
|
-
className="scroll-button left"
|
|
467
|
-
onClick={() => scrollAttachments('left')}
|
|
468
|
-
disabled={attachments.length <= 3}
|
|
469
|
-
>
|
|
470
|
-
<
|
|
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
|
-
>
|
|
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
|
-
|
|
517
|
-
|
|
518
|
-
|
|
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
|
-
|
|
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
|
+
<
|
|
531
474
|
</button>
|
|
532
475
|
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
<
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
<
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
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
|
+
>
|
|
501
|
+
</button>
|
|
565
502
|
</div>
|
|
503
|
+
)}
|
|
566
504
|
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
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
|
-
|
|
603
|
-
|
|
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
|
-
|
|
86
|
+
{conversation.lastMessage.message.length > 50
|
|
87
87
|
? conversation.lastMessage.message.slice(0, 50) + "..."
|
|
88
|
-
:
|
|
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">
|
package/src/style/style.css
CHANGED
|
@@ -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;
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
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
|
-
|
|
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;
|
|
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;
|
|
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
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
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
|
-
|
|
504
|
-
|
|
508
|
+
height: 550px;
|
|
509
|
+
grid-template-columns: repeat(9, minmax(0, 1fr));
|
|
505
510
|
}
|
|
506
511
|
|
|
507
512
|
.sidebarContainer {
|
|
508
|
-
|
|
509
|
-
|
|
513
|
+
/* display: grid; */
|
|
514
|
+
grid-column: span 4;
|
|
510
515
|
}
|
|
511
516
|
|
|
512
517
|
.messageContainer {
|
|
513
|
-
|
|
514
|
-
|
|
518
|
+
display: grid;
|
|
519
|
+
grid-column: span 5;
|
|
515
520
|
}
|
|
516
521
|
|
|
517
522
|
.chatMessageContainerInnerDiv_button {
|
|
518
|
-
|
|
523
|
+
display: none;
|
|
519
524
|
}
|
|
520
525
|
|
|
521
526
|
.chatMessages {
|
|
522
|
-
|
|
523
|
-
|
|
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.
|
|
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.
|
|
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;
|
|
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;
|
|
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;
|
|
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;
|
|
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;
|
|
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;
|
|
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% {
|
|
1235
|
-
|
|
1247
|
+
0% {
|
|
1248
|
+
transform: rotate(0deg);
|
|
1249
|
+
}
|
|
1250
|
+
|
|
1251
|
+
100% {
|
|
1252
|
+
transform: rotate(360deg);
|
|
1253
|
+
}
|
|
1236
1254
|
}
|
|
1237
1255
|
|
|
1238
1256
|
|