@droppii-org/chat-sdk 0.0.29 → 0.0.31
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/assets/conversationBg.png +0 -0
- package/dist/assets/images/conversationBg.png +0 -0
- package/dist/assets/images/imageFailed.png +0 -0
- package/dist/assets/sdk/sql-wasm.wasm +0 -0
- package/dist/assets/sdk/version +1 -0
- package/dist/assets/sdk/wasm_exec.js +575 -0
- package/dist/assets/svg/document.d.ts +2 -0
- package/dist/assets/svg/document.d.ts.map +1 -0
- package/dist/assets/svg/document.js +2 -0
- package/dist/assets/svg/document.tsx +37 -0
- package/dist/assets/svg/index.d.ts +2 -0
- package/dist/assets/svg/index.d.ts.map +1 -0
- package/dist/assets/svg/index.js +1 -0
- package/dist/assets/svg/index.ts +1 -0
- package/dist/components/chatBubble/ChatBubble.d.ts.map +1 -1
- package/dist/components/chatBubble/ChatBubble.js +6 -11
- package/dist/components/conversation/ConversationItemList.d.ts +7 -0
- package/dist/components/conversation/ConversationItemList.d.ts.map +1 -0
- package/dist/components/conversation/ConversationItemList.js +20 -0
- package/dist/components/conversation/DeskConversationList.d.ts +1 -5
- package/dist/components/conversation/DeskConversationList.d.ts.map +1 -1
- package/dist/components/conversation/DeskConversationList.js +44 -29
- package/dist/components/mediaCollection/FileCollection.d.ts +3 -0
- package/dist/components/mediaCollection/FileCollection.d.ts.map +1 -0
- package/dist/components/mediaCollection/FileCollection.js +54 -0
- package/dist/components/mediaCollection/ImageCollection.d.ts +3 -0
- package/dist/components/mediaCollection/ImageCollection.d.ts.map +1 -0
- package/dist/components/mediaCollection/ImageCollection.js +37 -0
- package/dist/components/mediaCollection/LinkCollection.d.ts +3 -0
- package/dist/components/mediaCollection/LinkCollection.d.ts.map +1 -0
- package/dist/components/mediaCollection/LinkCollection.js +8 -0
- package/dist/components/mediaCollection/VideoCollection.d.ts +3 -0
- package/dist/components/mediaCollection/VideoCollection.d.ts.map +1 -0
- package/dist/components/mediaCollection/VideoCollection.js +53 -0
- package/dist/components/mediaCollection/index.d.ts +9 -0
- package/dist/components/mediaCollection/index.d.ts.map +1 -0
- package/dist/components/mediaCollection/index.js +54 -0
- package/dist/components/message/MessageHeader.d.ts.map +1 -1
- package/dist/components/message/MessageHeader.js +2 -1
- package/dist/components/message/MessageList.d.ts.map +1 -1
- package/dist/components/message/MessageList.js +15 -3
- package/dist/components/message/footer/FilePreview.d.ts +0 -1
- package/dist/components/message/footer/FilePreview.d.ts.map +1 -1
- package/dist/components/message/footer/FilePreview.js +4 -4
- package/dist/components/message/footer/ToolbarPlugin.js +1 -1
- package/dist/components/message/footer/index.js +1 -1
- package/dist/components/message/item/FileMessage.d.ts.map +1 -1
- package/dist/components/message/item/FileMessage.js +2 -1
- package/dist/components/message/item/ImageMessage.js +3 -3
- package/dist/components/message/item/TextMessage.js +2 -2
- package/dist/components/message/item/index.js +1 -1
- package/dist/components/session/AssignedSessionFilter.d.ts.map +1 -1
- package/dist/components/session/AssignedSessionFilter.js +20 -12
- package/dist/constants/images.d.ts +5 -0
- package/dist/constants/images.d.ts.map +1 -0
- package/dist/constants/images.js +7 -0
- package/dist/context/ChatContext.d.ts +2 -1
- package/dist/context/ChatContext.d.ts.map +1 -1
- package/dist/context/ChatContext.js +17 -24
- package/dist/hooks/collection/useMediaCollection.d.ts +229 -0
- package/dist/hooks/collection/useMediaCollection.d.ts.map +1 -0
- package/dist/hooks/collection/useMediaCollection.js +66 -0
- package/dist/hooks/common/useIsMobile.d.ts +2 -0
- package/dist/hooks/common/useIsMobile.d.ts.map +1 -0
- package/dist/hooks/common/useIsMobile.js +15 -0
- package/dist/hooks/global/useGlobalEvent.d.ts.map +1 -1
- package/dist/hooks/global/useGlobalEvent.js +55 -6
- package/dist/hooks/init/useChatToken.d.ts +2 -0
- package/dist/hooks/init/useChatToken.d.ts.map +1 -0
- package/dist/hooks/init/useChatToken.js +11 -0
- package/dist/hooks/message/useSendMessage.d.ts.map +1 -1
- package/dist/hooks/message/useSendMessage.js +31 -12
- package/dist/index.d.ts +4 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/layout/index.d.ts.map +1 -1
- package/dist/layout/index.js +2 -5
- package/dist/locales/i18n.d.ts +3 -0
- package/dist/locales/i18n.d.ts.map +1 -0
- package/dist/locales/i18n.js +16 -0
- package/dist/locales/i18n.ts +18 -0
- package/dist/locales/vi/common.json +9 -0
- package/dist/screens/chatBubble/index.d.ts.map +1 -1
- package/dist/screens/chatBubble/index.js +4 -3
- package/dist/screens/deskMessage/index.d.ts.map +1 -1
- package/dist/screens/deskMessage/index.js +3 -3
- package/dist/services/api.d.ts +2 -0
- package/dist/services/api.d.ts.map +1 -0
- package/dist/services/api.js +16 -0
- package/dist/services/query.d.ts +5 -0
- package/dist/services/query.d.ts.map +1 -0
- package/dist/services/query.js +4 -0
- package/dist/services/routes.d.ts +15 -0
- package/dist/services/routes.d.ts.map +1 -0
- package/dist/services/routes.js +14 -0
- package/dist/store/auth.d.ts +4 -0
- package/dist/store/auth.d.ts.map +1 -0
- package/dist/store/auth.js +16 -0
- package/dist/store/conversation.d.ts.map +1 -1
- package/dist/store/conversation.js +4 -1
- package/dist/styles/global.css +1 -1
- package/dist/types/chat.d.ts +10 -4
- package/dist/types/chat.d.ts.map +1 -1
- package/dist/types/dto.d.ts +35 -0
- package/dist/types/dto.d.ts.map +1 -0
- package/dist/types/dto.js +1 -0
- package/dist/utils/common.d.ts +2 -0
- package/dist/utils/common.d.ts.map +1 -0
- package/dist/utils/common.js +12 -0
- package/package.json +15 -3
|
@@ -1,23 +1,18 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
-
import {
|
|
3
|
+
import { useState } from "react";
|
|
4
4
|
import { FloatButton, Drawer, Popover } from "antd";
|
|
5
5
|
import { MessageOutlined, CloseOutlined } from "@ant-design/icons";
|
|
6
6
|
import MessageList from "../message/MessageList";
|
|
7
7
|
import useConversationStore from "../../store/conversation";
|
|
8
|
+
import { useIsMobile } from "../../hooks/common/useIsMobile";
|
|
8
9
|
const ChatBubble = ({ className }) => {
|
|
9
|
-
const
|
|
10
|
+
const isMobile = useIsMobile();
|
|
10
11
|
const selectedConversationId = useConversationStore((state) => state.selectedConversationId);
|
|
11
12
|
const [isOpen, setIsOpen] = useState(false);
|
|
12
13
|
const toggleChat = () => {
|
|
13
14
|
setIsOpen(!isOpen);
|
|
14
15
|
};
|
|
15
|
-
useEffect(() => {
|
|
16
|
-
const handleResize = () => setIsMobile(window.innerWidth < 768);
|
|
17
|
-
handleResize();
|
|
18
|
-
window.addEventListener("resize", handleResize);
|
|
19
|
-
return () => window.removeEventListener("resize", handleResize);
|
|
20
|
-
}, []);
|
|
21
16
|
if (isMobile) {
|
|
22
17
|
return (_jsxs(_Fragment, { children: [_jsx(FloatButton, { icon: isOpen ? _jsx(CloseOutlined, {}) : _jsx(MessageOutlined, {}), type: "primary", style: {
|
|
23
18
|
right: 24,
|
|
@@ -28,13 +23,13 @@ const ChatBubble = ({ className }) => {
|
|
|
28
23
|
body: { padding: 0 },
|
|
29
24
|
}, classNames: {
|
|
30
25
|
wrapper: "!z-[9999]",
|
|
31
|
-
}, children: _jsx(MessageList, { conversationId: selectedConversationId, className: "flex-1", onClose: () => setIsOpen(false) }) })] }));
|
|
26
|
+
}, width: "100%", children: _jsx(MessageList, { conversationId: selectedConversationId, className: "flex-1", onClose: () => setIsOpen(false) }) })] }));
|
|
32
27
|
}
|
|
33
|
-
return (_jsx(Popover, { placement: "topLeft", trigger: "click", content: _jsx("div", {
|
|
28
|
+
return (_jsx(Popover, { placement: "topLeft", trigger: "click", open: isOpen, onOpenChange: setIsOpen, content: _jsx("div", { className: "w-[400px] h-[600px]", children: _jsx(MessageList, { conversationId: selectedConversationId, className: "flex-1", onClose: () => setIsOpen(false) }) }), styles: { body: { padding: 0 } }, children: _jsx(FloatButton, { icon: isOpen ? _jsx(CloseOutlined, {}) : _jsx(MessageOutlined, {}), type: "primary", style: {
|
|
34
29
|
right: 24,
|
|
35
30
|
bottom: 24,
|
|
36
31
|
width: 60,
|
|
37
32
|
height: 60,
|
|
38
|
-
},
|
|
33
|
+
}, className: className }) }));
|
|
39
34
|
};
|
|
40
35
|
export default ChatBubble;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { DChatConversationItem } from "./type";
|
|
2
|
+
declare const ConversationItemList: ({ conversation, isSelected, }: {
|
|
3
|
+
conversation: DChatConversationItem;
|
|
4
|
+
isSelected: boolean;
|
|
5
|
+
}) => import("react/jsx-runtime").JSX.Element;
|
|
6
|
+
export default ConversationItemList;
|
|
7
|
+
//# sourceMappingURL=ConversationItemList.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ConversationItemList.d.ts","sourceRoot":"","sources":["../../../src/components/conversation/ConversationItemList.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAE,qBAAqB,EAAE,MAAM,QAAQ,CAAC;AAG/C,QAAA,MAAM,oBAAoB,GAAI,+BAG3B;IACD,YAAY,EAAE,qBAAqB,CAAC;IACpC,UAAU,EAAE,OAAO,CAAC;CACrB,4CA8EA,CAAC;AAEF,eAAe,oBAAoB,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Avatar, Badge } from "antd";
|
|
3
|
+
import useConversationStore from "../../store/conversation";
|
|
4
|
+
import { usePathname, useRouter, useSearchParams } from "next/navigation";
|
|
5
|
+
const ConversationItemList = ({ conversation, isSelected, }) => {
|
|
6
|
+
const router = useRouter();
|
|
7
|
+
const pathname = usePathname();
|
|
8
|
+
const searchParams = useSearchParams();
|
|
9
|
+
const setConversationData = useConversationStore((state) => state.setConversationData);
|
|
10
|
+
const setSelectedConversationId = useConversationStore((state) => state.setSelectedConversationId);
|
|
11
|
+
const handleConversationClick = (conversation) => {
|
|
12
|
+
setConversationData(conversation);
|
|
13
|
+
const newSearchParams = new URLSearchParams(searchParams);
|
|
14
|
+
newSearchParams.set("threadId", conversation.conversationID);
|
|
15
|
+
router.push(`${pathname}?${newSearchParams.toString()}`);
|
|
16
|
+
setSelectedConversationId(conversation.conversationID);
|
|
17
|
+
};
|
|
18
|
+
return (_jsxs("div", { onClick: () => handleConversationClick(conversation), className: `relative p-3 border-b border-gray-100 hover:bg-gray-50 cursor-pointer transition-colors ${isSelected ? "bg-blue-50" : "bg-white"}`, children: [isSelected && (_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: true, status: "success", offset: [-2, 36], children: _jsx(Avatar, { size: 48, src: conversation.faceURL, alt: conversation.showName, children: conversation.showName.charAt(0).toUpperCase() }) }) }), _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.showName }), _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.conversationID));
|
|
19
|
+
};
|
|
20
|
+
export default ConversationItemList;
|
|
@@ -1,7 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
onConversationSelect?: (conversationId: string, threadId: string) => void;
|
|
3
|
-
className?: string;
|
|
4
|
-
}
|
|
5
|
-
declare const DeskConversationList: ({ onConversationSelect, className, }: DeskConversationListProps) => import("react/jsx-runtime").JSX.Element;
|
|
1
|
+
declare const DeskConversationList: () => import("react/jsx-runtime").JSX.Element;
|
|
6
2
|
export default DeskConversationList;
|
|
7
3
|
//# 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":"AAsGA,QAAA,MAAM,oBAAoB,+CAqHzB,CAAC;AAEF,eAAe,oBAAoB,CAAC"}
|
|
@@ -1,26 +1,40 @@
|
|
|
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, useMemo } from "react";
|
|
4
4
|
import { useRouter, useSearchParams, usePathname } from "next/navigation";
|
|
5
|
-
import { Input,
|
|
5
|
+
import { Input, Empty } from "antd";
|
|
6
|
+
import { MessageType } from "@openim/wasm-client-sdk";
|
|
6
7
|
import { Icon } from "../icon";
|
|
7
8
|
import { useChatContext } from "../../context/ChatContext";
|
|
8
9
|
import useConversationStore from "../../store/conversation";
|
|
10
|
+
import ConversationItemList from "./ConversationItemList";
|
|
11
|
+
import { DChatSDK } from "../../constants/sdk";
|
|
9
12
|
const parseLatestMessage = (latestMsg, currentUserId) => {
|
|
10
13
|
var _a;
|
|
11
14
|
if (!latestMsg)
|
|
12
15
|
return "";
|
|
13
16
|
try {
|
|
14
17
|
const msgData = JSON.parse(latestMsg);
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
const contentType = msgData === null || msgData === void 0 ? void 0 : msgData.contentType;
|
|
19
|
+
const isMe = currentUserId && msgData.sendID === currentUserId;
|
|
20
|
+
const sender = isMe ? "Me" : (msgData === null || msgData === void 0 ? void 0 : msgData.senderNickname) || msgData.sendID;
|
|
21
|
+
switch (contentType) {
|
|
22
|
+
case MessageType.TextMessage:
|
|
23
|
+
if ((_a = msgData.textElem) === null || _a === void 0 ? void 0 : _a.content) {
|
|
24
|
+
return `${sender}: ${msgData.textElem.content}`;
|
|
25
|
+
}
|
|
26
|
+
break;
|
|
27
|
+
case MessageType.PictureMessage:
|
|
28
|
+
return (_jsxs("span", { children: [sender, ": ", _jsx(Icon, { icon: "image-b", size: 16, className: "mr-1" }), "H\u00ECnh \u1EA3nh"] }));
|
|
29
|
+
case MessageType.VoiceMessage:
|
|
30
|
+
return `${sender}: [Tin nhắn thoại]`;
|
|
31
|
+
case MessageType.VideoMessage:
|
|
32
|
+
return `${sender}: [Video]`;
|
|
33
|
+
case MessageType.FileMessage:
|
|
34
|
+
return `${sender}: [File đính kèm]`;
|
|
35
|
+
default:
|
|
36
|
+
return "Tin nhắn không khả dụng";
|
|
20
37
|
}
|
|
21
|
-
// TODO: Handle other message types (fileElem, videoElem, etc.)
|
|
22
|
-
// For now, return empty string for non-text messages
|
|
23
|
-
// This can be enhanced later to show appropriate previews
|
|
24
38
|
return "Tin nhắn không khả dụng";
|
|
25
39
|
}
|
|
26
40
|
catch (error) {
|
|
@@ -62,10 +76,11 @@ const formatTimestamp = (timestamp) => {
|
|
|
62
76
|
};
|
|
63
77
|
// Transform API data to UI-friendly format
|
|
64
78
|
const transformConversationData = (apiData, currentUserId) => {
|
|
65
|
-
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 || "", lastMessage: parseLatestMessage(conv.latestMsg, currentUserId), timestamp: formatTimestamp(conv.latestMsgSendTime), unreadCount: conv.unreadCount
|
|
79
|
+
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 || "", lastMessage: parseLatestMessage(conv.latestMsg, currentUserId), timestamp: formatTimestamp(conv.latestMsgSendTime), unreadCount: conv.unreadCount })));
|
|
66
80
|
};
|
|
67
|
-
const DeskConversationList = (
|
|
81
|
+
const DeskConversationList = () => {
|
|
68
82
|
const [searchQuery, setSearchQuery] = useState("");
|
|
83
|
+
const [conversationIdFromSession, setConversationIdFromSession] = useState([]);
|
|
69
84
|
const router = useRouter();
|
|
70
85
|
const pathname = usePathname();
|
|
71
86
|
const searchParams = useSearchParams();
|
|
@@ -74,38 +89,38 @@ const DeskConversationList = ({ onConversationSelect, className = "", }) => {
|
|
|
74
89
|
const selectedConversationId = useConversationStore((state) => state.selectedConversationId);
|
|
75
90
|
const setSelectedConversationId = useConversationStore((state) => state.setSelectedConversationId);
|
|
76
91
|
const conversationList = useConversationStore((state) => state.conversationList);
|
|
92
|
+
const assignedSessionList = useConversationStore((state) => state.assignedSessionList);
|
|
77
93
|
// Transform real conversation data from the API
|
|
78
|
-
const conversations =
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
const
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
};
|
|
94
|
+
const conversations = useMemo(() => {
|
|
95
|
+
const filteredConversation = conversationList.filter((conv) => conversationIdFromSession.includes(conv.conversationID));
|
|
96
|
+
return transformConversationData(filteredConversation || [], user === null || user === void 0 ? void 0 : user.userID);
|
|
97
|
+
}, [conversationList, conversationIdFromSession, user === null || user === void 0 ? void 0 : user.userID]);
|
|
98
|
+
useEffect(() => {
|
|
99
|
+
const conversationIds = assignedSessionList.map((session) => session.conversationId);
|
|
100
|
+
DChatSDK.getMultipleConversation(conversationIds).then(({ data }) => {
|
|
101
|
+
const extractConversationIDs = data.map((conv) => conv.conversationID);
|
|
102
|
+
setConversationIdFromSession(extractConversationIDs);
|
|
103
|
+
});
|
|
104
|
+
}, [assignedSessionList]);
|
|
105
|
+
console.log({ assignedSessionList });
|
|
89
106
|
useEffect(() => {
|
|
90
107
|
const threadId = searchParams.get("threadId");
|
|
91
108
|
if (threadId) {
|
|
92
109
|
setSelectedConversationId(threadId);
|
|
93
|
-
const selectedConversation = conversations.find((conv) => conv.
|
|
110
|
+
const selectedConversation = conversations.find((conv) => conv.conversationID === threadId);
|
|
94
111
|
if (selectedConversation) {
|
|
95
112
|
setConversationData(selectedConversation);
|
|
96
113
|
}
|
|
97
114
|
}
|
|
98
115
|
else if (conversations.length > 0) {
|
|
99
|
-
setSelectedConversationId(conversations[0].
|
|
116
|
+
setSelectedConversationId(conversations[0].conversationID);
|
|
100
117
|
setConversationData(conversations[0]);
|
|
101
118
|
const newSearchParams = new URLSearchParams(searchParams);
|
|
102
|
-
newSearchParams.set("threadId", conversations[0].
|
|
119
|
+
newSearchParams.set("threadId", conversations[0].conversationID);
|
|
103
120
|
router.replace(`${pathname}?${newSearchParams.toString()}`);
|
|
104
121
|
}
|
|
105
122
|
}, [searchParams, conversations.length]);
|
|
106
|
-
return (_jsxs("div", { className: `flex flex-col h-full bg-white border-r border-gray-200 w-[320px]
|
|
107
|
-
? "bg-blue-50"
|
|
108
|
-
: "bg-white"}`, children: [selectedConversationId === 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, children: conversation.name.charAt(0).toUpperCase() }) }) }), _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
|
|
123
|
+
return (_jsxs("div", { className: `flex flex-col h-full bg-white border-r border-gray-200 w-[320px]`, 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: [conversations.map((conversation) => (_jsx(ConversationItemList, { conversation: conversation, isSelected: selectedConversationId === conversation.conversationID }, conversation.conversationID))), conversations.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
|
|
109
124
|
? "Thử tìm kiếm với từ khóa khác"
|
|
110
125
|
: "Chưa có cuộc trò chuyện nào" })] }) }) }))] })] }));
|
|
111
126
|
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FileCollection.d.ts","sourceRoot":"","sources":["../../../src/components/mediaCollection/FileCollection.tsx"],"names":[],"mappings":"AAaA,QAAA,MAAM,cAAc,+CA8GnB,CAAC;AAEF,eAAe,cAAc,CAAC"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { MessageType } from "@openim/wasm-client-sdk";
|
|
3
|
+
import { useMediaCollection } from "../../hooks/collection/useMediaCollection";
|
|
4
|
+
import InfiniteScroll from "react-infinite-scroll-component";
|
|
5
|
+
import { Empty, Spin } from "antd";
|
|
6
|
+
import { useCallback } from "react";
|
|
7
|
+
import dayjs from "dayjs";
|
|
8
|
+
import useConversationStore from "../../store/conversation";
|
|
9
|
+
import { useTranslation } from "react-i18next";
|
|
10
|
+
import { documentIcon } from "../../assets/svg";
|
|
11
|
+
import { shortenFileName } from "../message/footer/FilePreview";
|
|
12
|
+
import { renderFileSize } from "../../utils/common";
|
|
13
|
+
const FileCollection = () => {
|
|
14
|
+
const { t } = useTranslation();
|
|
15
|
+
const selectedSourceId = useConversationStore((state) => state.selectedSourceId);
|
|
16
|
+
const { groupedData, fetchNextPage, hasNextPage, dataFlatten, isLoading } = useMediaCollection({
|
|
17
|
+
recvID: selectedSourceId,
|
|
18
|
+
contentType: MessageType.FileMessage,
|
|
19
|
+
});
|
|
20
|
+
const handleDownload = (url, fileName) => {
|
|
21
|
+
if (!url) {
|
|
22
|
+
console.warn("Không có link file để tải");
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
const link = document.createElement("a");
|
|
26
|
+
link.href = url;
|
|
27
|
+
if (fileName) {
|
|
28
|
+
link.setAttribute("download", fileName);
|
|
29
|
+
}
|
|
30
|
+
link.setAttribute("target", "_blank");
|
|
31
|
+
link.setAttribute("rel", "noopener noreferrer");
|
|
32
|
+
document.body.appendChild(link);
|
|
33
|
+
link.click();
|
|
34
|
+
link.remove();
|
|
35
|
+
};
|
|
36
|
+
const renderItem = useCallback((date, items) => {
|
|
37
|
+
return (_jsxs("div", { className: "px-3", children: [_jsx("span", { className: "text-sm font-medium text-gray-500", children: dayjs(date).format("DD MMM, YYYY") }), _jsx("div", { className: "flex flex-col gap-1 mt-2", children: items.map((item) => {
|
|
38
|
+
var _a, _b, _c;
|
|
39
|
+
const fileContent = JSON.parse(((_a = item === null || item === void 0 ? void 0 : item.chatLog) === null || _a === void 0 ? void 0 : _a.content) || "{}");
|
|
40
|
+
return (_jsxs("div", { className: "relative flex flex-row items-center gap-2 align-center bg-gray-100 rounded-md p-2 cursor-pointer", onClick: () => handleDownload((fileContent === null || fileContent === void 0 ? void 0 : fileContent.sourceUrl) || "", (fileContent === null || fileContent === void 0 ? void 0 : fileContent.fileName) || ""), children: [documentIcon, _jsxs("div", { className: "flex flex-col flex-1", children: [_jsx("span", { className: "text-sm font-medium", children: shortenFileName((fileContent === null || fileContent === void 0 ? void 0 : fileContent.fileName) || "", {
|
|
41
|
+
maxLength: 32,
|
|
42
|
+
}) }), _jsx("span", { className: "text-xs text-gray-500", children: `${renderFileSize(fileContent.fileSize || 0)} - ${dayjs(((_b = item === null || item === void 0 ? void 0 : item.chatLog) === null || _b === void 0 ? void 0 : _b.sendTime) || 0).format("HH:mm")}` })] })] }, (_c = item.chatLog) === null || _c === void 0 ? void 0 : _c.clientMsgID));
|
|
43
|
+
}) })] }, date));
|
|
44
|
+
}, []);
|
|
45
|
+
if (dataFlatten.length === 0 && !isLoading)
|
|
46
|
+
return _jsx(Empty, { description: t("no_media_files") });
|
|
47
|
+
if (isLoading)
|
|
48
|
+
return (_jsx("div", { className: "flex items-center justify-center", children: _jsx(Spin, {}) }));
|
|
49
|
+
return (_jsx("div", { id: "scrollableFileDiv", style: {
|
|
50
|
+
height: "100%",
|
|
51
|
+
overflow: "auto",
|
|
52
|
+
}, children: _jsx(InfiniteScroll, { dataLength: Object.keys(groupedData).length, next: fetchNextPage, hasMore: hasNextPage, loader: _jsx("div", { className: "flex items-center justify-center py-2", children: _jsx(Spin, {}) }), scrollableTarget: "scrollableFileDiv", children: Object.entries(groupedData).map(([date, items]) => renderItem(date, items)) }) }));
|
|
53
|
+
};
|
|
54
|
+
export default FileCollection;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ImageCollection.d.ts","sourceRoot":"","sources":["../../../src/components/mediaCollection/ImageCollection.tsx"],"names":[],"mappings":"AAWA,QAAA,MAAM,eAAe,+CAwFpB,CAAC;AAEF,eAAe,eAAe,CAAC"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { MessageType } from "@openim/wasm-client-sdk";
|
|
3
|
+
import { useMediaCollection } from "../../hooks/collection/useMediaCollection";
|
|
4
|
+
import InfiniteScroll from "react-infinite-scroll-component";
|
|
5
|
+
import { Empty, Image, Spin } from "antd";
|
|
6
|
+
import { useCallback } from "react";
|
|
7
|
+
import dayjs from "dayjs";
|
|
8
|
+
import useConversationStore from "../../store/conversation";
|
|
9
|
+
import { images } from "../../constants/images";
|
|
10
|
+
import { useTranslation } from "react-i18next";
|
|
11
|
+
const ImageCollection = () => {
|
|
12
|
+
const { t } = useTranslation();
|
|
13
|
+
const selectedSourceId = useConversationStore((state) => state.selectedSourceId);
|
|
14
|
+
const { groupedData, fetchNextPage, hasNextPage, dataFlatten, isLoading } = useMediaCollection({
|
|
15
|
+
recvID: selectedSourceId,
|
|
16
|
+
contentType: MessageType.PictureMessage,
|
|
17
|
+
});
|
|
18
|
+
const renderItem = useCallback((date, items) => {
|
|
19
|
+
return (_jsxs("div", { className: "mb-2", children: [_jsx("span", { className: "text-sm font-medium text-gray-500 px-3", children: dayjs(date).format("DD MMM, YYYY") }), _jsx("div", { className: "grid grid-cols-3 justify-start gap-px py-2", children: items.map((item) => {
|
|
20
|
+
var _a, _b, _c, _d;
|
|
21
|
+
const imageContent = JSON.parse(((_a = item === null || item === void 0 ? void 0 : item.chatLog) === null || _a === void 0 ? void 0 : _a.content) || "{}");
|
|
22
|
+
const sourceUrl = ((_b = imageContent.sourcePicture) === null || _b === void 0 ? void 0 : _b.url) ||
|
|
23
|
+
((_c = imageContent.snapshotPicture) === null || _c === void 0 ? void 0 : _c.url);
|
|
24
|
+
return (_jsx("div", { className: "border inline-block w-full h-full aspect-square", children: _jsx(Image, { rootClassName: "cursor-pointer w-full h-full", className: "w-full !h-full object-cover", src: sourceUrl, preview: true, placeholder: _jsx("div", { className: "flex items-center justify-center", children: _jsx(Spin, {}) }), fallback: images.imageFailed }) }, (_d = item === null || item === void 0 ? void 0 : item.chatLog) === null || _d === void 0 ? void 0 : _d.clientMsgID));
|
|
25
|
+
}) })] }, date));
|
|
26
|
+
}, []);
|
|
27
|
+
if (dataFlatten.length === 0 && !isLoading)
|
|
28
|
+
return _jsx(Empty, { description: t("no_media_files") });
|
|
29
|
+
if (isLoading)
|
|
30
|
+
return (_jsx("div", { className: "flex items-center justify-center", children: _jsx(Spin, {}) }));
|
|
31
|
+
return (_jsx("div", { id: "scrollableImageDiv", style: {
|
|
32
|
+
height: "100%",
|
|
33
|
+
overflow: "auto",
|
|
34
|
+
display: "flex",
|
|
35
|
+
}, children: _jsx(Image.PreviewGroup, { children: _jsx(InfiniteScroll, { dataLength: Object.keys(groupedData).length, next: fetchNextPage, hasMore: hasNextPage, loader: _jsx("div", { className: "flex items-center justify-center py-2", children: _jsx(Spin, {}) }), scrollableTarget: "scrollableImageDiv", children: Object.entries(groupedData).map(([date, items]) => renderItem(date, items)) }) }) }));
|
|
36
|
+
};
|
|
37
|
+
export default ImageCollection;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"LinkCollection.d.ts","sourceRoot":"","sources":["../../../src/components/mediaCollection/LinkCollection.tsx"],"names":[],"mappings":"AAGA,QAAA,MAAM,cAAc,+CAInB,CAAC;AAEF,eAAe,cAAc,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { Empty } from "antd";
|
|
3
|
+
import { useTranslation } from "react-i18next";
|
|
4
|
+
const LinkCollection = () => {
|
|
5
|
+
const { t } = useTranslation();
|
|
6
|
+
return _jsx(Empty, { description: t("no_media_files") });
|
|
7
|
+
};
|
|
8
|
+
export default LinkCollection;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"VideoCollection.d.ts","sourceRoot":"","sources":["../../../src/components/mediaCollection/VideoCollection.tsx"],"names":[],"mappings":"AAaA,QAAA,MAAM,eAAe,+CAiIpB,CAAC;AAEF,eAAe,eAAe,CAAC"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { MessageType } from "@openim/wasm-client-sdk";
|
|
3
|
+
import { useMediaCollection } from "../../hooks/collection/useMediaCollection";
|
|
4
|
+
import InfiniteScroll from "react-infinite-scroll-component";
|
|
5
|
+
import { Carousel, Empty, Image, Modal, Spin } from "antd";
|
|
6
|
+
import { useCallback, useState } from "react";
|
|
7
|
+
import dayjs from "dayjs";
|
|
8
|
+
import useConversationStore from "../../store/conversation";
|
|
9
|
+
import { useBoolean } from "ahooks";
|
|
10
|
+
import { images } from "../../constants/images";
|
|
11
|
+
import { Icon } from "../icon";
|
|
12
|
+
import { useTranslation } from "react-i18next";
|
|
13
|
+
const VideoCollection = () => {
|
|
14
|
+
const { t } = useTranslation();
|
|
15
|
+
const selectedSourceId = useConversationStore((state) => state.selectedSourceId);
|
|
16
|
+
const { groupedData, fetchNextPage, hasNextPage, dataFlatten, isLoading } = useMediaCollection({
|
|
17
|
+
recvID: selectedSourceId,
|
|
18
|
+
contentType: MessageType.VideoMessage,
|
|
19
|
+
});
|
|
20
|
+
const [open, { setTrue, setFalse }] = useBoolean(false);
|
|
21
|
+
const [currentIndex, setCurrentIndex] = useState(0);
|
|
22
|
+
const handleOpenPreview = (index) => {
|
|
23
|
+
setCurrentIndex(index);
|
|
24
|
+
setTrue();
|
|
25
|
+
};
|
|
26
|
+
const renderItem = useCallback((date, items) => {
|
|
27
|
+
return (_jsxs("div", { className: "mb-2", children: [_jsx("span", { className: "text-sm font-medium text-gray-500 px-3", children: dayjs(date).format("DD MMMM, YYYY") }), _jsx("div", { className: "grid grid-cols-3 justify-start gap-px py-2", children: items.map((item) => {
|
|
28
|
+
var _a, _b;
|
|
29
|
+
const videoContent = JSON.parse(((_a = item === null || item === void 0 ? void 0 : item.chatLog) === null || _a === void 0 ? void 0 : _a.content) || "{}");
|
|
30
|
+
const globalIndex = dataFlatten.findIndex((v) => { var _a, _b; return ((_a = v.chatLog) === null || _a === void 0 ? void 0 : _a.clientMsgID) === ((_b = item.chatLog) === null || _b === void 0 ? void 0 : _b.clientMsgID); });
|
|
31
|
+
return (_jsxs("div", { className: "border relative w-full h-full aspect-square cursor-pointer", onClick: () => handleOpenPreview(globalIndex), children: [_jsx(Image, { rootClassName: "w-full h-full", src: videoContent.snapshotUrl, alt: "video thumbnail", className: "w-full !h-full object-cover", fallback: images.imageFailed }), _jsx("div", { className: "absolute inset-0 flex items-center justify-center bg-black/30 text-white text-2xl", children: _jsx(Icon, { icon: "play-b", size: 24, color: "white" }) })] }, (_b = item === null || item === void 0 ? void 0 : item.chatLog) === null || _b === void 0 ? void 0 : _b.clientMsgID));
|
|
32
|
+
}) })] }, date));
|
|
33
|
+
}, []);
|
|
34
|
+
if (dataFlatten.length === 0 && !isLoading)
|
|
35
|
+
return _jsx(Empty, { description: t("no_media_files") });
|
|
36
|
+
if (isLoading)
|
|
37
|
+
return (_jsx("div", { className: "flex items-center justify-center", children: _jsx(Spin, {}) }));
|
|
38
|
+
return (_jsxs("div", { id: "scrollableVideoDiv", style: {
|
|
39
|
+
height: "100%",
|
|
40
|
+
overflow: "auto",
|
|
41
|
+
display: "flex",
|
|
42
|
+
}, children: [_jsx(InfiniteScroll, { dataLength: Object.keys(groupedData).length, next: fetchNextPage, hasMore: hasNextPage, loader: _jsx("div", { className: "flex items-center justify-center py-2", children: _jsx(Spin, {}) }), scrollableTarget: "scrollableVideoDiv", children: Object.entries(groupedData).map(([date, items]) => renderItem(date, items)) }), _jsx(Modal, { open: open, onCancel: setFalse, footer: null, centered: true, styles: {
|
|
43
|
+
content: {
|
|
44
|
+
padding: 0,
|
|
45
|
+
},
|
|
46
|
+
}, children: _jsx(Carousel, { dots: true, infinite: false, initialSlide: currentIndex, afterChange: (i) => setCurrentIndex(i), children: dataFlatten.map((item, idx) => {
|
|
47
|
+
var _a;
|
|
48
|
+
const videoContent = JSON.parse(((_a = item === null || item === void 0 ? void 0 : item.chatLog) === null || _a === void 0 ? void 0 : _a.content) || "{}");
|
|
49
|
+
const sourceUrl = videoContent.videoUrl;
|
|
50
|
+
return (_jsx("div", { style: { textAlign: "center" }, children: _jsx("video", { src: sourceUrl, controls: true, autoPlay: idx === currentIndex, style: { width: "100%", maxHeight: "80vh" } }) }, idx));
|
|
51
|
+
}) }) })] }));
|
|
52
|
+
};
|
|
53
|
+
export default VideoCollection;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/mediaCollection/index.tsx"],"names":[],"mappings":"AAaA,oBAAY,MAAM;IAChB,KAAK,UAAU;IACf,KAAK,UAAU;IACf,IAAI,SAAS;IACb,IAAI,SAAS;CACd;AAED,QAAA,MAAM,eAAe,+CAsEpB,CAAC;AAEF,eAAe,eAAe,CAAC"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
+
import { useBoolean } from "ahooks";
|
|
4
|
+
import { Button, Drawer, Tabs } from "antd";
|
|
5
|
+
import { Icon } from "../icon";
|
|
6
|
+
import { useTranslation } from "react-i18next";
|
|
7
|
+
import ImageCollection from "./ImageCollection";
|
|
8
|
+
import VideoCollection from "./VideoCollection";
|
|
9
|
+
import { useIsMobile } from "../../hooks/common/useIsMobile";
|
|
10
|
+
import { useMemo } from "react";
|
|
11
|
+
import FileCollection from "./FileCollection";
|
|
12
|
+
import LinkCollection from "./LinkCollection";
|
|
13
|
+
export var TabKey;
|
|
14
|
+
(function (TabKey) {
|
|
15
|
+
TabKey["Image"] = "image";
|
|
16
|
+
TabKey["Video"] = "video";
|
|
17
|
+
TabKey["File"] = "file";
|
|
18
|
+
TabKey["Link"] = "link";
|
|
19
|
+
})(TabKey || (TabKey = {}));
|
|
20
|
+
const MediaCollection = () => {
|
|
21
|
+
const { t } = useTranslation();
|
|
22
|
+
const [isOpen, { toggle }] = useBoolean(false);
|
|
23
|
+
const isMobile = useIsMobile();
|
|
24
|
+
const items = useMemo(() => {
|
|
25
|
+
return [
|
|
26
|
+
{
|
|
27
|
+
key: TabKey.Image,
|
|
28
|
+
label: "Ảnh",
|
|
29
|
+
children: _jsx(ImageCollection, {}),
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
key: TabKey.Video,
|
|
33
|
+
label: "Video",
|
|
34
|
+
children: _jsx(VideoCollection, {}),
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
key: TabKey.File,
|
|
38
|
+
label: "Tập tin",
|
|
39
|
+
children: _jsx(FileCollection, {}),
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
key: TabKey.Link,
|
|
43
|
+
label: "Liên kết",
|
|
44
|
+
children: _jsx(LinkCollection, {}),
|
|
45
|
+
},
|
|
46
|
+
];
|
|
47
|
+
}, []);
|
|
48
|
+
return (_jsxs(_Fragment, { children: [_jsx(Button, { type: "text", shape: "default", className: "text-gray-500 w-8 h-8 p-0", onClick: toggle, children: _jsx(Icon, { icon: "folder-o", size: 22 }) }), _jsx(Drawer, { open: isOpen, onClose: toggle, mask: false, closeIcon: false, styles: {
|
|
49
|
+
body: {
|
|
50
|
+
padding: 0,
|
|
51
|
+
},
|
|
52
|
+
}, getContainer: false, width: isMobile ? "100%" : 360, children: _jsxs("div", { children: [_jsxs("div", { className: "flex items-center justify-between p-3", children: [_jsx("span", { className: "text-lg font-medium", children: t("library") }), _jsx(Button, { type: "text", shape: "default", className: "text-gray-500 w-8 h-8 p-0", onClick: toggle, children: _jsx(Icon, { icon: "close-b", size: 22 }) })] }), _jsx(Tabs, { defaultActiveKey: TabKey.Image, items: items })] }) })] }));
|
|
53
|
+
};
|
|
54
|
+
export default MediaCollection;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MessageHeader.d.ts","sourceRoot":"","sources":["../../../src/components/message/MessageHeader.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"MessageHeader.d.ts","sourceRoot":"","sources":["../../../src/components/message/MessageHeader.tsx"],"names":[],"mappings":"AASA,UAAU,kBAAkB;IAC1B,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB;AAED,QAAA,MAAM,aAAa,GAAI,aAAa,kBAAkB,4CA4CrD,CAAC;AAEF,eAAe,aAAa,CAAC"}
|
|
@@ -4,10 +4,11 @@ import { Avatar, Button } from "antd";
|
|
|
4
4
|
import { Icon } from "../icon";
|
|
5
5
|
import { useConversationDisplayData } from "../../hooks/conversation/useConversation";
|
|
6
6
|
import useConversationStore from "../../store/conversation";
|
|
7
|
+
import MediaCollection from "../mediaCollection";
|
|
7
8
|
const MessageHeader = ({ onClose }) => {
|
|
8
9
|
var _a;
|
|
9
10
|
const conversationData = useConversationStore((state) => state.conversationData);
|
|
10
11
|
const { avatar, displayName } = useConversationDisplayData(conversationData);
|
|
11
|
-
return (_jsxs("div", { className: "px-4 py-3 flex items-center border-b gap-3", children: [_jsx(Avatar, { src: avatar, size: "large", children: ((_a = displayName === null || displayName === void 0 ? void 0 : displayName.charAt) === null || _a === void 0 ? void 0 : _a.call(displayName, 0)) || "A" }), _jsxs("div", { className: "flex flex-col flex-1", children: [_jsx("p", { children: displayName || "" }), _jsx("p", { className: "text-xs text-gray-500", children: "2 thành viên" })] }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Button, { type: "text", shape: "default", className: "text-gray-500 w-8 h-8 p-0", children: _jsx(Icon, { icon: "search-o", size: 22 }) }), _jsx(
|
|
12
|
+
return (_jsxs("div", { className: "px-4 py-3 flex items-center border-b gap-3 bg-white", children: [_jsx(Avatar, { src: avatar, size: "large", children: ((_a = displayName === null || displayName === void 0 ? void 0 : displayName.charAt) === null || _a === void 0 ? void 0 : _a.call(displayName, 0)) || "A" }), _jsxs("div", { className: "flex flex-col flex-1", children: [_jsx("p", { children: displayName || "" }), _jsx("p", { className: "text-xs text-gray-500", children: "2 thành viên" })] }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Button, { type: "text", shape: "default", className: "text-gray-500 w-8 h-8 p-0", children: _jsx(Icon, { icon: "search-o", size: 22 }) }), _jsx(MediaCollection, {}), _jsx(Button, { type: "text", shape: "default", className: "text-gray-500 w-8 h-8 p-0", children: _jsx(Icon, { icon: "align-justify-o", size: 22 }) }), !!onClose && (_jsx(Button, { type: "text", shape: "default", className: "text-gray-500 w-8 h-8 p-0", onClick: onClose, children: _jsx(Icon, { icon: "close-b", size: 22 }) }))] })] }));
|
|
12
13
|
};
|
|
13
14
|
export default MessageHeader;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MessageList.d.ts","sourceRoot":"","sources":["../../../src/components/message/MessageList.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"MessageList.d.ts","sourceRoot":"","sources":["../../../src/components/message/MessageList.tsx"],"names":[],"mappings":"AAiBA,UAAU,gBAAgB;IACxB,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB;AAED,QAAA,MAAM,WAAW,GAAI,OAAO,gBAAgB,4CA0F3C,CAAC;AAEF,eAAe,WAAW,CAAC"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { useMessage } from "../../hooks/message/useMessage";
|
|
4
|
-
import { Spin } from "antd";
|
|
4
|
+
import { Empty, Spin } from "antd";
|
|
5
5
|
import { useEffect, useMemo, useRef } from "react";
|
|
6
6
|
import dayjs from "dayjs";
|
|
7
7
|
import isToday from "dayjs/plugin/isToday";
|
|
@@ -10,12 +10,17 @@ import MessageItem from "./item";
|
|
|
10
10
|
import InfiniteScroll from "react-infinite-scroll-component";
|
|
11
11
|
import MessageHeader from "./MessageHeader";
|
|
12
12
|
import MessageFooter from "./footer";
|
|
13
|
+
import { images } from "../../constants/images";
|
|
14
|
+
import { useTranslation } from "react-i18next";
|
|
15
|
+
import useConversationStore from "../../store/conversation";
|
|
13
16
|
dayjs.extend(isToday);
|
|
14
17
|
const MessageList = (props) => {
|
|
15
18
|
var _a, _b, _c;
|
|
19
|
+
const { t } = useTranslation();
|
|
16
20
|
const { onClose, conversationId } = props;
|
|
17
21
|
const scrollRef = useRef(null);
|
|
18
22
|
const { getMoreOldMessages, moreOldLoading, loadState, latestLoadState } = useMessage(conversationId);
|
|
23
|
+
const conversationData = useConversationStore((state) => state.conversationData);
|
|
19
24
|
const lastMessage = useMemo(() => {
|
|
20
25
|
var _a;
|
|
21
26
|
const messageList = (_a = latestLoadState.current) === null || _a === void 0 ? void 0 : _a.messageList;
|
|
@@ -41,11 +46,18 @@ const MessageList = (props) => {
|
|
|
41
46
|
emitter.off("CHAT_LIST_SCROLL_TO_BOTTOM", scrollToBottom);
|
|
42
47
|
};
|
|
43
48
|
}, []);
|
|
44
|
-
|
|
49
|
+
if (!conversationData) {
|
|
50
|
+
return (_jsx("div", { className: "flex flex-1 items-center justify-center h-full", children: _jsx(Empty, { description: t("no_conversation_data") }) }));
|
|
51
|
+
}
|
|
52
|
+
return (_jsxs("div", { className: "flex flex-col flex-1 relative h-full", style: {
|
|
53
|
+
backgroundImage: `url(${images.conversationBg})`,
|
|
54
|
+
backgroundSize: "cover",
|
|
55
|
+
backgroundPosition: "center",
|
|
56
|
+
}, children: [_jsx(MessageHeader, { onClose: onClose }), _jsx("div", { id: "scrollableDiv", style: {
|
|
45
57
|
height: "100%",
|
|
46
58
|
overflow: "auto",
|
|
47
59
|
display: "flex",
|
|
48
60
|
flexDirection: "column-reverse",
|
|
49
|
-
}, children: _jsx(InfiniteScroll, { dataLength: ((_b = loadState.groupMessageList) === null || _b === void 0 ? void 0 : _b.length) || 0, next: loadMoreMessage, style: { display: "flex", flexDirection: "column-reverse" }, inverse: true, hasMore: loadState.hasMoreOld, loader: _jsx("div", { className: "flex items-center justify-center py-2", children: _jsx(Spin, {}) }), scrollableTarget: "scrollableDiv", children: (_c = loadState.groupMessageList) === null || _c === void 0 ? void 0 : _c.toReversed().map((message) => _jsx(MessageItem, { groupMessage: message })) }) }), _jsx(MessageFooter, { lastMessage: lastMessage })] }));
|
|
61
|
+
}, children: _jsx(InfiniteScroll, { dataLength: ((_b = loadState.groupMessageList) === null || _b === void 0 ? void 0 : _b.length) || 0, next: loadMoreMessage, style: { display: "flex", flexDirection: "column-reverse" }, inverse: true, hasMore: loadState.hasMoreOld, loader: _jsx("div", { className: "flex items-center justify-center py-2", children: _jsx(Spin, {}) }), scrollableTarget: "scrollableDiv", children: (_c = loadState.groupMessageList) === null || _c === void 0 ? void 0 : _c.toReversed().map((message) => (_jsx(MessageItem, { groupMessage: message }, message.groupMessageID))) }) }), _jsx(MessageFooter, { lastMessage: lastMessage })] }));
|
|
50
62
|
};
|
|
51
63
|
export default MessageList;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FilePreview.d.ts","sourceRoot":"","sources":["../../../../src/components/message/footer/FilePreview.tsx"],"names":[],"mappings":"AAYA,
|
|
1
|
+
{"version":3,"file":"FilePreview.d.ts","sourceRoot":"","sources":["../../../../src/components/message/footer/FilePreview.tsx"],"names":[],"mappings":"AAYA,UAAU,cAAc;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,eAAO,MAAM,eAAe,GAAI,MAAM,MAAM,EAAE,UAAS,cAAmB,WAkBzE,CAAC;AAEF,QAAA,MAAM,WAAW,+CAkFhB,CAAC;AAEF,eAAe,WAAW,CAAC"}
|