@pubuduth-aplicy/chat-ui 2.1.68 → 2.1.69
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 +2 -1
- package/src/components/Chat.tsx +32 -59
- package/src/components/messages/Message.tsx +173 -7
- package/src/components/messages/MessageContainer.tsx +55 -40
- package/src/components/messages/MessageInput.tsx +333 -248
- package/src/components/messages/Messages.tsx +58 -91
- package/src/components/sidebar/Conversation.tsx +55 -38
- package/src/hooks/mutations/useDeleteMessage.ts +26 -0
- package/src/hooks/mutations/useEditMessage.ts +25 -0
- package/src/lib/api/apiClient.ts +1 -1
- package/src/lib/api/endpoint.ts +3 -1
- package/src/providers/ChatProvider.tsx +85 -66
- package/src/service/messageService.ts +46 -1
- package/src/style/style.css +36 -13
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pubuduth-aplicy/chat-ui",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.69",
|
|
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": "",
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
"dependencies": {
|
|
15
15
|
"@tanstack/react-query": "^5.67.2",
|
|
16
16
|
"axios": "^1.8.2",
|
|
17
|
+
"lucide-react": "^0.514.0",
|
|
17
18
|
"react": "^19.0.0",
|
|
18
19
|
"react-dom": "^19.0.0",
|
|
19
20
|
"react-intersection-observer": "^9.16.0",
|
package/src/components/Chat.tsx
CHANGED
|
@@ -4,74 +4,47 @@ import MessageContainer from "./messages/MessageContainer";
|
|
|
4
4
|
import { Sidebar } from "./sidebar/Sidebar";
|
|
5
5
|
import { useChatContext } from "../providers/ChatProvider";
|
|
6
6
|
|
|
7
|
-
// import MessageContainer from './components/messages/MessageContainer'
|
|
8
|
-
// import useConversation from '../../zustand/useConversation';
|
|
9
|
-
|
|
10
7
|
export const Chat = () => {
|
|
11
|
-
const {
|
|
8
|
+
const { messages, setMessages, updateMessageStatus } =
|
|
12
9
|
useChatUIStore();
|
|
13
10
|
const { socket } = useChatContext();
|
|
11
|
+
|
|
14
12
|
useEffect(() => {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
13
|
+
if (!socket) return;
|
|
14
|
+
|
|
15
|
+
const handleMessage = (event: MessageEvent) => {
|
|
16
|
+
try {
|
|
17
|
+
const data = JSON.parse(event.data);
|
|
18
|
+
|
|
19
|
+
if (data.type === "receiveMessage") {
|
|
20
|
+
setMessages([...messages, { ...data.message, status: "sent" }]);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
if (data.type === "messageDelivered") {
|
|
24
|
+
updateMessageStatus(data.messageId, "delivered");
|
|
25
|
+
}
|
|
26
|
+
} catch (error) {
|
|
27
|
+
console.error("Error parsing WebSocket message:", error);
|
|
28
|
+
}
|
|
29
|
+
};
|
|
18
30
|
|
|
19
|
-
socket.
|
|
20
|
-
updateMessageStatus(messageId, "delivered");
|
|
21
|
-
});
|
|
31
|
+
socket.addEventListener("message", handleMessage);
|
|
22
32
|
|
|
23
33
|
return () => {
|
|
24
|
-
socket.
|
|
25
|
-
socket.off("messageDelivered");
|
|
34
|
+
socket.removeEventListener("message", handleMessage);
|
|
26
35
|
};
|
|
27
|
-
}, [messages, setMessages, updateMessageStatus]);
|
|
36
|
+
}, [socket, messages, setMessages, updateMessageStatus]);
|
|
37
|
+
|
|
28
38
|
return (
|
|
29
|
-
|
|
30
|
-
<div className="container
|
|
31
|
-
<div className=
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
</div>
|
|
37
|
-
<div className="messageContainer">
|
|
38
|
-
<MessageContainer />
|
|
39
|
-
</div>
|
|
40
|
-
</>
|
|
41
|
-
) : (
|
|
42
|
-
<>
|
|
43
|
-
<div className="sidebarContainer">
|
|
44
|
-
<Sidebar />
|
|
45
|
-
</div>
|
|
46
|
-
<div className="messageContainer">
|
|
47
|
-
<MessageContainer />
|
|
48
|
-
</div>
|
|
49
|
-
</>
|
|
50
|
-
)}
|
|
39
|
+
<div className="container mx-auto mb-5">
|
|
40
|
+
<div className="grid-container">
|
|
41
|
+
<div className={`sidebarContainer`}>
|
|
42
|
+
<Sidebar />
|
|
43
|
+
</div>
|
|
44
|
+
<div className="messageContainer">
|
|
45
|
+
<MessageContainer />
|
|
51
46
|
</div>
|
|
52
47
|
</div>
|
|
53
|
-
|
|
48
|
+
</div>
|
|
54
49
|
);
|
|
55
|
-
};
|
|
56
|
-
|
|
57
|
-
// const MessageBody = () => {
|
|
58
|
-
|
|
59
|
-
// return (
|
|
60
|
-
// <><div className='flex-grow px-8 pt-8 text-left text-gray-700 overflow-y-auto'>
|
|
61
|
-
// <div className="relative mb-6 text-left">
|
|
62
|
-
// <div className="text-gray-700">
|
|
63
|
-
// <div className="absolute inset-x-0 top-0">
|
|
64
|
-
// <img src="/images/fR71TFZIDTv2jhvKsOMhC.png" alt className="float-right inline-block h-6 w-6 sm:h-12 sm:w-12 rounded-full" />
|
|
65
|
-
// </div>
|
|
66
|
-
// <div className="relative float-right mr-8 sm:mr-16 inline-block rounded-md bg-blue-700 py-3 px-4 text-white">
|
|
67
|
-
// <p className="text-sm">Hi, John</p>
|
|
68
|
-
// </div>
|
|
69
|
-
// </div>
|
|
70
|
-
// <div className="clear-both flex text-gray-700" />
|
|
71
|
-
// </div>
|
|
72
|
-
// </div><div className="relative mt-4 flex items-start border-t border-gray-300 sm:p-8 py-4 text-left text-gray-700">
|
|
73
|
-
// <input placeholder="Your Message" className="mr-4 overflow-hidden w-full flex-1 cursor-text resize-none whitespace-pre-wrap rounded-md bg-white text-sm py-2 sm:py-0 font-normal text-gray-600 opacity-70 shadow-none outline-none focus:text-gray-600 focus:opacity-100" defaultValue={""} />
|
|
74
|
-
// <button className="relative inline-flex h-10 w-auto flex-initial cursor-pointer items-center justify-center self-center rounded-md bg-blue-700 px-6 text-center align-middle text-sm font-medium text-white outline-none focus:ring-2">Send</button>
|
|
75
|
-
// </div></>
|
|
76
|
-
// );
|
|
77
|
-
// };
|
|
50
|
+
};
|
|
@@ -1,10 +1,15 @@
|
|
|
1
|
+
/* eslint-disable react-hooks/rules-of-hooks */
|
|
1
2
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
3
|
import { MessageStatus } from "../../types/type";
|
|
3
4
|
import { useChatContext } from "../../providers/ChatProvider";
|
|
4
|
-
import { useEffect, useState } from "react";
|
|
5
5
|
import { FileType } from "../common/FilePreview";
|
|
6
6
|
import { getChatConfig } from "../../Chat.config";
|
|
7
7
|
import { Path } from "../../lib/api/endpoint";
|
|
8
|
+
import { MoreHorizontal, Pencil, Trash2 } from "lucide-react"
|
|
9
|
+
import { useEditMessageMutation } from "../../hooks/mutations/useEditMessage";
|
|
10
|
+
import { useDeleteMessageMutation } from "../../hooks/mutations/useDeleteMessage"
|
|
11
|
+
import { useEffect, useRef, useState } from "react";
|
|
12
|
+
|
|
8
13
|
|
|
9
14
|
interface MessageProps {
|
|
10
15
|
message: {
|
|
@@ -22,17 +27,72 @@ interface MessageProps {
|
|
|
22
27
|
uploadError: string | null;
|
|
23
28
|
}[];
|
|
24
29
|
isUploading?: boolean;
|
|
30
|
+
isEdited?: boolean
|
|
31
|
+
isDeleted?: boolean
|
|
32
|
+
onEdit?: (messageId: string, newMessage: string) => void
|
|
33
|
+
onDelete?: (messageId: string) => void
|
|
34
|
+
type?: 'user' | 'system' | 'system-completion';
|
|
35
|
+
meta?: {
|
|
36
|
+
bookingDetails?: {
|
|
37
|
+
serviceId: string;
|
|
38
|
+
date: string;
|
|
39
|
+
time: string;
|
|
40
|
+
price: number;
|
|
41
|
+
// Add other booking details as needed
|
|
42
|
+
};
|
|
43
|
+
reviewLink?: string;
|
|
44
|
+
};
|
|
25
45
|
};
|
|
26
46
|
}
|
|
27
47
|
|
|
28
48
|
const Message = ({ message }: MessageProps) => {
|
|
29
49
|
const { userId } = useChatContext();
|
|
30
50
|
const { apiUrl } = getChatConfig();
|
|
51
|
+
|
|
52
|
+
if (message.type === 'system') {
|
|
53
|
+
return (
|
|
54
|
+
<div className="system-message booking-details">
|
|
55
|
+
<h4>Booking Confirmed</h4>
|
|
56
|
+
<div className="details">
|
|
57
|
+
<p>Service: {message.meta?.bookingDetails?.serviceId}</p>
|
|
58
|
+
<p>Date: {message.meta?.bookingDetails?.date}</p>
|
|
59
|
+
<p>Time: {message.meta?.bookingDetails?.time}</p>
|
|
60
|
+
<p>Price: ${message.meta?.bookingDetails?.price}</p>
|
|
61
|
+
</div>
|
|
62
|
+
</div>
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (message.type === 'system-completion') {
|
|
67
|
+
return (
|
|
68
|
+
<div className="system-message completion-notice">
|
|
69
|
+
<p>Service completed successfully!</p>
|
|
70
|
+
<button
|
|
71
|
+
onClick={() => window.location.href = message.meta?.reviewLink || '#'}
|
|
72
|
+
className="review-button"
|
|
73
|
+
>
|
|
74
|
+
Leave a Review
|
|
75
|
+
</button>
|
|
76
|
+
</div>
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
|
|
31
82
|
const fromMe = message.senderId === userId;
|
|
32
83
|
const timestamp = fromMe ? "timestamp_outgoing" : "timestamp_incomeing";
|
|
33
84
|
const alignItems = fromMe ? "outgoing" : "incoming";
|
|
34
85
|
const [localStatus, setLocalStatus] = useState(message.status);
|
|
35
|
-
|
|
86
|
+
|
|
87
|
+
const [showOptions, setShowOptions] = useState(false)
|
|
88
|
+
const [showDeleteOption, setShowDeleteOption] = useState(false)
|
|
89
|
+
const editInputRef = useRef<HTMLInputElement>(null)
|
|
90
|
+
const optionsRef = useRef<HTMLDivElement>(null)
|
|
91
|
+
const { mutate: editMessage} = useEditMessageMutation();
|
|
92
|
+
const [editedMessage, setEditedMessage] = useState('');
|
|
93
|
+
const [isEditingMode, setIsEditingMode] = useState(false);
|
|
94
|
+
const { mutate: deleteMessage} = useDeleteMessageMutation();
|
|
95
|
+
|
|
36
96
|
|
|
37
97
|
useEffect(() => {
|
|
38
98
|
setLocalStatus(message.status);
|
|
@@ -42,7 +102,7 @@ const Message = ({ message }: MessageProps) => {
|
|
|
42
102
|
// saveAs(url, name);
|
|
43
103
|
// };
|
|
44
104
|
|
|
45
|
-
|
|
105
|
+
const [downloadingIndex, setDownloadingIndex] = useState<number | null>(null)
|
|
46
106
|
const [downloadProgress, setDownloadProgress] = useState<number>(0)
|
|
47
107
|
const [downloadController, setDownloadController] = useState<AbortController | null>(null)
|
|
48
108
|
|
|
@@ -309,15 +369,120 @@ const Message = ({ message }: MessageProps) => {
|
|
|
309
369
|
);
|
|
310
370
|
};
|
|
311
371
|
|
|
372
|
+
|
|
373
|
+
const handleEditClick = () => {
|
|
374
|
+
setIsEditingMode(true)
|
|
375
|
+
setShowOptions(false)
|
|
376
|
+
setTimeout(() => {
|
|
377
|
+
editInputRef.current?.focus()
|
|
378
|
+
}, 0)
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
const handleSaveEdit = () => {
|
|
382
|
+
if (message._id && editedMessage.trim() !== message.message) {
|
|
383
|
+
editMessage({
|
|
384
|
+
messageId: message._id ?? '',
|
|
385
|
+
userId: userId, // Using userId from useChatContext
|
|
386
|
+
newMessage: editedMessage.trim()
|
|
387
|
+
}, {
|
|
388
|
+
onSuccess: () => {
|
|
389
|
+
setIsEditingMode(false);
|
|
390
|
+
// Any additional success handling
|
|
391
|
+
},
|
|
392
|
+
onError: (error:any) => {
|
|
393
|
+
// Handle error specifically for this edit
|
|
394
|
+
console.error("Edit failed:", error);
|
|
395
|
+
}
|
|
396
|
+
});
|
|
397
|
+
} else {
|
|
398
|
+
setIsEditingMode(false);
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
const handleCancelEdit = () => {
|
|
403
|
+
setEditedMessage(message.message)
|
|
404
|
+
setIsEditingMode(false)
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
const handleKeyDown = (e: React.KeyboardEvent) => {
|
|
408
|
+
if (e.key === "Enter") {
|
|
409
|
+
handleSaveEdit()
|
|
410
|
+
} else if (e.key === "Escape") {
|
|
411
|
+
handleCancelEdit()
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
const handleDeleteClick = () => {
|
|
416
|
+
deleteMessage({
|
|
417
|
+
messageId: message._id ?? '',
|
|
418
|
+
userId: userId // Get this from your auth context
|
|
419
|
+
});
|
|
420
|
+
};
|
|
421
|
+
|
|
422
|
+
|
|
312
423
|
return (
|
|
313
424
|
<div className="chat-container">
|
|
314
425
|
<div className={`message-row ${alignItems}`}>
|
|
315
|
-
<div
|
|
316
|
-
|
|
426
|
+
<div
|
|
427
|
+
className="bubble-container"
|
|
428
|
+
onMouseEnter={() => fromMe && setShowOptions(true)}
|
|
429
|
+
onMouseLeave={() => fromMe && !showDeleteOption && setShowOptions(false)}
|
|
430
|
+
>
|
|
431
|
+
{message.isDeleted ? (
|
|
432
|
+
<div className="chat-bubble compact-bubble deleted-message">
|
|
433
|
+
<div className="message-text">This message was deleted</div>
|
|
434
|
+
</div>
|
|
435
|
+
) : (message.message || (message.media && message.media.length > 0)) && (
|
|
317
436
|
<div className="chat-bubble compact-bubble">
|
|
318
437
|
{renderMedia()}
|
|
319
|
-
{
|
|
320
|
-
<div className="message-
|
|
438
|
+
{isEditingMode ? (
|
|
439
|
+
<div className="edit-message-container">
|
|
440
|
+
<input
|
|
441
|
+
ref={editInputRef}
|
|
442
|
+
type="text"
|
|
443
|
+
value={editedMessage}
|
|
444
|
+
onChange={(e) => setEditedMessage(e.target.value)}
|
|
445
|
+
onKeyDown={handleKeyDown}
|
|
446
|
+
className="edit-message-input"
|
|
447
|
+
/>
|
|
448
|
+
<div className="edit-actions">
|
|
449
|
+
<button className="save-edit" onClick={handleSaveEdit}>
|
|
450
|
+
Save
|
|
451
|
+
</button>
|
|
452
|
+
<button className="cancel-edit" onClick={handleCancelEdit}>
|
|
453
|
+
Cancel
|
|
454
|
+
</button>
|
|
455
|
+
</div>
|
|
456
|
+
</div>
|
|
457
|
+
) : (
|
|
458
|
+
message.message && <div className="message-text">{message.message}</div>
|
|
459
|
+
)}
|
|
460
|
+
|
|
461
|
+
{/* Message options for outgoing messages */}
|
|
462
|
+
{fromMe && showOptions && !isEditingMode && !message.isDeleted && (
|
|
463
|
+
<div className="message-options">
|
|
464
|
+
<button className="message-option-btn edit-btn" onClick={handleEditClick} title="Edit">
|
|
465
|
+
<Pencil size={16} />
|
|
466
|
+
</button>
|
|
467
|
+
<div className="more-options-container" ref={optionsRef}>
|
|
468
|
+
<button
|
|
469
|
+
className="message-option-btn more-btn"
|
|
470
|
+
onClick={() => setShowDeleteOption(!showDeleteOption)}
|
|
471
|
+
title="More options"
|
|
472
|
+
>
|
|
473
|
+
<MoreHorizontal size={16} />
|
|
474
|
+
</button>
|
|
475
|
+
|
|
476
|
+
{showDeleteOption && (
|
|
477
|
+
<div className="delete-option">
|
|
478
|
+
<button className="delete-btn" onClick={handleDeleteClick}>
|
|
479
|
+
<Trash2 size={16} />
|
|
480
|
+
<span>Delete</span>
|
|
481
|
+
</button>
|
|
482
|
+
</div>
|
|
483
|
+
)}
|
|
484
|
+
</div>
|
|
485
|
+
</div>
|
|
321
486
|
)}
|
|
322
487
|
</div>
|
|
323
488
|
)}
|
|
@@ -326,6 +491,7 @@ const Message = ({ message }: MessageProps) => {
|
|
|
326
491
|
hour: "2-digit",
|
|
327
492
|
minute: "2-digit",
|
|
328
493
|
})}
|
|
494
|
+
{message.isEdited && !message.isDeleted && <span className="edited-label">edited</span>}
|
|
329
495
|
<span className="status-icon">{getStatusIcon()}</span>
|
|
330
496
|
</div>
|
|
331
497
|
</div>
|
|
@@ -1,11 +1,9 @@
|
|
|
1
|
-
import { useEffect } from "react";
|
|
2
|
-
// import useConversation from "../../zustand/useConversation";
|
|
1
|
+
import { useEffect, useState } from "react";
|
|
3
2
|
import MessageInput from "./MessageInput";
|
|
4
3
|
import Messages from "./Messages";
|
|
5
4
|
import useChatUIStore from "../../stores/Zustant";
|
|
6
5
|
import { useChatContext } from "../../providers/ChatProvider";
|
|
7
|
-
|
|
8
|
-
// import { useAuthContext } from "../../context/AuthContext";
|
|
6
|
+
import { getChatConfig } from "@pubuduth-aplicy/chat-ui";
|
|
9
7
|
|
|
10
8
|
const MessageContainer = () => {
|
|
11
9
|
const {
|
|
@@ -14,34 +12,60 @@ const MessageContainer = () => {
|
|
|
14
12
|
onlineUsers,
|
|
15
13
|
setOnlineUsers,
|
|
16
14
|
} = useChatUIStore();
|
|
17
|
-
const { socket } = useChatContext();
|
|
15
|
+
const { socket, sendMessage } = useChatContext();
|
|
16
|
+
const {role}= getChatConfig()
|
|
17
|
+
const [joinedChats, setJoinedChats] = useState<Set<string>>(new Set());
|
|
18
18
|
|
|
19
|
+
// Join chat room when conversation is selected
|
|
19
20
|
useEffect(() => {
|
|
20
|
-
if (selectedConversation?._id && socket) {
|
|
21
|
-
|
|
21
|
+
if (selectedConversation?._id && socket?.readyState === WebSocket.OPEN) {
|
|
22
|
+
const chatId = selectedConversation._id;
|
|
23
|
+
if (!joinedChats.has(chatId)) {
|
|
24
|
+
sendMessage({
|
|
25
|
+
type: "joinChat",
|
|
26
|
+
chatId: chatId,
|
|
27
|
+
});
|
|
28
|
+
setJoinedChats(new Set(joinedChats).add(chatId));
|
|
29
|
+
}
|
|
22
30
|
}
|
|
23
|
-
}, [selectedConversation?._id, socket]);
|
|
31
|
+
}, [selectedConversation?._id, socket, sendMessage, joinedChats]);
|
|
24
32
|
|
|
33
|
+
// Listen for online users updates
|
|
25
34
|
useEffect(() => {
|
|
26
35
|
if (!socket) return;
|
|
27
36
|
|
|
28
|
-
const
|
|
29
|
-
|
|
37
|
+
const handleMessage = (event: MessageEvent) => {
|
|
38
|
+
try {
|
|
39
|
+
const data = JSON.parse(event.data);
|
|
40
|
+
if (data.type === "getOnlineUsers") {
|
|
41
|
+
setOnlineUsers(data.users);
|
|
42
|
+
}
|
|
43
|
+
} catch (error) {
|
|
44
|
+
console.error("Error parsing message:", error);
|
|
45
|
+
}
|
|
30
46
|
};
|
|
31
47
|
|
|
32
|
-
socket.
|
|
48
|
+
socket.addEventListener("message", handleMessage);
|
|
33
49
|
|
|
34
50
|
return () => {
|
|
35
|
-
socket.
|
|
51
|
+
socket.removeEventListener("message", handleMessage);
|
|
36
52
|
};
|
|
37
53
|
}, [socket, setOnlineUsers]);
|
|
38
54
|
|
|
55
|
+
role === 'admin' && Array.isArray(selectedConversation?.participantDetails)
|
|
56
|
+
? selectedConversation.participantDetails[1]?.profilePic
|
|
57
|
+
: !Array.isArray(selectedConversation?.participantDetails)
|
|
58
|
+
? selectedConversation?.participantDetails?.profilePic
|
|
59
|
+
: undefined;
|
|
60
|
+
|
|
39
61
|
const isUserOnline =
|
|
40
|
-
|
|
41
|
-
|
|
62
|
+
!Array.isArray(selectedConversation?.participantDetails) &&
|
|
63
|
+
!!selectedConversation?.participantDetails?._id &&
|
|
64
|
+
onlineUsers?.includes(selectedConversation.participantDetails._id);
|
|
65
|
+
|
|
42
66
|
|
|
67
|
+
// Cleanup on unmount
|
|
43
68
|
useEffect(() => {
|
|
44
|
-
// cleanup function (unmounts)
|
|
45
69
|
return () => setSelectedConversation(null);
|
|
46
70
|
}, [setSelectedConversation]);
|
|
47
71
|
|
|
@@ -60,44 +84,34 @@ const MessageContainer = () => {
|
|
|
60
84
|
className="chatMessageContainerInnerImg"
|
|
61
85
|
alt="Profile"
|
|
62
86
|
src={
|
|
63
|
-
|
|
64
|
-
|
|
87
|
+
role === 'admin' && Array.isArray(selectedConversation?.participantDetails)
|
|
88
|
+
? selectedConversation.participantDetails[1]?.profilePic
|
|
89
|
+
: !Array.isArray(selectedConversation?.participantDetails)
|
|
90
|
+
? selectedConversation?.participantDetails?.profilePic
|
|
91
|
+
: undefined
|
|
65
92
|
}
|
|
66
93
|
/>
|
|
67
94
|
<div className="chatMessageContainerOutter">
|
|
68
95
|
<div className="chatMessageContainerOutterDiv">
|
|
69
96
|
<p className="chatMessageContainerOutterDiv_name">
|
|
70
|
-
|
|
97
|
+
{role === 'admin' && Array.isArray(selectedConversation?.participantDetails)
|
|
98
|
+
? selectedConversation.participantDetails[1]?.firstname
|
|
99
|
+
: !Array.isArray(selectedConversation?.participantDetails)
|
|
100
|
+
? selectedConversation?.participantDetails?.firstname
|
|
101
|
+
: undefined
|
|
102
|
+
}
|
|
71
103
|
</p>
|
|
72
|
-
<p className="text-sm
|
|
104
|
+
<p className="text-sm">
|
|
73
105
|
{isUserOnline ? "Online" : "Offline"}
|
|
74
106
|
</p>
|
|
75
107
|
</div>
|
|
76
108
|
</div>
|
|
77
|
-
{/* <h4 className=" inline-block py-2 text-left font-sans font-semibold normal-case">Lara Abegnale</h4> */}
|
|
78
109
|
</div>
|
|
79
110
|
</div>
|
|
80
111
|
|
|
81
|
-
{/* <div className="h-14 overflow-x-hidden">
|
|
82
|
-
<div className="top-0 h-14 px-4 py-4 w-full border-b border-gray-300 justify-start items-start gap-2 inline-flex sticky z-10">
|
|
83
|
-
<div className="grow shrink basis-0 self-stretch py-2 justify-start items-center gap-4 flex">
|
|
84
|
-
<button onClick={() => setSelectedConversation(null)} className="text-blue-500 md:hidden">
|
|
85
|
-
<CaretLeft size={25} />
|
|
86
|
-
</button>
|
|
87
|
-
<img className="w-10 h-10 rounded-circle" src={selectedConversation.profile} alt="Profile" />
|
|
88
|
-
<div className="grow shrink basis-0 flex-col justify-start items-start gap-1 inline-flex">
|
|
89
|
-
<div className="self-stretch justify-start items-center inline-flex">
|
|
90
|
-
<div className="grow shrink basis-0 text-slate-900 text-base font-semibold font-inter leading-tight">
|
|
91
|
-
{selectedConversation.username}
|
|
92
|
-
</div>
|
|
93
|
-
</div>
|
|
94
|
-
</div>
|
|
95
|
-
</div>
|
|
96
|
-
</div>
|
|
97
|
-
</div> */}
|
|
98
|
-
|
|
99
112
|
<Messages />
|
|
100
|
-
<MessageInput />
|
|
113
|
+
{role !== 'admin'&& (<MessageInput />)}
|
|
114
|
+
|
|
101
115
|
</>
|
|
102
116
|
)}
|
|
103
117
|
</div>
|
|
@@ -106,6 +120,7 @@ const MessageContainer = () => {
|
|
|
106
120
|
|
|
107
121
|
export default MessageContainer;
|
|
108
122
|
|
|
123
|
+
// EmptyInbox component remains the same
|
|
109
124
|
interface EmptyInboxProps {
|
|
110
125
|
title?: string;
|
|
111
126
|
description?: string;
|
|
@@ -198,4 +213,4 @@ const EmptyInbox: React.FC<EmptyInboxProps> = ({
|
|
|
198
213
|
<p className="text-gray-500 max-w-sm">{description}</p>
|
|
199
214
|
</div>
|
|
200
215
|
);
|
|
201
|
-
};
|
|
216
|
+
};
|