@droppii-org/chat-sdk 0.0.30 → 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 +40 -24
- 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 +14 -2
- 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.js +9 -10
- 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/conversation/useConversationStore.d.ts +3 -2
- package/dist/hooks/conversation/useConversationStore.d.ts.map +1 -1
- 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 +5 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- 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/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/dist/utils/imCommon.d.ts +0 -1
- package/dist/utils/imCommon.d.ts.map +1 -1
- package/dist/utils/imCommon.js +0 -5
- package/package.json +15 -3
- package/dist/assets/openIM.wasm +0 -0
- package/dist/components/ChatBubble.d.ts +0 -10
- package/dist/components/ChatBubble.d.ts.map +0 -1
- package/dist/components/ChatBubble.js +0 -28
- package/dist/components/message/MessageItem.d.ts +0 -7
- package/dist/components/message/MessageItem.d.ts.map +0 -1
- package/dist/components/message/MessageItem.js +0 -21
- package/dist/components/message/footer/BottomSection.d.ts +0 -3
- package/dist/components/message/footer/BottomSection.d.ts.map +0 -1
- package/dist/components/message/footer/BottomSection.js +0 -6
- package/dist/screens/desk-message/index.d.ts +0 -3
- package/dist/screens/desk-message/index.d.ts.map +0 -1
- package/dist/screens/desk-message/index.js +0 -15
- package/dist/tsconfig.tsbuildinfo +0 -1
- package/dist/types/index.d.ts +0 -1
- package/dist/types/index.d.ts.map +0 -1
- package/dist/types/index.js +0 -1
- package/dist/types/sdk.d.ts +0 -1
- package/dist/types/sdk.d.ts.map +0 -1
- package/dist/types/sdk.js +0 -1
|
@@ -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) {
|
|
@@ -64,8 +78,9 @@ const formatTimestamp = (timestamp) => {
|
|
|
64
78
|
const transformConversationData = (apiData, currentUserId) => {
|
|
65
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,17 +89,20 @@ 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);
|
|
77
|
-
|
|
92
|
+
const assignedSessionList = useConversationStore((state) => state.assignedSessionList);
|
|
78
93
|
// Transform real conversation data from the API
|
|
79
|
-
const conversations =
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
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 });
|
|
88
106
|
useEffect(() => {
|
|
89
107
|
const threadId = searchParams.get("threadId");
|
|
90
108
|
if (threadId) {
|
|
@@ -102,9 +120,7 @@ const DeskConversationList = ({ onConversationSelect, className = "", }) => {
|
|
|
102
120
|
router.replace(`${pathname}?${newSearchParams.toString()}`);
|
|
103
121
|
}
|
|
104
122
|
}, [searchParams, conversations.length]);
|
|
105
|
-
return (_jsxs("div", { className: `flex flex-col h-full bg-white border-r border-gray-200 w-[320px]
|
|
106
|
-
? "bg-blue-50"
|
|
107
|
-
: "bg-white"}`, children: [selectedConversationId === conversation.conversationID && (_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))), 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
|
|
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
|
|
108
124
|
? "Thử tìm kiếm với từ khóa khác"
|
|
109
125
|
: "Chưa có cuộc trò chuyện nào" })] }) }) }))] })] }));
|
|
110
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,7 +46,14 @@ 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",
|
|
@@ -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"}
|
|
@@ -4,12 +4,12 @@ import { useCallback } from "react";
|
|
|
4
4
|
import { useMessageFooterContext } from ".";
|
|
5
5
|
import { Button } from "antd";
|
|
6
6
|
import { Icon } from "../../icon";
|
|
7
|
+
import { documentIcon } from "../../../assets/svg";
|
|
7
8
|
const documentTypes = [
|
|
8
9
|
"application/pdf",
|
|
9
10
|
"application/msword",
|
|
10
11
|
"application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
|
11
12
|
];
|
|
12
|
-
export const documentIcon = (_jsxs("svg", { width: "40", height: "40", viewBox: "0 0 40 40", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: [_jsx("path", { d: "M10.1923 5.83301L23.4363 5.83301L34.1656 14.2054V29.8639C34.1656 31.8997 32.5286 34.1663 29.8068 34.1663C27.0849 34.1663 10.1923 34.1663 10.1923 34.1663C7.4704 34.1663 5.8335 31.8997 5.8335 29.8639V10.0305C5.8335 7.99475 7.4704 5.83301 10.1923 5.83301Z", fill: "#24B0FF" }), _jsx("path", { d: "M10.8335 28.1394V20.833H16.0309V22.4222H12.7026V23.5916H15.3612V25.1708H12.7026V28.1394H10.8335Z", fill: "#edf6ff" }), _jsx("path", { d: "M19.0073 28.0885V20.833H20.8613V26.5118H24.0146V28.0885L19.0073 28.0885Z", fill: "#edf6ff" }), _jsx("path", { d: "M16.5918 28.1001V20.833H18.4485V28.1001H16.5918Z", fill: "#edf6ff" }), _jsx("path", { d: "M24.5737 20.833V28.1393H29.7723V26.5573H26.439L26.4422 25.1708H29.1017V23.5916H26.4422V22.4222H29.7723V20.833H24.5737Z", fill: "#edf6ff" }), _jsx("path", { opacity: "0.302", "fill-rule": "evenodd", "clip-rule": "evenodd", d: "M23.2686 5.83301V14.2281H34.1655L23.2686 5.83301Z", fill: "#edf6ff" })] }));
|
|
13
13
|
export const shortenFileName = (name, options = {}) => {
|
|
14
14
|
const { maxLength = 20, keepStart = 8, keepEnd = 3 } = options;
|
|
15
15
|
if (name.length <= maxLength)
|
|
@@ -31,7 +31,7 @@ const FilePreview = () => {
|
|
|
31
31
|
setListUploadFiles(listUploadFiles.filter((f) => f.uid !== file.uid));
|
|
32
32
|
};
|
|
33
33
|
const renderFilePreview = useCallback((file) => {
|
|
34
|
-
var _a, _b;
|
|
34
|
+
var _a, _b, _c;
|
|
35
35
|
const isDocument = documentTypes.includes(((_a = file === null || file === void 0 ? void 0 : file.originFileObj) === null || _a === void 0 ? void 0 : _a.type) || "");
|
|
36
36
|
const isVideo = (_b = file.type) === null || _b === void 0 ? void 0 : _b.startsWith("video/");
|
|
37
37
|
let src = file.url;
|
|
@@ -39,10 +39,10 @@ const FilePreview = () => {
|
|
|
39
39
|
src = URL.createObjectURL(file.originFileObj);
|
|
40
40
|
}
|
|
41
41
|
if (isDocument) {
|
|
42
|
-
return (_jsxs("div", { className: "relative flex flex-row items-center gap-2 align-center bg-gray-100 rounded-md p-1 pr-2", children: [documentIcon, _jsx("span", { className: "text-xs text-gray-500", children: shortenFileName(file.name) }), _jsx(Button, { className: "absolute top-[-8px] right-[-8px] w-5 h-5 rounded-full p-0 bg-gray-500 hover:bg-gray-600", type: "primary", onClick: () => onRemoveFile(file), children: _jsx(Icon, { icon: "close-b", size: 12, color: "white" }) })] }, file.uid));
|
|
42
|
+
return (_jsxs("div", { className: "relative flex flex-row items-center gap-2 align-center bg-gray-100 rounded-md p-1 pr-2", children: [documentIcon, _jsx("span", { className: "text-xs text-gray-500", children: shortenFileName(((_c = file === null || file === void 0 ? void 0 : file.originFileObj) === null || _c === void 0 ? void 0 : _c.name) || "") }), _jsx(Button, { className: "absolute top-[-8px] right-[-8px] w-5 h-5 rounded-full p-0 bg-gray-500 hover:bg-gray-600", type: "primary", onClick: () => onRemoveFile(file), children: _jsx(Icon, { icon: "close-b", size: 12, color: "white" }) })] }, file.uid));
|
|
43
43
|
}
|
|
44
44
|
return (_jsxs("div", { className: "relative rounded-md border", children: [isVideo ? (_jsx("video", { src: src, className: "w-[48px] h-[48px] object-cover rounded-lg", autoPlay: false })) : (_jsx("img", { src: src, alt: file.name, className: "w-[48px] h-[48px] object-cover rounded-lg" })), _jsx(Button, { className: "absolute top-[-8px] right-[-8px] w-5 h-5 rounded-full p-0 bg-gray-500 hover:bg-gray-600", type: "primary", onClick: () => onRemoveFile(file), children: _jsx(Icon, { icon: "close-b", size: 12, color: "white" }) }), isVideo && (_jsx(Icon, { className: "absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2", icon: "play-b", size: 20, color: "white" }))] }, file.uid));
|
|
45
45
|
}, [listUploadFiles]);
|
|
46
|
-
return (_jsx("div", { className: "overflow-x-auto", children: _jsx("div", { className: "border-b py-2 px-4", children: _jsx("div", { className: "flex items-center gap-2", children: listUploadFiles.map((file) => renderFilePreview(file)) }) }) }));
|
|
46
|
+
return (_jsx("div", { className: "overflow-x-auto mb-[-4px]", children: _jsx("div", { className: "border-b py-2 px-4", children: _jsx("div", { className: "flex items-center gap-2", children: listUploadFiles.map((file) => renderFilePreview(file)) }) }) }));
|
|
47
47
|
};
|
|
48
48
|
export default FilePreview;
|