@droppii-org/chat-sdk 0.0.18 → 0.0.20
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/dist/components/chatBubble/ChatBubble.d.ts.map +1 -0
- package/dist/components/{ChatBubble.js → chatBubble/ChatBubble.js} +2 -2
- package/dist/components/conversation/DeskConversationList.d.ts +1 -2
- package/dist/components/conversation/DeskConversationList.d.ts.map +1 -1
- package/dist/components/conversation/DeskConversationList.js +107 -148
- package/dist/components/message/MessageList.d.ts.map +1 -1
- package/dist/components/message/MessageList.js +46 -14
- package/dist/constants/index.d.ts +2 -0
- package/dist/constants/index.d.ts.map +1 -0
- package/dist/constants/index.js +1 -0
- package/dist/constants/sdk.d.ts +3 -0
- package/dist/constants/sdk.d.ts.map +1 -0
- package/dist/constants/sdk.js +7 -0
- package/dist/context/ChatContext.d.ts +1 -1
- package/dist/context/ChatContext.d.ts.map +1 -1
- package/dist/context/ChatContext.js +43 -9
- package/dist/hooks/conversation/useConversation.d.ts +4 -3
- package/dist/hooks/conversation/useConversation.d.ts.map +1 -1
- package/dist/hooks/conversation/useConversation.js +32 -25
- package/dist/hooks/message/useMessage.d.ts +3 -0
- package/dist/hooks/message/useMessage.d.ts.map +1 -1
- package/dist/hooks/message/useMessage.js +38 -6
- package/dist/hooks/message/useSendMessage.d.ts +5 -2
- package/dist/hooks/message/useSendMessage.d.ts.map +1 -1
- package/dist/hooks/message/useSendMessage.js +22 -10
- package/dist/hooks/user/useAuth.d.ts.map +1 -1
- package/dist/hooks/user/useAuth.js +1 -2
- package/dist/hooks/zustand/useMessageStore.d.ts +9 -0
- package/dist/hooks/zustand/useMessageStore.d.ts.map +1 -0
- package/dist/hooks/zustand/useMessageStore.js +8 -0
- package/dist/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -3
- package/dist/screens/chatBubble/index.d.ts +10 -0
- package/dist/screens/chatBubble/index.d.ts.map +1 -0
- package/dist/screens/chatBubble/index.js +12 -0
- package/dist/screens/deskMessage/index.d.ts.map +1 -0
- package/dist/screens/deskMessage/index.js +22 -0
- package/dist/styles/global.css +1 -1
- package/dist/types/chat.d.ts +15 -1
- package/dist/types/chat.d.ts.map +1 -1
- package/dist/types/chat.js +6 -1
- package/package.json +14 -2
- package/dist/assets/openIM.wasm +0 -0
- package/dist/components/ChatBubble.d.ts.map +0 -1
- package/dist/components/chat-bubble/ChatBubble.d.ts +0 -9
- package/dist/components/chat-bubble/ChatBubble.d.ts.map +0 -1
- package/dist/components/chat-bubble/ChatBubble.js +0 -27
- package/dist/screens/desk-message/index.d.ts.map +0 -1
- package/dist/screens/desk-message/index.js +0 -14
- package/dist/styles.css +0 -1
- /package/dist/components/{ChatBubble.d.ts → chatBubble/ChatBubble.d.ts} +0 -0
- /package/dist/screens/{desk-message → deskMessage}/index.d.ts +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ChatBubble.d.ts","sourceRoot":"","sources":["../../../src/components/chatBubble/ChatBubble.tsx"],"names":[],"mappings":"AAKA,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAGtD,UAAU,eAAe;IACvB,cAAc,EAAE,MAAM,CAAC;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,WAAW,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,QAAA,MAAM,UAAU,GAAI,uDAKjB,eAAe,4CAmDjB,CAAC;AAEF,eAAe,UAAU,CAAC"}
|
|
@@ -3,8 +3,8 @@ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-run
|
|
|
3
3
|
import { useState } from "react";
|
|
4
4
|
import { FloatButton, Drawer } from "antd";
|
|
5
5
|
import { MessageOutlined, CloseOutlined } from "@ant-design/icons";
|
|
6
|
-
import MessageList from "
|
|
7
|
-
import { useConversationDetail } from "
|
|
6
|
+
import MessageList from "../message/MessageList";
|
|
7
|
+
import { useConversationDetail } from "../../hooks/conversation/useConversation";
|
|
8
8
|
const ChatBubble = ({ conversationId, sourceID, sessionType, className, }) => {
|
|
9
9
|
const { conversationDetail } = useConversationDetail({
|
|
10
10
|
sourceID,
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
interface DeskConversationListProps {
|
|
2
2
|
onConversationSelect?: (conversationId: string, threadId: string) => void;
|
|
3
|
-
selectedConversationId?: string;
|
|
4
3
|
className?: string;
|
|
5
4
|
}
|
|
6
|
-
declare const DeskConversationList: ({ onConversationSelect,
|
|
5
|
+
declare const DeskConversationList: ({ onConversationSelect, className, }: DeskConversationListProps) => import("react/jsx-runtime").JSX.Element;
|
|
7
6
|
export default DeskConversationList;
|
|
8
7
|
//# sourceMappingURL=DeskConversationList.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DeskConversationList.d.ts","sourceRoot":"","sources":["../../../src/components/conversation/DeskConversationList.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"DeskConversationList.d.ts","sourceRoot":"","sources":["../../../src/components/conversation/DeskConversationList.tsx"],"names":[],"mappings":"AAwGA,UAAU,yBAAyB;IACjC,oBAAoB,CAAC,EAAE,CAAC,cAAc,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1E,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,QAAA,MAAM,oBAAoB,GAAI,sCAG3B,yBAAyB,4CAiL3B,CAAC;AAEF,eAAe,oBAAoB,CAAC"}
|
|
@@ -1,168 +1,127 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
-
import { useState, useEffect } from "react";
|
|
3
|
+
import { useState, useEffect, useCallback } from "react";
|
|
4
4
|
import { useRouter, useSearchParams, usePathname } from "next/navigation";
|
|
5
|
+
import { Input, Avatar, Badge, Empty } from "antd";
|
|
6
|
+
import { SessionType } from "@openim/wasm-client-sdk";
|
|
5
7
|
import { useConversationList } from "../../hooks/conversation/useConversation";
|
|
6
8
|
import { Icon } from "../icon";
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
avatar: "https://i.pinimg.com/736x/55/e5/ed/55e5edbb1a5b5f6e4f3cefc98de629ca.jpg",
|
|
27
|
-
lastMessage: "Customer: hi Livechat Obefe",
|
|
28
|
-
timestamp: "27/07",
|
|
29
|
-
unreadCount: 1,
|
|
30
|
-
isOnline: true,
|
|
31
|
-
status: "slow",
|
|
32
|
-
source: "obefe",
|
|
33
|
-
},
|
|
34
|
-
{
|
|
35
|
-
id: "3",
|
|
36
|
-
threadId: "thread_003",
|
|
37
|
-
name: "Phương Huyền (phhuyen2110)",
|
|
38
|
-
username: "phhuyen2110",
|
|
39
|
-
avatar: "https://i.pinimg.com/736x/55/e5/ed/55e5edbb1a5b5f6e4f3cefc98de629ca.jpg",
|
|
40
|
-
lastMessage: "Customer: hi Livechat Obefe",
|
|
41
|
-
timestamp: "27/07",
|
|
42
|
-
unreadCount: 1,
|
|
43
|
-
isOnline: true,
|
|
44
|
-
status: "waiting",
|
|
45
|
-
source: "obefe",
|
|
46
|
-
},
|
|
47
|
-
{
|
|
48
|
-
id: "4",
|
|
49
|
-
threadId: "thread_004",
|
|
50
|
-
name: "Phương Huyền (phhuyen2110)",
|
|
51
|
-
username: "phhuyen2110",
|
|
52
|
-
avatar: "https://i.pinimg.com/736x/55/e5/ed/55e5edbb1a5b5f6e4f3cefc98de629ca.jpg",
|
|
53
|
-
lastMessage: "Customer: hi Livechat Obefe",
|
|
54
|
-
timestamp: "27/07",
|
|
55
|
-
unreadCount: 1,
|
|
56
|
-
isOnline: true,
|
|
57
|
-
status: "not_replied",
|
|
58
|
-
source: "obefe",
|
|
59
|
-
},
|
|
60
|
-
{
|
|
61
|
-
id: "5",
|
|
62
|
-
threadId: "thread_005",
|
|
63
|
-
name: "Phương Huyền (phhuyen2110)",
|
|
64
|
-
username: "phhuyen2110",
|
|
65
|
-
avatar: "https://i.pinimg.com/736x/55/e5/ed/55e5edbb1a5b5f6e4f3cefc98de629ca.jpg",
|
|
66
|
-
lastMessage: "Customer: hi Livechat Obefe",
|
|
67
|
-
timestamp: "27/07",
|
|
68
|
-
unreadCount: 1,
|
|
69
|
-
isOnline: true,
|
|
70
|
-
status: "processing",
|
|
71
|
-
source: "obefe",
|
|
72
|
-
},
|
|
73
|
-
{
|
|
74
|
-
id: "6",
|
|
75
|
-
threadId: "thread_006",
|
|
76
|
-
name: "Phương Huyền (phhuyen2110)",
|
|
77
|
-
username: "phhuyen2110",
|
|
78
|
-
avatar: "https://i.pinimg.com/736x/55/e5/ed/55e5edbb1a5b5f6e4f3cefc98de629ca.jpg",
|
|
79
|
-
lastMessage: "Customer: hi Livechat Obefe",
|
|
80
|
-
timestamp: "27/07",
|
|
81
|
-
unreadCount: 1,
|
|
82
|
-
isOnline: true,
|
|
83
|
-
status: "closed",
|
|
84
|
-
source: "obefe",
|
|
85
|
-
},
|
|
86
|
-
];
|
|
87
|
-
const getStatusIcon = (status) => {
|
|
88
|
-
switch (status) {
|
|
89
|
-
case "unassigned":
|
|
90
|
-
return {
|
|
91
|
-
icon: "user-del-o",
|
|
92
|
-
bgColor: "bg-red-100",
|
|
93
|
-
iconColor: "text-red-500",
|
|
94
|
-
};
|
|
95
|
-
case "slow":
|
|
96
|
-
return {
|
|
97
|
-
icon: "warning-square-o",
|
|
98
|
-
bgColor: "bg-orange-100",
|
|
99
|
-
iconColor: "text-orange-500",
|
|
100
|
-
};
|
|
101
|
-
case "waiting":
|
|
102
|
-
return {
|
|
103
|
-
icon: "time-circle-o",
|
|
104
|
-
bgColor: "bg-yellow-100",
|
|
105
|
-
iconColor: "text-yellow-600",
|
|
106
|
-
};
|
|
107
|
-
case "not_replied":
|
|
108
|
-
return {
|
|
109
|
-
icon: "arrow-reply-o",
|
|
110
|
-
bgColor: "bg-orange-100",
|
|
111
|
-
iconColor: "text-orange-500",
|
|
112
|
-
};
|
|
113
|
-
case "processing":
|
|
114
|
-
return {
|
|
115
|
-
icon: "play-b",
|
|
116
|
-
bgColor: "bg-blue-100",
|
|
117
|
-
iconColor: "text-blue-500",
|
|
118
|
-
};
|
|
119
|
-
case "paused":
|
|
120
|
-
return {
|
|
121
|
-
icon: "pause-b",
|
|
122
|
-
bgColor: "bg-gray-100",
|
|
123
|
-
iconColor: "text-gray-500",
|
|
124
|
-
};
|
|
125
|
-
case "closed":
|
|
126
|
-
return {
|
|
127
|
-
icon: "check-b",
|
|
128
|
-
bgColor: "bg-green-100",
|
|
129
|
-
iconColor: "text-green-500",
|
|
130
|
-
};
|
|
131
|
-
default:
|
|
132
|
-
return null;
|
|
9
|
+
import { useChatContext } from "../../context/ChatContext";
|
|
10
|
+
import useMessageStore from "../../hooks/zustand/useMessageStore";
|
|
11
|
+
import { useMessage } from "../../hooks/message/useMessage";
|
|
12
|
+
const parseLatestMessage = (latestMsg, currentUserId) => {
|
|
13
|
+
var _a;
|
|
14
|
+
if (!latestMsg)
|
|
15
|
+
return "";
|
|
16
|
+
try {
|
|
17
|
+
const msgData = JSON.parse(latestMsg);
|
|
18
|
+
// Check for text message (textElem)
|
|
19
|
+
if ((_a = msgData.textElem) === null || _a === void 0 ? void 0 : _a.content) {
|
|
20
|
+
const isMe = currentUserId && msgData.sendID === currentUserId;
|
|
21
|
+
const sender = isMe ? "Me" : (msgData === null || msgData === void 0 ? void 0 : msgData.senderNickname) || msgData.sendID;
|
|
22
|
+
return `${sender}: ${msgData.textElem.content}`;
|
|
23
|
+
}
|
|
24
|
+
// TODO: Handle other message types (fileElem, videoElem, etc.)
|
|
25
|
+
// For now, return empty string for non-text messages
|
|
26
|
+
// This can be enhanced later to show appropriate previews
|
|
27
|
+
return "Tin nhắn không khả dụng";
|
|
133
28
|
}
|
|
29
|
+
catch (error) {
|
|
30
|
+
console.error("Error parsing latest message:", error);
|
|
31
|
+
return "";
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
// Utility function to format timestamp
|
|
35
|
+
const formatTimestamp = (timestamp) => {
|
|
36
|
+
if (!timestamp)
|
|
37
|
+
return "";
|
|
38
|
+
const date = new Date(timestamp);
|
|
39
|
+
const now = new Date();
|
|
40
|
+
const diffInMs = now.getTime() - date.getTime();
|
|
41
|
+
const diffInDays = Math.floor(diffInMs / (1000 * 60 * 60 * 24));
|
|
42
|
+
if (diffInDays === 0) {
|
|
43
|
+
// Today - show time
|
|
44
|
+
return date.toLocaleTimeString("vi-VN", {
|
|
45
|
+
hour: "2-digit",
|
|
46
|
+
minute: "2-digit",
|
|
47
|
+
hour12: false,
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
else if (diffInDays === 1) {
|
|
51
|
+
// Yesterday
|
|
52
|
+
return "Hôm qua";
|
|
53
|
+
}
|
|
54
|
+
else if (diffInDays < 7) {
|
|
55
|
+
// This week - show day name
|
|
56
|
+
return date.toLocaleDateString("vi-VN", { weekday: "long" });
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
// Older - show date
|
|
60
|
+
return date.toLocaleDateString("vi-VN", {
|
|
61
|
+
day: "2-digit",
|
|
62
|
+
month: "2-digit",
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
// Transform API data to UI-friendly format
|
|
67
|
+
const transformConversationData = (apiData, currentUserId) => {
|
|
68
|
+
return apiData.map((conv) => (Object.assign(Object.assign({}, conv), { id: conv.conversationID, threadId: conv.conversationID, name: conv.showName || "Unknown User", username: conv.userID || conv.groupID || "", avatar: conv.faceURL ||
|
|
69
|
+
"https://i.pinimg.com/736x/55/e5/ed/55e5edbb1a5b5f6e4f3cefc98de629ca.jpg", lastMessage: parseLatestMessage(conv.latestMsg, currentUserId), timestamp: formatTimestamp(conv.latestMsgSendTime), unreadCount: conv.unreadCount, isOnline: true, source: conv.conversationType === 3 ? "group" : "direct" })));
|
|
134
70
|
};
|
|
135
|
-
const DeskConversationList = ({ onConversationSelect,
|
|
136
|
-
const { conversationList } = useConversationList();
|
|
71
|
+
const DeskConversationList = ({ onConversationSelect, className = "", }) => {
|
|
137
72
|
const [searchQuery, setSearchQuery] = useState("");
|
|
138
73
|
const router = useRouter();
|
|
139
74
|
const pathname = usePathname();
|
|
140
75
|
const searchParams = useSearchParams();
|
|
141
|
-
|
|
142
|
-
const
|
|
143
|
-
const
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
}
|
|
147
|
-
|
|
76
|
+
const { user } = useChatContext();
|
|
77
|
+
const selectedThreadId = useMessageStore((state) => state.selectedThreadId);
|
|
78
|
+
const setSelectedThreadId = useMessageStore((state) => state.setSelectedThreadId);
|
|
79
|
+
const setSelectedSourceId = useMessageStore((state) => state.setSelectedSourceId);
|
|
80
|
+
const { markConversationMessageAsRead } = useMessage(selectedThreadId);
|
|
81
|
+
const { conversationList } = useConversationList(selectedThreadId);
|
|
82
|
+
// Transform real conversation data from the API
|
|
83
|
+
const conversations = transformConversationData(conversationList || [], user === null || user === void 0 ? void 0 : user.userID);
|
|
148
84
|
const filteredConversations = conversations.filter((conv) => conv.name.toLowerCase().includes(searchQuery.toLowerCase()) ||
|
|
149
85
|
conv.lastMessage.toLowerCase().includes(searchQuery.toLowerCase()));
|
|
150
86
|
const handleConversationClick = (conversation) => {
|
|
151
87
|
const newSearchParams = new URLSearchParams(searchParams);
|
|
152
|
-
newSearchParams.set("threadId", conversation.
|
|
88
|
+
newSearchParams.set("threadId", conversation.id);
|
|
153
89
|
router.push(`${pathname}?${newSearchParams.toString()}`);
|
|
154
|
-
setSelectedThreadId(conversation.
|
|
155
|
-
onConversationSelect === null || onConversationSelect === void 0 ? void 0 : onConversationSelect(conversation.id, conversation.
|
|
90
|
+
setSelectedThreadId(conversation.id);
|
|
91
|
+
onConversationSelect === null || onConversationSelect === void 0 ? void 0 : onConversationSelect(conversation.id, conversation.id);
|
|
156
92
|
};
|
|
157
|
-
|
|
93
|
+
const onSetSelectedSourceId = useCallback(() => {
|
|
94
|
+
const selectedConversation = conversations.findIndex((conv) => conv.id === selectedThreadId);
|
|
95
|
+
if (selectedConversation !== -1) {
|
|
96
|
+
const conversation = conversations[selectedConversation];
|
|
97
|
+
const sourceId = conversation.conversationType === SessionType.Group
|
|
98
|
+
? conversation.groupID
|
|
99
|
+
: conversation.userID;
|
|
100
|
+
setSelectedSourceId(sourceId);
|
|
101
|
+
}
|
|
102
|
+
}, [conversationList, selectedThreadId]);
|
|
103
|
+
useEffect(() => {
|
|
104
|
+
const threadId = searchParams.get("threadId");
|
|
105
|
+
if (threadId) {
|
|
106
|
+
setSelectedThreadId(threadId);
|
|
107
|
+
}
|
|
108
|
+
else if (conversations.length > 0) {
|
|
109
|
+
setSelectedThreadId(conversations[0].id);
|
|
110
|
+
const newSearchParams = new URLSearchParams(searchParams);
|
|
111
|
+
newSearchParams.set("threadId", conversations[0].id);
|
|
112
|
+
router.replace(`${pathname}?${newSearchParams.toString()}`);
|
|
113
|
+
}
|
|
114
|
+
}, [searchParams, conversations.length]);
|
|
115
|
+
useEffect(() => {
|
|
116
|
+
if (!!selectedThreadId) {
|
|
117
|
+
markConversationMessageAsRead();
|
|
118
|
+
onSetSelectedSourceId();
|
|
119
|
+
}
|
|
120
|
+
}, [selectedThreadId, onSetSelectedSourceId, markConversationMessageAsRead]);
|
|
121
|
+
return (_jsxs("div", { className: `flex flex-col h-full bg-white border-r border-gray-200 ${className}`, children: [_jsx("div", { className: "p-3 border-b border-gray-200", children: _jsx(Input, { placeholder: "T\u00ECm ki\u1EBFm", prefix: _jsx(Icon, { icon: "search-o", size: 18, className: "text-gray-400" }), value: searchQuery, onChange: (e) => setSearchQuery(e.target.value), className: "rounded-lg" }) }), _jsxs("div", { className: "flex-1 overflow-y-auto", children: [filteredConversations.map((conversation) => (_jsxs("div", { onClick: () => handleConversationClick(conversation), className: `relative p-3 border-b border-gray-100 hover:bg-gray-50 cursor-pointer transition-colors ${selectedThreadId === conversation.threadId
|
|
158
122
|
? "bg-blue-50"
|
|
159
|
-
: "bg-white"}`, children: [selectedThreadId === conversation.threadId && (_jsx("div", { className: "absolute left-0 top-0 bottom-0 w-1 bg-blue-500" })), _jsxs("div", { className: "flex items-start gap-3", children: [
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
return null;
|
|
163
|
-
return (_jsx("div", { className: `w-5 h-5 ${statusIcon.bgColor} rounded-full flex items-center justify-center`, children: _jsx(Icon, { icon: statusIcon.icon, size: 12, className: statusIcon.iconColor }) }));
|
|
164
|
-
})()] })] })] }) })] })] }, conversation.id))), filteredConversations.length === 0 && (_jsxs("div", { className: "flex flex-col items-center justify-center py-12 text-gray-500", children: [_jsx(Icon, { icon: "chat-square-b", size: 48, className: "text-gray-300 mb-4" }), _jsx("p", { className: "text-lg font-medium mb-2", children: "Kh\u00F4ng t\u00ECm th\u1EA5y cu\u1ED9c tr\u00F2 chuy\u1EC7n" }), _jsx("p", { className: "text-sm text-center", children: searchQuery
|
|
165
|
-
? "Thử tìm kiếm với từ khóa khác"
|
|
166
|
-
: "Chưa có cuộc trò chuyện nào" })] }))] })] }));
|
|
123
|
+
: "bg-white"}`, children: [selectedThreadId === conversation.threadId && (_jsx("div", { className: "absolute left-0 top-0 bottom-0 w-1 bg-blue-500" })), _jsxs("div", { className: "flex items-start gap-3", children: [_jsx("div", { className: "relative flex-shrink-0", children: _jsx(Badge, { dot: conversation.isOnline, status: conversation.isOnline ? "success" : "default", offset: [-2, 36], children: _jsx(Avatar, { size: 48, src: conversation.avatar, alt: conversation.name }) }) }), _jsx("div", { className: "flex-1 min-w-0", children: _jsxs("div", { className: "flex items-start justify-between", children: [_jsxs("div", { className: "flex-1 min-w-0", children: [_jsx("h3", { className: "font-semibold text-gray-900 text-sm truncate", children: conversation.name }), _jsx("p", { className: "text-xs text-gray-500 truncate mt-0.5", children: conversation.lastMessage })] }), _jsxs("div", { className: "flex flex-col items-end gap-1 ml-2", children: [_jsx("span", { className: "text-xs text-gray-400", children: conversation.timestamp }), _jsx("div", { className: "flex items-center gap-1", children: conversation.unreadCount > 0 && (_jsx(Badge, { count: conversation.unreadCount })) })] })] }) })] })] }, conversation.id))), filteredConversations.length === 0 && (_jsx("div", { className: "flex items-center justify-center py-12", children: _jsx(Empty, { image: _jsx(Icon, { icon: "chat-square-b", size: 48, className: "text-gray-300" }), description: _jsxs("div", { children: [_jsx("p", { className: "text-lg font-medium mb-2 text-gray-500", children: "Kh\u00F4ng t\u00ECm th\u1EA5y cu\u1ED9c tr\u00F2 chuy\u1EC7n" }), _jsx("p", { className: "text-sm text-gray-400", children: searchQuery
|
|
124
|
+
? "Thử tìm kiếm với từ khóa khác"
|
|
125
|
+
: "Chưa có cuộc trò chuyện nào" })] }) }) }))] })] }));
|
|
167
126
|
};
|
|
168
127
|
export default DeskConversationList;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MessageList.d.ts","sourceRoot":"","sources":["../../../src/components/message/MessageList.tsx"],"names":[],"mappings":"AACA,OAAO,EACL,KAAK,gBAAgB,EAGtB,MAAM,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"MessageList.d.ts","sourceRoot":"","sources":["../../../src/components/message/MessageList.tsx"],"names":[],"mappings":"AACA,OAAO,EACL,KAAK,gBAAgB,EAGtB,MAAM,yBAAyB,CAAC;AAkBjC,UAAU,gBAAgB;IACxB,cAAc,EAAE,MAAM,CAAC;IACvB,gBAAgB,EAAE,gBAAgB,GAAG,IAAI,CAAC;IAC1C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB;AAED,QAAA,MAAM,WAAW,GAAI,OAAO,gBAAgB,4CA0O3C,CAAC;AAEF,eAAe,WAAW,CAAC"}
|
|
@@ -1,4 +1,15 @@
|
|
|
1
1
|
"use client";
|
|
2
|
+
var __rest = (this && this.__rest) || function (s, e) {
|
|
3
|
+
var t = {};
|
|
4
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
5
|
+
t[p] = s[p];
|
|
6
|
+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
7
|
+
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
8
|
+
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
9
|
+
t[p[i]] = s[p[i]];
|
|
10
|
+
}
|
|
11
|
+
return t;
|
|
12
|
+
};
|
|
2
13
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
14
|
import { SessionType, } from "@openim/wasm-client-sdk";
|
|
4
15
|
import { useChatContext } from "../../context/ChatContext";
|
|
@@ -7,11 +18,14 @@ import { Avatar, Button, Input, Tooltip } from "antd";
|
|
|
7
18
|
import { Icon } from "../icon";
|
|
8
19
|
import { useCallback, useEffect, useRef, useState } from "react";
|
|
9
20
|
import clsx from "clsx";
|
|
10
|
-
import { useSendMessage } from "../../hooks/message/useSendMessage";
|
|
21
|
+
import { useSendMessage, } from "../../hooks/message/useSendMessage";
|
|
22
|
+
import InfiniteLoader from "react-window-infinite-loader";
|
|
23
|
+
import { VariableSizeList as List, } from "react-window";
|
|
24
|
+
import AutoSizer from "react-virtualized-auto-sizer";
|
|
11
25
|
const MessageList = (props) => {
|
|
12
26
|
var _a, _b;
|
|
13
27
|
const { conversationId, conversationData, onClose } = props;
|
|
14
|
-
const { messageList, refetch } = useMessage(conversationId);
|
|
28
|
+
const { messageList, groupMessages, refetch } = useMessage(conversationId);
|
|
15
29
|
const scrollRef = useRef(null);
|
|
16
30
|
const shouldScrollToBottomRef = useRef(true);
|
|
17
31
|
const lastMessageCountRef = useRef((messageList === null || messageList === void 0 ? void 0 : messageList.length) || 0);
|
|
@@ -25,6 +39,7 @@ const MessageList = (props) => {
|
|
|
25
39
|
: (conversationData === null || conversationData === void 0 ? void 0 : conversationData.groupID) || "",
|
|
26
40
|
});
|
|
27
41
|
const [textMessage, setTextMessage] = useState("");
|
|
42
|
+
const [composing, setComposing] = useState(false);
|
|
28
43
|
const [showScrollToBottomButton, setShowScrollToBottomButton] = useState(false);
|
|
29
44
|
const scrollToBottom = useCallback((force = false) => {
|
|
30
45
|
if (scrollRef.current) {
|
|
@@ -51,20 +66,27 @@ const MessageList = (props) => {
|
|
|
51
66
|
setShowScrollToBottomButton(distanceFromBottom > SCROLL_DOWN_THRESHOLD &&
|
|
52
67
|
!shouldScrollToBottomRef.current);
|
|
53
68
|
}, []);
|
|
54
|
-
const onSendTextMessage = async () => {
|
|
69
|
+
const onSendTextMessage = useCallback(async () => {
|
|
55
70
|
setTextMessage("");
|
|
56
|
-
const
|
|
71
|
+
const lastMessage = messageList === null || messageList === void 0 ? void 0 : messageList[(messageList === null || messageList === void 0 ? void 0 : messageList.length) - 1];
|
|
72
|
+
const res = await sendTextMessage(textMessage, lastMessage);
|
|
57
73
|
if (res) {
|
|
58
74
|
refetch();
|
|
59
75
|
}
|
|
60
|
-
};
|
|
61
|
-
const renderMessageItem = useCallback((
|
|
62
|
-
|
|
63
|
-
const
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
76
|
+
}, [textMessage, sendTextMessage, refetch, messageList]);
|
|
77
|
+
const renderMessageItem = useCallback((listItemProps) => {
|
|
78
|
+
const { index } = listItemProps;
|
|
79
|
+
const groupMessage = groupMessages === null || groupMessages === void 0 ? void 0 : groupMessages[index];
|
|
80
|
+
const messagesInGroup = (groupMessage === null || groupMessage === void 0 ? void 0 : groupMessage.messages) || [];
|
|
81
|
+
return (_jsxs("div", { children: [_jsx("div", { children: groupMessage === null || groupMessage === void 0 ? void 0 : groupMessage.sendTime }), messagesInGroup === null || messagesInGroup === void 0 ? void 0 : messagesInGroup.map((message) => {
|
|
82
|
+
var _a, _b, _c;
|
|
83
|
+
const isMine = (message === null || message === void 0 ? void 0 : message.sendID) === (user === null || user === void 0 ? void 0 : user.userID);
|
|
84
|
+
return (_jsx("div", { className: clsx("flex", isMine ? "justify-end" : "justify-start"), children: _jsxs("div", { className: "flex items-end gap-2", children: [!isMine && (_jsx(Avatar, { children: ((_b = (_a = message === null || message === void 0 ? void 0 : message.senderNickname) === null || _a === void 0 ? void 0 : _a.charAt) === null || _b === void 0 ? void 0 : _b.call(_a, 0)) || "A" })), _jsxs("div", { className: "flex flex-col items-start", children: [!isMine && (_jsx("span", { className: "text-xs text-gray-500 mb-1 px-3", children: message === null || message === void 0 ? void 0 : message.senderNickname })), _jsx("div", { className: clsx("px-3 py-2 sm:px-4 sm:py-2 rounded-2xl max-w-full break-words", isMine
|
|
85
|
+
? "bg-blue-500 text-white"
|
|
86
|
+
: "bg-gray-100 text-gray-900"), children: _jsx("p", { className: "text-sm sm:text-base whitespace-pre-wrap", children: ((_c = message === null || message === void 0 ? void 0 : message.textElem) === null || _c === void 0 ? void 0 : _c.content) ||
|
|
87
|
+
"Tin nhắn không khả dụng" }) })] })] }) }, message === null || message === void 0 ? void 0 : message.clientMsgID));
|
|
88
|
+
})] }));
|
|
89
|
+
}, [user === null || user === void 0 ? void 0 : user.userID, groupMessages]);
|
|
68
90
|
useEffect(() => {
|
|
69
91
|
const currentMessageCount = (messageList === null || messageList === void 0 ? void 0 : messageList.length) || 0;
|
|
70
92
|
const previousMessageCount = lastMessageCountRef.current;
|
|
@@ -82,10 +104,20 @@ const MessageList = (props) => {
|
|
|
82
104
|
}
|
|
83
105
|
lastMessageCountRef.current = currentMessageCount;
|
|
84
106
|
}, [messageList, user === null || user === void 0 ? void 0 : user.userID, scrollToBottom]);
|
|
85
|
-
return (_jsxs("div", { className: "flex flex-col flex-1 relative h-full bg-white", children: [_jsxs("div", { className: "px-4 py-3 flex items-center border-b gap-3", children: [_jsx(Avatar, { src: conversationData === null || conversationData === void 0 ? void 0 : conversationData.faceURL, children: ((_b = (_a = conversationData === null || conversationData === void 0 ? void 0 : conversationData.showName) === null || _a === void 0 ? void 0 : _a.charAt) === null || _b === void 0 ? void 0 : _b.call(_a, 0)) || "A" }), _jsxs("div", { className: "flex flex-col flex-1", children: [_jsx("p", { children: (conversationData === null || conversationData === void 0 ? void 0 : conversationData.showName) || "" }), _jsx("p", { className: "text-xs text-gray-500", children: "2 thành viên" })] }), _jsx(Button, { type: "text", shape: "circle", icon: _jsx(Icon, { icon: "align-justify-o", size: 24 }) }), !!onClose && (_jsx(Button, { type: "text", shape: "circle", icon: _jsx(Icon, { icon: "close-b", size: 24 }), onClick: onClose }))] }), _jsx("div", { className: "flex flex-col flex-1 min-h-0", children: _jsx("div", { className: "relative h-full
|
|
107
|
+
return (_jsxs("div", { className: "flex flex-col flex-1 relative h-full bg-white", children: [_jsxs("div", { className: "px-4 py-3 flex items-center border-b gap-3", children: [_jsx(Avatar, { src: conversationData === null || conversationData === void 0 ? void 0 : conversationData.faceURL, children: ((_b = (_a = conversationData === null || conversationData === void 0 ? void 0 : conversationData.showName) === null || _a === void 0 ? void 0 : _a.charAt) === null || _b === void 0 ? void 0 : _b.call(_a, 0)) || "A" }), _jsxs("div", { className: "flex flex-col flex-1", children: [_jsx("p", { children: (conversationData === null || conversationData === void 0 ? void 0 : conversationData.showName) || "" }), _jsx("p", { className: "text-xs text-gray-500", children: "2 thành viên" })] }), _jsx(Button, { type: "text", shape: "circle", icon: _jsx(Icon, { icon: "align-justify-o", size: 24 }) }), !!onClose && (_jsx(Button, { type: "text", shape: "circle", icon: _jsx(Icon, { icon: "close-b", size: 24 }), onClick: onClose }))] }), _jsx("div", { className: "flex flex-col flex-1 min-h-0", children: _jsx("div", { className: "relative h-full", children: _jsx(AutoSizer, { children: ({ height, width }) => (_jsx(InfiniteLoader, { isItemLoaded: () => true, loadMoreItems: () => { }, itemCount: (groupMessages === null || groupMessages === void 0 ? void 0 : groupMessages.length) || 0, children: (_a) => {
|
|
108
|
+
var { onItemsRendered, ref } = _a, rest = __rest(_a, ["onItemsRendered", "ref"]);
|
|
109
|
+
return (_jsx(List, Object.assign({ ref: ref }, rest, { itemCount: (groupMessages === null || groupMessages === void 0 ? void 0 : groupMessages.length) || 0, onItemsRendered: onItemsRendered, height: height, width: width, itemSize: (index) => {
|
|
110
|
+
const groupMessage = groupMessages === null || groupMessages === void 0 ? void 0 : groupMessages[index];
|
|
111
|
+
const messagesInGroup = (groupMessage === null || groupMessage === void 0 ? void 0 : groupMessage.messages) || [];
|
|
112
|
+
return (messagesInGroup === null || messagesInGroup === void 0 ? void 0 : messagesInGroup.length) * 50;
|
|
113
|
+
}, children: renderMessageItem })));
|
|
114
|
+
} })) }) }) }), _jsx("div", { className: "border-t px-4 py-3", children: _jsx("div", { className: "border rounded-lg bg-gray-50", children: _jsxs("div", { className: "px-4 py-3 flex items-center gap-4", children: [_jsx(Input, { placeholder: "Nh\u1EADp tin nh\u1EAFn", size: "small", variant: "borderless", value: textMessage, onChange: (e) => setTextMessage(e.target.value), onKeyDown: (e) => {
|
|
115
|
+
if (composing) {
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
86
118
|
if (e.key === "Enter") {
|
|
87
119
|
onSendTextMessage();
|
|
88
120
|
}
|
|
89
|
-
} }), _jsx(Tooltip, { title: "G\u1EEDi tin nh\u1EAFn", children: _jsx(Button, { type: "primary", shape: "circle", size: "middle", icon: _jsx(Icon, { icon: "send-b", color: "white", size: 16 }), disabled: textMessage.length === 0, onClick: onSendTextMessage }) })] }) }) })] }));
|
|
121
|
+
}, onCompositionStart: () => setComposing(true), onCompositionEnd: () => setComposing(false) }), _jsx(Tooltip, { title: "G\u1EEDi tin nh\u1EAFn", children: _jsx(Button, { type: "primary", shape: "circle", size: "middle", icon: _jsx(Icon, { icon: "send-b", color: "white", size: 16 }), disabled: textMessage.length === 0, onClick: onSendTextMessage }) })] }) }) })] }));
|
|
90
122
|
};
|
|
91
123
|
export default MessageList;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/constants/index.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,YAAY,0GACgF,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const coreWasmPath = "https://droppiistg.blob.core.windows.net/droppii-stg-public/3315964d-11d5-4d27-8af7-d2ec2354994f.wasm";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sdk.d.ts","sourceRoot":"","sources":["../../src/constants/sdk.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AAGjD,eAAO,MAAM,QAAQ,EAAE,UAAU,CAAC,OAAO,MAAM,CAI7C,CAAC"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ChatContextType, ChatProviderProps } from "../types/chat";
|
|
2
2
|
export declare const ChatContext: import("react").Context<ChatContextType>;
|
|
3
3
|
export declare const useChatContext: () => ChatContextType;
|
|
4
|
-
export declare const ChatProvider: ({ children, config }: ChatProviderProps) => import("react/jsx-runtime").JSX.Element;
|
|
4
|
+
export declare const ChatProvider: ({ children, config, refetchToken, }: ChatProviderProps) => import("react/jsx-runtime").JSX.Element;
|
|
5
5
|
//# sourceMappingURL=ChatContext.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ChatContext.d.ts","sourceRoot":"","sources":["../../src/context/ChatContext.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ChatContext.d.ts","sourceRoot":"","sources":["../../src/context/ChatContext.tsx"],"names":[],"mappings":"AAIA,OAAO,EACL,eAAe,EACf,iBAAiB,EAElB,MAAM,eAAe,CAAC;AAGvB,eAAO,MAAM,WAAW,0CAGtB,CAAC;AAEH,eAAO,MAAM,cAAc,uBAAgC,CAAC;AAE5D,eAAO,MAAM,YAAY,GAAI,qCAI1B,iBAAiB,4CAyEnB,CAAC"}
|
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
3
|
import { createContext, useContext, useEffect, useState } from "react";
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
|
|
4
|
+
import { CbEvents } from "@openim/wasm-client-sdk";
|
|
5
|
+
import { ConnectStatus, } from "../types/chat";
|
|
6
|
+
import { DChatSDK } from "../constants/sdk";
|
|
7
7
|
export const ChatContext = createContext({
|
|
8
8
|
user: null,
|
|
9
|
+
connectStatus: ConnectStatus.Disconnected,
|
|
9
10
|
});
|
|
10
11
|
export const useChatContext = () => useContext(ChatContext);
|
|
11
|
-
export const ChatProvider = ({ children, config }) => {
|
|
12
|
-
const [
|
|
12
|
+
export const ChatProvider = ({ children, config, refetchToken, }) => {
|
|
13
|
+
const [connectStatus, setConnectStatus] = useState(ConnectStatus.Disconnected);
|
|
13
14
|
const [user, setUser] = useState(null);
|
|
14
15
|
const getUserInfo = () => {
|
|
15
16
|
DChatSDK.getSelfUserInfo()
|
|
@@ -20,11 +21,10 @@ export const ChatProvider = ({ children, config }) => {
|
|
|
20
21
|
console.log("getSelfUserInfo", errCode, errMsg);
|
|
21
22
|
});
|
|
22
23
|
};
|
|
23
|
-
const handleLogin = () => {
|
|
24
|
-
DChatSDK.login(config)
|
|
24
|
+
const handleLogin = (newToken) => {
|
|
25
|
+
DChatSDK.login(Object.assign(Object.assign({}, config), { token: newToken || config.token }))
|
|
25
26
|
.then((res) => {
|
|
26
27
|
getUserInfo();
|
|
27
|
-
setLoading(false);
|
|
28
28
|
})
|
|
29
29
|
.catch(({ errCode, errMsg }) => {
|
|
30
30
|
console.log("handleLogin", errCode, errMsg);
|
|
@@ -33,5 +33,39 @@ export const ChatProvider = ({ children, config }) => {
|
|
|
33
33
|
useEffect(() => {
|
|
34
34
|
handleLogin();
|
|
35
35
|
}, [config]);
|
|
36
|
-
|
|
36
|
+
useEffect(() => {
|
|
37
|
+
DChatSDK.on(CbEvents.OnUserTokenExpired, () => {
|
|
38
|
+
console.log("OnUserTokenExpired");
|
|
39
|
+
refetchToken().then((token) => {
|
|
40
|
+
if (!!token) {
|
|
41
|
+
handleLogin(token);
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
DChatSDK.on(CbEvents.OnUserTokenInvalid, () => {
|
|
46
|
+
console.log("OnUserTokenInvalid");
|
|
47
|
+
refetchToken().then((token) => {
|
|
48
|
+
if (!!token) {
|
|
49
|
+
handleLogin(token);
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
DChatSDK.on(CbEvents.OnConnectSuccess, () => {
|
|
54
|
+
setConnectStatus(ConnectStatus.Connected);
|
|
55
|
+
});
|
|
56
|
+
DChatSDK.on(CbEvents.OnConnecting, () => {
|
|
57
|
+
setConnectStatus(ConnectStatus.Connecting);
|
|
58
|
+
});
|
|
59
|
+
DChatSDK.on(CbEvents.OnConnectFailed, () => {
|
|
60
|
+
setConnectStatus(ConnectStatus.Disconnected);
|
|
61
|
+
});
|
|
62
|
+
return () => {
|
|
63
|
+
DChatSDK.off(CbEvents.OnUserTokenExpired, () => { });
|
|
64
|
+
DChatSDK.off(CbEvents.OnUserTokenInvalid, () => { });
|
|
65
|
+
DChatSDK.off(CbEvents.OnConnectSuccess, () => { });
|
|
66
|
+
DChatSDK.off(CbEvents.OnConnectFailed, () => { });
|
|
67
|
+
DChatSDK.off(CbEvents.OnConnecting, () => { });
|
|
68
|
+
};
|
|
69
|
+
}, [refetchToken]);
|
|
70
|
+
return (_jsx(ChatContext.Provider, { value: { user, connectStatus }, children: children }));
|
|
37
71
|
};
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import { ConversationItem, SessionType } from
|
|
2
|
-
export declare const useConversationList: () => {
|
|
1
|
+
import { ConversationItem, SessionType } from "@openim/wasm-client-sdk";
|
|
2
|
+
export declare const useConversationList: (selectedThreadId?: string) => {
|
|
3
3
|
conversationList: ConversationItem[];
|
|
4
|
+
getAllConversationList: () => Promise<void>;
|
|
4
5
|
};
|
|
5
|
-
export declare const useConversationDetail: ({ sourceID, sessionType }: {
|
|
6
|
+
export declare const useConversationDetail: ({ sourceID, sessionType, }: {
|
|
6
7
|
sourceID: string;
|
|
7
8
|
sessionType: SessionType;
|
|
8
9
|
}) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useConversation.d.ts","sourceRoot":"","sources":["../../../src/hooks/conversation/useConversation.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"useConversation.d.ts","sourceRoot":"","sources":["../../../src/hooks/conversation/useConversation.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,gBAAgB,EAChB,WAAW,EAEZ,MAAM,yBAAyB,CAAC;AAIjC,eAAO,MAAM,mBAAmB,GAAI,mBAAmB,MAAM;;;CA0C5D,CAAC;AAEF,eAAO,MAAM,qBAAqB,GAAI,4BAGnC;IACD,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,WAAW,CAAC;CAC1B;;CAuBA,CAAC"}
|