@pubuduth-aplicy/chat-ui 2.1.77 → 2.1.79
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/Chat.config.ts +1 -1
- package/src/components/Chat.tsx +7 -3
- package/src/components/messages/MessageContainer.tsx +13 -11
- package/src/components/messages/MessageInput.tsx +4 -0
- package/src/components/sidebar/Conversation.tsx +1 -1
- package/src/declarations.d.ts +1 -0
- package/src/providers/ChatProvider.tsx +4 -3
- package/src/service/messageService.ts +7 -1
- package/src/service/sidebarApi.ts +1 -1
- package/src/style/style.css +194 -11
package/package.json
CHANGED
package/src/Chat.config.ts
CHANGED
package/src/components/Chat.tsx
CHANGED
|
@@ -5,7 +5,7 @@ import { Sidebar } from "./sidebar/Sidebar";
|
|
|
5
5
|
import { useChatContext } from "../providers/ChatProvider";
|
|
6
6
|
|
|
7
7
|
export const Chat = () => {
|
|
8
|
-
const { setMessages, updateMessageStatus } = useChatUIStore();
|
|
8
|
+
const { setMessages, selectedConversation, updateMessageStatus } = useChatUIStore();
|
|
9
9
|
|
|
10
10
|
const { socket, sendMessage } = useChatContext();
|
|
11
11
|
|
|
@@ -44,10 +44,14 @@ export const Chat = () => {
|
|
|
44
44
|
return (
|
|
45
45
|
<div className="container mx-auto mb-5">
|
|
46
46
|
<div className="grid-container">
|
|
47
|
-
<div className={`sidebarContainer dark:bg-gray-800
|
|
47
|
+
<div className={`sidebarContainer dark:bg-gray-800 ${
|
|
48
|
+
selectedConversation ? "mobile-hidden" : "mobile-visible"
|
|
49
|
+
}`}>
|
|
48
50
|
<Sidebar />
|
|
49
51
|
</div>
|
|
50
|
-
<div className=
|
|
52
|
+
<div className={`messageContainer ${
|
|
53
|
+
selectedConversation ? "mobile-visible" : "mobile-hidden"
|
|
54
|
+
}`}>
|
|
51
55
|
<MessageContainer />
|
|
52
56
|
</div>
|
|
53
57
|
</div>
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
-
import { MessageSquare } from "lucide-react";
|
|
2
|
+
import { ChevronLeft, MessageSquare } from "lucide-react";
|
|
3
|
+
import { FiArrowLeft } from "react-icons/fi";
|
|
3
4
|
import { useEffect } from "react";
|
|
4
5
|
import MessageInput from "./MessageInput";
|
|
5
6
|
import Messages from "./Messages";
|
|
@@ -22,7 +23,7 @@ const MessageContainer = () => {
|
|
|
22
23
|
event: "joinChat",
|
|
23
24
|
data: {
|
|
24
25
|
chatId: selectedConversation._id,
|
|
25
|
-
userId: userId
|
|
26
|
+
userId: userId,
|
|
26
27
|
},
|
|
27
28
|
})
|
|
28
29
|
);
|
|
@@ -53,20 +54,18 @@ const MessageContainer = () => {
|
|
|
53
54
|
|
|
54
55
|
// Listen for online users updates
|
|
55
56
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
57
|
+
const participantDetails = Array.isArray(
|
|
58
|
+
selectedConversation?.participantDetails
|
|
59
|
+
)
|
|
59
60
|
? selectedConversation?.participantDetails
|
|
60
61
|
: [selectedConversation?.participantDetails].filter(Boolean);
|
|
61
62
|
|
|
62
|
-
const participant = participantDetails.find(
|
|
63
|
-
(p: any) => p._id !== userId
|
|
64
|
-
);
|
|
63
|
+
const participant = participantDetails.find((p: any) => p._id !== userId);
|
|
65
64
|
|
|
66
65
|
// const participant = selectedConversation?.participantDetails?.find(
|
|
67
66
|
// (p: any) => p._id !== userId
|
|
68
67
|
// );
|
|
69
|
-
|
|
68
|
+
|
|
70
69
|
const isOnline = isUserOnline(participant?._id || "");
|
|
71
70
|
|
|
72
71
|
// Cleanup on unmount
|
|
@@ -82,8 +81,11 @@ const MessageContainer = () => {
|
|
|
82
81
|
<>
|
|
83
82
|
<div className="chatMessageContainerInner">
|
|
84
83
|
<div className="chatMessageContainerInnerDiv">
|
|
85
|
-
<button
|
|
86
|
-
|
|
84
|
+
<button
|
|
85
|
+
className="backButton"
|
|
86
|
+
onClick={() => setSelectedConversation(null)}
|
|
87
|
+
>
|
|
88
|
+
<ChevronLeft size={20} />
|
|
87
89
|
</button>
|
|
88
90
|
{selectedConversation.type === "service" ? (
|
|
89
91
|
<div className="w-10 h-10 rounded-full bg-gray-200 flex items-center justify-center">
|
|
@@ -7,6 +7,7 @@ import { FilePreview, FileType } from "../common/FilePreview";
|
|
|
7
7
|
import { getApiClient } from "../../lib/api/apiClient";
|
|
8
8
|
import { MessageStatus } from "../../types/type";
|
|
9
9
|
import { Path } from "../../lib/api/endpoint";
|
|
10
|
+
import { getChatConfig } from "../../Chat.config";
|
|
10
11
|
|
|
11
12
|
const MAX_FILE_SIZE_MB = 5;
|
|
12
13
|
const MAX_FILE_COUNT = 5;
|
|
@@ -37,6 +38,7 @@ interface Attachment {
|
|
|
37
38
|
|
|
38
39
|
const MessageInput = () => {
|
|
39
40
|
const apiClient = getApiClient();
|
|
41
|
+
const {role} = getChatConfig();
|
|
40
42
|
const { socket, sendMessage, userId } = useChatContext();
|
|
41
43
|
const { selectedConversation, setMessages } = useChatUIStore();
|
|
42
44
|
const [message, setMessage] = useState("");
|
|
@@ -349,6 +351,8 @@ const MessageInput = () => {
|
|
|
349
351
|
selectedConversation?.type === "service"
|
|
350
352
|
? selectedConversation?.serviceId
|
|
351
353
|
: undefined,
|
|
354
|
+
senderRole: role,
|
|
355
|
+
receiverRole: role === 'customer' ? 'provider' : 'customer',
|
|
352
356
|
},
|
|
353
357
|
{
|
|
354
358
|
onSuccess: (data) => {
|
|
@@ -116,7 +116,7 @@ const Conversation = ({ conversation }: ConversationProps) => {
|
|
|
116
116
|
</p>
|
|
117
117
|
<div className="flex items-center gap-2">
|
|
118
118
|
{unreadCount > 0 && (
|
|
119
|
-
|
|
119
|
+
<span className="background text-white text-xs rounded-full h-5 w-5 flex items-center justify-center">
|
|
120
120
|
{unreadCount}
|
|
121
121
|
</span>
|
|
122
122
|
)}
|
package/src/declarations.d.ts
CHANGED
|
@@ -41,7 +41,7 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({
|
|
|
41
41
|
const reconnectAttempts = useRef(0);
|
|
42
42
|
const maxReconnectAttempts = 5;
|
|
43
43
|
const reconnectInterval = 5000; // 5 seconds
|
|
44
|
-
const { webSocketUrl } = getChatConfig();
|
|
44
|
+
const { webSocketUrl,role } = getChatConfig();
|
|
45
45
|
|
|
46
46
|
const connectWebSocket = useCallback(() => {
|
|
47
47
|
// console.log("🔌 Creating new WebSocket connection...");
|
|
@@ -49,7 +49,7 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({
|
|
|
49
49
|
// Convert HTTP URL to WebSocket URL
|
|
50
50
|
const wsUrl = webSocketUrl.replace(/^http:/, "ws:").replace(/^https:/, "wss:");
|
|
51
51
|
const socketInstance = new WebSocket(
|
|
52
|
-
`${wsUrl}?userId=${encodeURIComponent(userId)}`
|
|
52
|
+
`${wsUrl}?userId=${encodeURIComponent(userId)}&role=${encodeURIComponent(role)}`
|
|
53
53
|
);
|
|
54
54
|
|
|
55
55
|
socketInstance.onopen = () => {
|
|
@@ -62,6 +62,7 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({
|
|
|
62
62
|
JSON.stringify({
|
|
63
63
|
event: "handshake",
|
|
64
64
|
userId: userId,
|
|
65
|
+
role: role,
|
|
65
66
|
})
|
|
66
67
|
);
|
|
67
68
|
};
|
|
@@ -86,7 +87,7 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({
|
|
|
86
87
|
console.error("❌ WebSocket error:", error);
|
|
87
88
|
};
|
|
88
89
|
|
|
89
|
-
socketInstance.onclose = (
|
|
90
|
+
socketInstance.onclose = () => {
|
|
90
91
|
// console.log("🔌 WebSocket connection closed", event);
|
|
91
92
|
// console.log("❌ WebSocket disconnected:", event.code, event.reason);
|
|
92
93
|
setIsConnected(false);
|
|
@@ -12,6 +12,8 @@ export const sendMessage = async (params: {
|
|
|
12
12
|
serviceTitle?: string;
|
|
13
13
|
type?: "personal" | "service";
|
|
14
14
|
serviceId?: string;
|
|
15
|
+
senderRole?: string;
|
|
16
|
+
receiverRole?: string;
|
|
15
17
|
}) => {
|
|
16
18
|
const {
|
|
17
19
|
receiverId,
|
|
@@ -22,6 +24,8 @@ export const sendMessage = async (params: {
|
|
|
22
24
|
serviceTitle,
|
|
23
25
|
type,
|
|
24
26
|
serviceId,
|
|
27
|
+
senderRole,
|
|
28
|
+
receiverRole,
|
|
25
29
|
} = params;
|
|
26
30
|
const apiClient = getApiClient();
|
|
27
31
|
|
|
@@ -34,7 +38,9 @@ export const sendMessage = async (params: {
|
|
|
34
38
|
serviceTitle,
|
|
35
39
|
type,
|
|
36
40
|
serviceId,
|
|
37
|
-
messageType: "user"
|
|
41
|
+
messageType: "user",
|
|
42
|
+
senderRole,
|
|
43
|
+
receiverRole
|
|
38
44
|
}
|
|
39
45
|
);
|
|
40
46
|
return response.data;
|
|
@@ -12,7 +12,7 @@ export const getAllConversationData = async (userid: string) => {
|
|
|
12
12
|
|
|
13
13
|
const endpoint = role === 'admin'
|
|
14
14
|
? `${Path.getConversationListByAdmin}`
|
|
15
|
-
: `${Path.getconversation}/${userid}`;
|
|
15
|
+
: `${Path.getconversation}/${userid}/${role}`;
|
|
16
16
|
|
|
17
17
|
const res = await apiClient.get<ApiResponse>(endpoint);
|
|
18
18
|
if (res.data) {
|
package/src/style/style.css
CHANGED
|
@@ -9,12 +9,14 @@
|
|
|
9
9
|
/* background-color: #9CA3AF; */
|
|
10
10
|
--bg-opacity: 0;
|
|
11
11
|
backdrop-blur: blur(16px);
|
|
12
|
+
|
|
13
|
+
|
|
12
14
|
}
|
|
13
15
|
|
|
14
16
|
.sidebarContainer {
|
|
15
17
|
/* grid-column: span 3; */
|
|
16
18
|
/* overflow-y: auto; */
|
|
17
|
-
border: 1px solid #ddd;
|
|
19
|
+
/* border: 1px solid #ddd; */
|
|
18
20
|
max-height: 100vh;
|
|
19
21
|
}
|
|
20
22
|
|
|
@@ -23,6 +25,29 @@
|
|
|
23
25
|
/* border: 1px solid; */
|
|
24
26
|
max-height: 100vh;
|
|
25
27
|
overflow-y: auto;
|
|
28
|
+
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.sidebarContainer,
|
|
32
|
+
.messageContainer {
|
|
33
|
+
height: 100%;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
.hide-on-mobile {
|
|
37
|
+
display: none;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
.show {
|
|
41
|
+
display: block;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/* Back button visible only on mobile */
|
|
45
|
+
.back-button {
|
|
46
|
+
display: none;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
.background {
|
|
50
|
+
background-color: #317490;
|
|
26
51
|
}
|
|
27
52
|
|
|
28
53
|
.chatSidebarMain {
|
|
@@ -58,7 +83,7 @@
|
|
|
58
83
|
justify-content: flex-start;
|
|
59
84
|
align-items: center;
|
|
60
85
|
height: 2.5rem;
|
|
61
|
-
background-color:
|
|
86
|
+
background-color: #FEFEFF;
|
|
62
87
|
/* Move bg color here */
|
|
63
88
|
}
|
|
64
89
|
|
|
@@ -167,6 +192,7 @@
|
|
|
167
192
|
flex-direction: column;
|
|
168
193
|
justify-content: center;
|
|
169
194
|
height: 100%;
|
|
195
|
+
background-color: #FEFEFF;
|
|
170
196
|
}
|
|
171
197
|
|
|
172
198
|
.chatMessageContainerInner {
|
|
@@ -379,7 +405,7 @@
|
|
|
379
405
|
}
|
|
380
406
|
|
|
381
407
|
.chatMessageInputSubmit {
|
|
382
|
-
background-color: #
|
|
408
|
+
background-color: #317490;
|
|
383
409
|
border: none;
|
|
384
410
|
width: 40px;
|
|
385
411
|
height: 40px;
|
|
@@ -412,6 +438,8 @@
|
|
|
412
438
|
width: 100%;
|
|
413
439
|
font-family: Arial, sans-serif;
|
|
414
440
|
margin-bottom: 8px;
|
|
441
|
+
margin: 0 auto;
|
|
442
|
+
max-width: 1200px;
|
|
415
443
|
}
|
|
416
444
|
|
|
417
445
|
.message-row {
|
|
@@ -468,14 +496,14 @@
|
|
|
468
496
|
}
|
|
469
497
|
|
|
470
498
|
.outgoing .chat-bubble {
|
|
471
|
-
background-color: #
|
|
472
|
-
color: #
|
|
499
|
+
background-color: #317490;
|
|
500
|
+
color: #DDE8ED;
|
|
473
501
|
|
|
474
502
|
}
|
|
475
503
|
|
|
476
504
|
.incoming .chat-bubble {
|
|
477
|
-
background-color: #
|
|
478
|
-
color: #
|
|
505
|
+
background-color: #F4F3F6;
|
|
506
|
+
color: #476179;
|
|
479
507
|
}
|
|
480
508
|
|
|
481
509
|
.timestamp_incomeing {
|
|
@@ -551,15 +579,15 @@
|
|
|
551
579
|
.sidebarContainer {
|
|
552
580
|
/* display: grid; */
|
|
553
581
|
grid-column: span 3;
|
|
554
|
-
background-color:
|
|
555
|
-
border-radius:
|
|
582
|
+
background-color: #FEFEFF;
|
|
583
|
+
border-radius: 2%;
|
|
556
584
|
}
|
|
557
585
|
|
|
558
586
|
.messageContainer {
|
|
559
587
|
display: grid;
|
|
560
588
|
grid-column: span 6;
|
|
561
|
-
border: 1px solid #ddd;
|
|
562
|
-
border-radius:
|
|
589
|
+
/* border: 1px solid #ddd; */
|
|
590
|
+
border-radius: 3%;
|
|
563
591
|
}
|
|
564
592
|
|
|
565
593
|
.chatMessageContainerInnerDiv_button {
|
|
@@ -1905,4 +1933,159 @@
|
|
|
1905
1933
|
|
|
1906
1934
|
.message-option-btn.disabled:hover::before {
|
|
1907
1935
|
background: #666;
|
|
1936
|
+
}
|
|
1937
|
+
|
|
1938
|
+
.backButton {
|
|
1939
|
+
display: none;
|
|
1940
|
+
align-items: center;
|
|
1941
|
+
gap: 4px;
|
|
1942
|
+
}
|
|
1943
|
+
|
|
1944
|
+
|
|
1945
|
+
@media (max-width: 768px) {
|
|
1946
|
+
.grid-container {
|
|
1947
|
+
display: flex;
|
|
1948
|
+
flex-direction: column;
|
|
1949
|
+
width: 100%;
|
|
1950
|
+
}
|
|
1951
|
+
|
|
1952
|
+
.sidebarContainer {
|
|
1953
|
+
max-height: auto;
|
|
1954
|
+
order: 1;
|
|
1955
|
+
}
|
|
1956
|
+
|
|
1957
|
+
.messageContainer {
|
|
1958
|
+
max-height: auto;
|
|
1959
|
+
order: 2;
|
|
1960
|
+
}
|
|
1961
|
+
|
|
1962
|
+
.chatSidebarSearchbar {
|
|
1963
|
+
padding: 1rem;
|
|
1964
|
+
flex-wrap: wrap;
|
|
1965
|
+
height: auto;
|
|
1966
|
+
}
|
|
1967
|
+
|
|
1968
|
+
.chatMessagesBubble_inner {
|
|
1969
|
+
max-width: 70%; /* allow wider bubbles on small screens */
|
|
1970
|
+
}
|
|
1971
|
+
}
|
|
1972
|
+
|
|
1973
|
+
/* Mobile Layout (≤ 480px) */
|
|
1974
|
+
@media (max-width: 480px) {
|
|
1975
|
+
.grid-container {
|
|
1976
|
+
flex-direction: column;
|
|
1977
|
+
width: 100%;
|
|
1978
|
+
}
|
|
1979
|
+
|
|
1980
|
+
.chatSidebarMain {
|
|
1981
|
+
flex-direction: column;
|
|
1982
|
+
padding: 0.5rem;
|
|
1983
|
+
}
|
|
1984
|
+
|
|
1985
|
+
.chatSidebarSearchbarContainer {
|
|
1986
|
+
padding: 0.5rem;
|
|
1987
|
+
font-size: 0.9rem;
|
|
1988
|
+
}
|
|
1989
|
+
|
|
1990
|
+
.chatMessageContainerInner {
|
|
1991
|
+
padding: 1rem;
|
|
1992
|
+
font-size: 0.8rem;
|
|
1993
|
+
}
|
|
1994
|
+
|
|
1995
|
+
.chatMessagesBubble_inner {
|
|
1996
|
+
max-width: 85%;
|
|
1997
|
+
font-size: 13px;
|
|
1998
|
+
}
|
|
1999
|
+
|
|
2000
|
+
.chatMessageInput {
|
|
2001
|
+
font-size: 0.9rem;
|
|
2002
|
+
padding: 6px 4px;
|
|
2003
|
+
}
|
|
2004
|
+
|
|
2005
|
+
.chatMessageInputSubmit {
|
|
2006
|
+
width: 35px;
|
|
2007
|
+
height: 35px;
|
|
2008
|
+
}
|
|
2009
|
+
|
|
2010
|
+
.chat-bubble {
|
|
2011
|
+
font-size: 13px;
|
|
2012
|
+
max-width: 90%;
|
|
2013
|
+
}
|
|
2014
|
+
|
|
2015
|
+
.timestamp_incomeing,
|
|
2016
|
+
.timestamp_outgoing {
|
|
2017
|
+
font-size: 10px;
|
|
2018
|
+
}
|
|
2019
|
+
|
|
2020
|
+
.attachments-preview {
|
|
2021
|
+
width: 100%;
|
|
2022
|
+
}
|
|
2023
|
+
|
|
2024
|
+
}
|
|
2025
|
+
|
|
2026
|
+
/* Mobile styles */
|
|
2027
|
+
@media (max-width: 768px) {
|
|
2028
|
+
.grid-container {
|
|
2029
|
+
display: block;
|
|
2030
|
+
}
|
|
2031
|
+
|
|
2032
|
+
.chatMessageContainer {
|
|
2033
|
+
display: flex;
|
|
2034
|
+
flex-direction: column;
|
|
2035
|
+
justify-content: center;
|
|
2036
|
+
height: 100%;
|
|
2037
|
+
background-color: #FEFEFF;
|
|
2038
|
+
width: 100%;
|
|
2039
|
+
}
|
|
2040
|
+
|
|
2041
|
+
.sidebarContainer,
|
|
2042
|
+
.messageContainer {
|
|
2043
|
+
width: 100%;
|
|
2044
|
+
}
|
|
2045
|
+
|
|
2046
|
+
.back-button {
|
|
2047
|
+
display: block;
|
|
2048
|
+
}
|
|
2049
|
+
.messageContainer.active {
|
|
2050
|
+
display: block;
|
|
2051
|
+
}
|
|
2052
|
+
|
|
2053
|
+
.sidebarContainer.hidden {
|
|
2054
|
+
display: none;
|
|
2055
|
+
}
|
|
2056
|
+
|
|
2057
|
+
.backButton {
|
|
2058
|
+
display: inline-block;
|
|
2059
|
+
margin-right: 10px;
|
|
2060
|
+
background: none;
|
|
2061
|
+
border: none;
|
|
2062
|
+
font-size: 14px;
|
|
2063
|
+
cursor: pointer;
|
|
2064
|
+
}
|
|
2065
|
+
|
|
2066
|
+
.mobile-hidden {
|
|
2067
|
+
display: none !important;
|
|
2068
|
+
}
|
|
2069
|
+
.mobile-visible {
|
|
2070
|
+
display: block !important;
|
|
2071
|
+
}
|
|
2072
|
+
|
|
2073
|
+
.chatMessageInputform{
|
|
2074
|
+
padding-left: 0rem;
|
|
2075
|
+
}
|
|
2076
|
+
|
|
2077
|
+
.message-input-container{
|
|
2078
|
+
padding: 0px;
|
|
2079
|
+
}
|
|
2080
|
+
|
|
2081
|
+
.media-item{
|
|
2082
|
+
width: 100%;
|
|
2083
|
+
}
|
|
2084
|
+
|
|
2085
|
+
.chatMessageInputSubmit {
|
|
2086
|
+
/* width: 25px; */
|
|
2087
|
+
height: 35px;
|
|
2088
|
+
}
|
|
2089
|
+
|
|
2090
|
+
|
|
1908
2091
|
}
|