@droppii-org/chat-sdk 0.0.30 → 0.0.32
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/ConversationBySessionItem.d.ts +7 -0
- package/dist/components/conversation/ConversationBySessionItem.d.ts.map +1 -0
- package/dist/components/conversation/ConversationBySessionItem.js +97 -0
- 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 +33 -87
- 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 +52 -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 +51 -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 +50 -0
- package/dist/components/mediaCollection/index.d.ts +10 -0
- package/dist/components/mediaCollection/index.d.ts.map +1 -0
- package/dist/components/mediaCollection/index.js +58 -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.d.ts.map +1 -1
- package/dist/components/message/footer/ToolbarPlugin.js +3 -6
- 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/searchConversation/SearchAll.d.ts +3 -0
- package/dist/components/searchConversation/SearchAll.d.ts.map +1 -0
- package/dist/components/searchConversation/SearchAll.js +8 -0
- package/dist/components/searchConversation/SearchConversationAsMessages.d.ts +3 -0
- package/dist/components/searchConversation/SearchConversationAsMessages.d.ts.map +1 -0
- package/dist/components/searchConversation/SearchConversationAsMessages.js +8 -0
- package/dist/components/searchConversation/SearchConversationAsUsers.d.ts +3 -0
- package/dist/components/searchConversation/SearchConversationAsUsers.d.ts.map +1 -0
- package/dist/components/searchConversation/SearchConversationAsUsers.js +8 -0
- package/dist/components/searchConversation/index.d.ts +8 -0
- package/dist/components/searchConversation/index.d.ts.map +1 -0
- package/dist/components/searchConversation/index.js +38 -0
- package/dist/components/session/AssignedSessionFilter.js +9 -10
- package/dist/components/session/DeskAssignedSession.d.ts +3 -0
- package/dist/components/session/DeskAssignedSession.d.ts.map +1 -0
- package/dist/components/session/DeskAssignedSession.js +118 -0
- 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/useConversation.js +1 -1
- 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/hooks/search/useSearchConversation.d.ts +2 -0
- package/dist/hooks/search/useSearchConversation.d.ts.map +1 -0
- package/dist/hooks/search/useSearchConversation.js +1 -0
- package/dist/hooks/session/useGetSessionByTagOrStatus.d.ts +220 -0
- package/dist/hooks/session/useGetSessionByTagOrStatus.d.ts.map +1 -0
- package/dist/hooks/session/useGetSessionByTagOrStatus.js +72 -0
- package/dist/hooks/session/useGetSessionSummary.d.ts +3 -0
- package/dist/hooks/session/useGetSessionSummary.d.ts.map +1 -0
- package/dist/hooks/session/useGetSessionSummary.js +14 -0
- package/dist/index.d.ts +5 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -4
- 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 +24 -0
- package/dist/screens/chatBubble/index.d.ts.map +1 -1
- package/dist/screens/chatBubble/index.js +20 -10
- package/dist/screens/deskMessage/index.d.ts.map +1 -1
- package/dist/screens/deskMessage/index.js +4 -4
- 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 +7 -0
- package/dist/services/query.d.ts.map +1 -0
- package/dist/services/query.js +6 -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 +0 -11
- package/dist/store/session.d.ts +8 -0
- package/dist/store/session.d.ts.map +1 -0
- package/dist/store/session.js +10 -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 +55 -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%", push: false, 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 { ISessionByStatus } from "../../store/type";
|
|
2
|
+
interface ConversationBySessionItemProps {
|
|
3
|
+
sessionItem: ISessionByStatus;
|
|
4
|
+
}
|
|
5
|
+
declare const ConversationBySessionItem: ({ sessionItem, }: ConversationBySessionItemProps) => import("react/jsx-runtime").JSX.Element | null;
|
|
6
|
+
export default ConversationBySessionItem;
|
|
7
|
+
//# sourceMappingURL=ConversationBySessionItem.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ConversationBySessionItem.d.ts","sourceRoot":"","sources":["../../../src/components/conversation/ConversationBySessionItem.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAQpD,UAAU,8BAA8B;IACtC,WAAW,EAAE,gBAAgB,CAAC;CAC/B;AAED,QAAA,MAAM,yBAAyB,GAAI,kBAEhC,8BAA8B,mDAwFhC,CAAC;AAEF,eAAe,yBAAyB,CAAC"}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { MessageType } from "@openim/wasm-client-sdk";
|
|
4
|
+
import { useTranslation } from "react-i18next";
|
|
5
|
+
import useConversationStore from "../../store/conversation";
|
|
6
|
+
import { usePathname, useRouter, useSearchParams } from "next/navigation";
|
|
7
|
+
import { Avatar, Badge } from "antd";
|
|
8
|
+
import { Icon } from "../icon";
|
|
9
|
+
import { useChatContext } from "../../context/ChatContext";
|
|
10
|
+
import { useConversationDisplayData } from "../../hooks/conversation/useConversation";
|
|
11
|
+
const ConversationBySessionItem = ({ sessionItem, }) => {
|
|
12
|
+
const { t } = useTranslation();
|
|
13
|
+
const { user } = useChatContext();
|
|
14
|
+
const conversation = useConversationStore((state) => state.conversationList.find((conv) => conv.conversationID === sessionItem.conversationId));
|
|
15
|
+
const isSelected = useConversationStore((state) => state.selectedConversationId === sessionItem.conversationId);
|
|
16
|
+
const router = useRouter();
|
|
17
|
+
const pathname = usePathname();
|
|
18
|
+
const searchParams = useSearchParams();
|
|
19
|
+
const setConversationData = useConversationStore((state) => state.setConversationData);
|
|
20
|
+
const setSelectedConversationId = useConversationStore((state) => state.setSelectedConversationId);
|
|
21
|
+
const handleConversationClick = (conversation) => {
|
|
22
|
+
setConversationData(conversation);
|
|
23
|
+
const newSearchParams = new URLSearchParams(searchParams);
|
|
24
|
+
newSearchParams.set("threadId", conversation.conversationID);
|
|
25
|
+
router.push(`${pathname}?${newSearchParams.toString()}`);
|
|
26
|
+
setSelectedConversationId(conversation.conversationID);
|
|
27
|
+
};
|
|
28
|
+
if (!conversation)
|
|
29
|
+
return null;
|
|
30
|
+
const { avatar, displayName = "" } = useConversationDisplayData(conversation);
|
|
31
|
+
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: avatar, alt: displayName, children: displayName.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: displayName }), _jsx("p", { className: "text-xs text-gray-500 truncate mt-0.5", children: parseLatestMessage(conversation.latestMsg, user === null || user === void 0 ? void 0 : user.userID) })] }), _jsxs("div", { className: "flex flex-col items-end gap-1 ml-2", children: [_jsx("span", { className: "text-xs text-gray-400", children: formatTimestamp(conversation.latestMsgSendTime) }), _jsx("div", { className: "flex items-center gap-1", children: conversation.unreadCount > 0 && (_jsx(Badge, { count: conversation.unreadCount })) })] })] }) })] })] }, conversation.conversationID));
|
|
32
|
+
};
|
|
33
|
+
export default ConversationBySessionItem;
|
|
34
|
+
const parseLatestMessage = (latestMsg, currentUserId) => {
|
|
35
|
+
var _a;
|
|
36
|
+
if (!latestMsg)
|
|
37
|
+
return "";
|
|
38
|
+
try {
|
|
39
|
+
const msgData = JSON.parse(latestMsg);
|
|
40
|
+
const contentType = msgData === null || msgData === void 0 ? void 0 : msgData.contentType;
|
|
41
|
+
const isMe = currentUserId && msgData.sendID === currentUserId;
|
|
42
|
+
const sender = isMe ? "Me" : (msgData === null || msgData === void 0 ? void 0 : msgData.senderNickname) || msgData.sendID;
|
|
43
|
+
switch (contentType) {
|
|
44
|
+
case MessageType.TextMessage:
|
|
45
|
+
if ((_a = msgData.textElem) === null || _a === void 0 ? void 0 : _a.content) {
|
|
46
|
+
return `${sender}: ${msgData.textElem.content}`;
|
|
47
|
+
}
|
|
48
|
+
break;
|
|
49
|
+
case MessageType.PictureMessage:
|
|
50
|
+
return (_jsxs("span", { children: [sender, ": ", _jsx(Icon, { icon: "image-o", size: 16, className: "mr-1" }), "H\u00ECnh \u1EA3nh"] }));
|
|
51
|
+
case MessageType.VoiceMessage:
|
|
52
|
+
return `${sender}: [Tin nhắn thoại]`;
|
|
53
|
+
case MessageType.VideoMessage:
|
|
54
|
+
return `${sender}: [Video]`;
|
|
55
|
+
case MessageType.FileMessage:
|
|
56
|
+
return `${sender}: [File đính kèm]`;
|
|
57
|
+
default:
|
|
58
|
+
return "Tin nhắn không khả dụng";
|
|
59
|
+
}
|
|
60
|
+
return "Tin nhắn không khả dụng";
|
|
61
|
+
}
|
|
62
|
+
catch (error) {
|
|
63
|
+
console.error("Error parsing latest message:", error);
|
|
64
|
+
return "";
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
const formatTimestamp = (timestamp) => {
|
|
68
|
+
if (!timestamp)
|
|
69
|
+
return "";
|
|
70
|
+
const date = new Date(timestamp);
|
|
71
|
+
const now = new Date();
|
|
72
|
+
const diffInMs = now.getTime() - date.getTime();
|
|
73
|
+
const diffInDays = Math.floor(diffInMs / (1000 * 60 * 60 * 24));
|
|
74
|
+
if (diffInDays === 0) {
|
|
75
|
+
// Today - show time
|
|
76
|
+
return date.toLocaleTimeString("vi-VN", {
|
|
77
|
+
hour: "2-digit",
|
|
78
|
+
minute: "2-digit",
|
|
79
|
+
hour12: false,
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
else if (diffInDays === 1) {
|
|
83
|
+
// Yesterday
|
|
84
|
+
return "Hôm qua";
|
|
85
|
+
}
|
|
86
|
+
else if (diffInDays < 7) {
|
|
87
|
+
// This week - show day name
|
|
88
|
+
return date.toLocaleDateString("vi-VN", { weekday: "long" });
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
// Older - show date
|
|
92
|
+
return date.toLocaleDateString("vi-VN", {
|
|
93
|
+
day: "2-digit",
|
|
94
|
+
month: "2-digit",
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
};
|
|
@@ -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":"AAeA,QAAA,MAAM,oBAAoB,+CAkJzB,CAAC;AAEF,eAAe,oBAAoB,CAAC"}
|
|
@@ -1,111 +1,57 @@
|
|
|
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, useRef } from "react";
|
|
4
4
|
import { useRouter, useSearchParams, usePathname } from "next/navigation";
|
|
5
|
-
import { Input,
|
|
5
|
+
import { Input, Empty, Drawer, Button, Spin } from "antd";
|
|
6
6
|
import { Icon } from "../icon";
|
|
7
|
-
import { useChatContext } from "../../context/ChatContext";
|
|
8
7
|
import useConversationStore from "../../store/conversation";
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
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
|
-
return "Tin nhắn không khả dụng";
|
|
25
|
-
}
|
|
26
|
-
catch (error) {
|
|
27
|
-
console.error("Error parsing latest message:", error);
|
|
28
|
-
return "";
|
|
29
|
-
}
|
|
30
|
-
};
|
|
31
|
-
// Utility function to format timestamp
|
|
32
|
-
const formatTimestamp = (timestamp) => {
|
|
33
|
-
if (!timestamp)
|
|
34
|
-
return "";
|
|
35
|
-
const date = new Date(timestamp);
|
|
36
|
-
const now = new Date();
|
|
37
|
-
const diffInMs = now.getTime() - date.getTime();
|
|
38
|
-
const diffInDays = Math.floor(diffInMs / (1000 * 60 * 60 * 24));
|
|
39
|
-
if (diffInDays === 0) {
|
|
40
|
-
// Today - show time
|
|
41
|
-
return date.toLocaleTimeString("vi-VN", {
|
|
42
|
-
hour: "2-digit",
|
|
43
|
-
minute: "2-digit",
|
|
44
|
-
hour12: false,
|
|
45
|
-
});
|
|
46
|
-
}
|
|
47
|
-
else if (diffInDays === 1) {
|
|
48
|
-
// Yesterday
|
|
49
|
-
return "Hôm qua";
|
|
50
|
-
}
|
|
51
|
-
else if (diffInDays < 7) {
|
|
52
|
-
// This week - show day name
|
|
53
|
-
return date.toLocaleDateString("vi-VN", { weekday: "long" });
|
|
54
|
-
}
|
|
55
|
-
else {
|
|
56
|
-
// Older - show date
|
|
57
|
-
return date.toLocaleDateString("vi-VN", {
|
|
58
|
-
day: "2-digit",
|
|
59
|
-
month: "2-digit",
|
|
60
|
-
});
|
|
61
|
-
}
|
|
62
|
-
};
|
|
63
|
-
// Transform API data to UI-friendly format
|
|
64
|
-
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 })));
|
|
66
|
-
};
|
|
67
|
-
const DeskConversationList = ({ onConversationSelect, className = "", }) => {
|
|
68
|
-
const [searchQuery, setSearchQuery] = useState("");
|
|
8
|
+
import { useTranslation } from "react-i18next";
|
|
9
|
+
import { useBoolean, useDebounceFn } from "ahooks";
|
|
10
|
+
import SearchConversation from "../searchConversation";
|
|
11
|
+
import useSessionStore from "../../store/session";
|
|
12
|
+
import { useGetSessionByTagOrStatus } from "../../hooks/session/useGetSessionByTagOrStatus";
|
|
13
|
+
import InfiniteScroll from "react-infinite-scroll-component";
|
|
14
|
+
import ConversationBySessionItem from "./ConversationBySessionItem";
|
|
15
|
+
const DeskConversationList = () => {
|
|
16
|
+
const searchInputRef = useRef(null);
|
|
17
|
+
const { t } = useTranslation();
|
|
18
|
+
const [search, setSearch] = useState("");
|
|
19
|
+
const [showSearch, { setTrue: setShowSearchTrue, setFalse: setShowSearchFalse },] = useBoolean(false);
|
|
69
20
|
const router = useRouter();
|
|
70
21
|
const pathname = usePathname();
|
|
71
22
|
const searchParams = useSearchParams();
|
|
72
|
-
const { user } = useChatContext();
|
|
73
23
|
const setConversationData = useConversationStore((state) => state.setConversationData);
|
|
74
|
-
const selectedConversationId = useConversationStore((state) => state.selectedConversationId);
|
|
75
24
|
const setSelectedConversationId = useConversationStore((state) => state.setSelectedConversationId);
|
|
76
25
|
const conversationList = useConversationStore((state) => state.conversationList);
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
const
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
const newSearchParams = new URLSearchParams(searchParams);
|
|
83
|
-
newSearchParams.set("threadId", conversation.conversationID);
|
|
84
|
-
router.push(`${pathname}?${newSearchParams.toString()}`);
|
|
85
|
-
setSelectedConversationId(conversation.conversationID);
|
|
86
|
-
onConversationSelect === null || onConversationSelect === void 0 ? void 0 : onConversationSelect(conversation.conversationID, conversation.conversationID);
|
|
87
|
-
};
|
|
26
|
+
const filterSummary = useSessionStore((state) => state.filterSummary);
|
|
27
|
+
const { dataFlatten: sessions, isLoading, error, hasNextPage, fetchNextPage, isFetchingNextPage, } = useGetSessionByTagOrStatus(filterSummary);
|
|
28
|
+
const { run: deboundSearch } = useDebounceFn((value) => {
|
|
29
|
+
setSearch(value);
|
|
30
|
+
}, { wait: 500 });
|
|
88
31
|
useEffect(() => {
|
|
89
32
|
const threadId = searchParams.get("threadId");
|
|
90
33
|
if (threadId) {
|
|
91
34
|
setSelectedConversationId(threadId);
|
|
92
|
-
const selectedConversation =
|
|
35
|
+
const selectedConversation = conversationList.find((conv) => conv.conversationID === threadId);
|
|
93
36
|
if (selectedConversation) {
|
|
94
37
|
setConversationData(selectedConversation);
|
|
95
38
|
}
|
|
96
39
|
}
|
|
97
|
-
else if (
|
|
98
|
-
setSelectedConversationId(
|
|
99
|
-
setConversationData(
|
|
40
|
+
else if (conversationList.length > 0) {
|
|
41
|
+
setSelectedConversationId(conversationList[0].conversationID);
|
|
42
|
+
setConversationData(conversationList[0]);
|
|
100
43
|
const newSearchParams = new URLSearchParams(searchParams);
|
|
101
|
-
newSearchParams.set("threadId",
|
|
44
|
+
newSearchParams.set("threadId", conversationList[0].conversationID);
|
|
102
45
|
router.replace(`${pathname}?${newSearchParams.toString()}`);
|
|
103
46
|
}
|
|
104
|
-
}, [searchParams,
|
|
105
|
-
return (_jsxs("div", { className: `flex flex-col h-full bg-white border-r border-gray-200 w-[320px]
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
47
|
+
}, [searchParams, conversationList]);
|
|
48
|
+
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-100", children: _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Input, { ref: searchInputRef, placeholder: t("search"), prefix: _jsx(Icon, { icon: "search-o", size: 18, className: "text-gray-400" }), onChange: (e) => deboundSearch(e.target.value), className: "rounded-lg text-sm flex-1 h-[36px]", size: "large", allowClear: true, onClick: setShowSearchTrue }), showSearch && (_jsx(Button, { onClick: setShowSearchFalse, variant: "outlined", className: "p-0 w-[36px] h-[36px] text-gray-500", children: _jsx(Icon, { icon: "close-b", size: 22 }) }))] }) }), _jsx("div", { id: "scrollableDiv", style: {
|
|
49
|
+
height: "100%",
|
|
50
|
+
overflow: "auto",
|
|
51
|
+
}, children: _jsxs(InfiniteScroll, { dataLength: (sessions === null || sessions === void 0 ? void 0 : sessions.length) || 0, next: fetchNextPage, hasMore: hasNextPage, loader: _jsx("div", { className: "flex items-center justify-center py-2", children: _jsx(Spin, {}) }), scrollableTarget: "scrollableDiv", children: [(sessions === null || sessions === void 0 ? void 0 : sessions.length) === 0 && (_jsx("div", { className: "flex items-center justify-center py-12", children: _jsx(Empty, { image: _jsx(Icon, { icon: "chat-square-b", size: 80, className: "text-gray-300" }), description: t("no_conversation") }) })), sessions === null || sessions === void 0 ? void 0 : sessions.map((session) => (_jsx(ConversationBySessionItem, { sessionItem: session }, session.conversationId)))] }) }), _jsx(Drawer, { open: showSearch, mask: false, closeIcon: false, styles: {
|
|
52
|
+
body: {
|
|
53
|
+
padding: 0,
|
|
54
|
+
},
|
|
55
|
+
}, getContainer: false, width: "100%", children: _jsx(SearchConversation, {}) })] }));
|
|
110
56
|
};
|
|
111
57
|
export default DeskConversationList;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FileCollection.d.ts","sourceRoot":"","sources":["../../../src/components/mediaCollection/FileCollection.tsx"],"names":[],"mappings":"AAcA,QAAA,MAAM,cAAc,+CA4GnB,CAAC;AAEF,eAAe,cAAc,CAAC"}
|
|
@@ -0,0 +1,52 @@
|
|
|
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
|
+
import { TOP_OFFSET } from ".";
|
|
14
|
+
const FileCollection = () => {
|
|
15
|
+
const { t } = useTranslation();
|
|
16
|
+
const selectedSourceId = useConversationStore((state) => state.selectedSourceId);
|
|
17
|
+
const { groupedData, fetchNextPage, hasNextPage, dataFlatten, isLoading } = useMediaCollection({
|
|
18
|
+
recvID: selectedSourceId,
|
|
19
|
+
contentType: MessageType.FileMessage,
|
|
20
|
+
});
|
|
21
|
+
const handleDownload = (url, fileName) => {
|
|
22
|
+
if (!url) {
|
|
23
|
+
console.warn("Không có link file để tải");
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
const link = document.createElement("a");
|
|
27
|
+
link.href = url;
|
|
28
|
+
if (fileName) {
|
|
29
|
+
link.setAttribute("download", fileName);
|
|
30
|
+
}
|
|
31
|
+
link.setAttribute("target", "_blank");
|
|
32
|
+
link.setAttribute("rel", "noopener noreferrer");
|
|
33
|
+
document.body.appendChild(link);
|
|
34
|
+
link.click();
|
|
35
|
+
link.remove();
|
|
36
|
+
};
|
|
37
|
+
const renderItem = useCallback((date, items) => {
|
|
38
|
+
return (_jsxs("div", { className: "px-3", children: [_jsx("span", { className: "text-sm font-medium text-gray-500", children: dayjs(date).format("DD MMMM, YYYY") }), _jsx("div", { className: "flex flex-col gap-1 mt-2", children: items.map((item) => {
|
|
39
|
+
var _a, _b, _c;
|
|
40
|
+
const fileContent = JSON.parse(((_a = item === null || item === void 0 ? void 0 : item.chatLog) === null || _a === void 0 ? void 0 : _a.content) || "{}");
|
|
41
|
+
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) || "", {
|
|
42
|
+
maxLength: 32,
|
|
43
|
+
}) }), _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));
|
|
44
|
+
}) })] }, date));
|
|
45
|
+
}, []);
|
|
46
|
+
if (dataFlatten.length === 0 && !isLoading)
|
|
47
|
+
return _jsx(Empty, { description: t("no_media_files") });
|
|
48
|
+
if (isLoading)
|
|
49
|
+
return (_jsx("div", { className: "flex items-center justify-center", children: _jsx(Spin, {}) }));
|
|
50
|
+
return (_jsx("div", { id: "scrollableFileDiv", className: "h-full overflow-auto", style: { maxHeight: `calc(100vh - ${TOP_OFFSET}px)` }, 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)) }) }));
|
|
51
|
+
};
|
|
52
|
+
export default FileCollection;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ImageCollection.d.ts","sourceRoot":"","sources":["../../../src/components/mediaCollection/ImageCollection.tsx"],"names":[],"mappings":"AAaA,QAAA,MAAM,eAAe,+CAoHpB,CAAC;AAEF,eAAe,eAAe,CAAC"}
|
|
@@ -0,0 +1,51 @@
|
|
|
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 { Button, 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
|
+
import { TOP_OFFSET } from ".";
|
|
12
|
+
import { DownloadOutlined } from "@ant-design/icons";
|
|
13
|
+
const ImageCollection = () => {
|
|
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.PictureMessage,
|
|
19
|
+
});
|
|
20
|
+
const handleDownload = (imageUrl) => {
|
|
21
|
+
if (!imageUrl)
|
|
22
|
+
return;
|
|
23
|
+
const link = document.createElement("a");
|
|
24
|
+
link.href = imageUrl;
|
|
25
|
+
link.download = imageUrl.substring(imageUrl.lastIndexOf("/") + 1);
|
|
26
|
+
document.body.appendChild(link);
|
|
27
|
+
link.click();
|
|
28
|
+
document.body.removeChild(link);
|
|
29
|
+
};
|
|
30
|
+
const renderItem = useCallback((date, items) => {
|
|
31
|
+
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) => {
|
|
32
|
+
var _a, _b, _c, _d;
|
|
33
|
+
const imageContent = JSON.parse(((_a = item === null || item === void 0 ? void 0 : item.chatLog) === null || _a === void 0 ? void 0 : _a.content) || "{}");
|
|
34
|
+
const sourceUrl = ((_b = imageContent.sourcePicture) === null || _b === void 0 ? void 0 : _b.url) ||
|
|
35
|
+
((_c = imageContent.snapshotPicture) === null || _c === void 0 ? void 0 : _c.url);
|
|
36
|
+
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));
|
|
37
|
+
}) })] }, date));
|
|
38
|
+
}, []);
|
|
39
|
+
if (dataFlatten.length === 0 && !isLoading)
|
|
40
|
+
return _jsx(Empty, { description: t("no_media_files") });
|
|
41
|
+
if (isLoading)
|
|
42
|
+
return (_jsx("div", { className: "flex items-center justify-center", children: _jsx(Spin, {}) }));
|
|
43
|
+
return (_jsx("div", { id: "scrollableImageDiv", className: "h-full overflow-auto", style: { maxHeight: `calc(100vh - ${TOP_OFFSET}px)` }, children: _jsx(Image.PreviewGroup, { preview: {
|
|
44
|
+
toolbarRender: (originalNode, info) => {
|
|
45
|
+
var _a;
|
|
46
|
+
const imageUrl = (_a = info === null || info === void 0 ? void 0 : info.image) === null || _a === void 0 ? void 0 : _a.url;
|
|
47
|
+
return (_jsxs("div", { className: "flex flex-col justify-center gap-2", children: [originalNode, imageUrl && (_jsx(Button, { type: "primary", icon: _jsx(DownloadOutlined, {}), className: "self-center", onClick: () => handleDownload(imageUrl), children: t("download") }))] }));
|
|
48
|
+
},
|
|
49
|
+
}, children: _jsx(InfiniteScroll, { dataLength: dataFlatten.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)) }) }) }));
|
|
50
|
+
};
|
|
51
|
+
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":"AAcA,QAAA,MAAM,eAAe,+CA8HpB,CAAC;AAEF,eAAe,eAAe,CAAC"}
|
|
@@ -0,0 +1,50 @@
|
|
|
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
|
+
import { TOP_OFFSET } from ".";
|
|
14
|
+
const VideoCollection = () => {
|
|
15
|
+
const { t } = useTranslation();
|
|
16
|
+
const selectedSourceId = useConversationStore((state) => state.selectedSourceId);
|
|
17
|
+
const { groupedData, fetchNextPage, hasNextPage, dataFlatten, isLoading } = useMediaCollection({
|
|
18
|
+
recvID: selectedSourceId,
|
|
19
|
+
contentType: MessageType.VideoMessage,
|
|
20
|
+
});
|
|
21
|
+
const [open, { setTrue, setFalse }] = useBoolean(false);
|
|
22
|
+
const [currentIndex, setCurrentIndex] = useState(0);
|
|
23
|
+
const handleOpenPreview = (index) => {
|
|
24
|
+
setCurrentIndex(index);
|
|
25
|
+
setTrue();
|
|
26
|
+
};
|
|
27
|
+
const renderItem = useCallback((date, items) => {
|
|
28
|
+
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) => {
|
|
29
|
+
var _a, _b;
|
|
30
|
+
const videoContent = JSON.parse(((_a = item === null || item === void 0 ? void 0 : item.chatLog) === null || _a === void 0 ? void 0 : _a.content) || "{}");
|
|
31
|
+
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); });
|
|
32
|
+
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));
|
|
33
|
+
}) })] }, date));
|
|
34
|
+
}, []);
|
|
35
|
+
if (dataFlatten.length === 0 && !isLoading)
|
|
36
|
+
return _jsx(Empty, { description: t("no_media_files") });
|
|
37
|
+
if (isLoading)
|
|
38
|
+
return (_jsx("div", { className: "flex items-center justify-center", children: _jsx(Spin, {}) }));
|
|
39
|
+
return (_jsxs("div", { id: "scrollableVideoDiv", className: "h-full overflow-auto", style: { maxHeight: `calc(100vh - ${TOP_OFFSET}px)` }, 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: {
|
|
40
|
+
content: {
|
|
41
|
+
padding: 0,
|
|
42
|
+
},
|
|
43
|
+
}, children: _jsx(Carousel, { dots: true, infinite: false, initialSlide: currentIndex, afterChange: (i) => setCurrentIndex(i), children: dataFlatten.map((item, idx) => {
|
|
44
|
+
var _a;
|
|
45
|
+
const videoContent = JSON.parse(((_a = item === null || item === void 0 ? void 0 : item.chatLog) === null || _a === void 0 ? void 0 : _a.content) || "{}");
|
|
46
|
+
const sourceUrl = videoContent.videoUrl;
|
|
47
|
+
return (_jsx("div", { style: { textAlign: "center" }, children: _jsx("video", { src: sourceUrl, controls: true, autoPlay: idx === currentIndex, style: { width: "100%", maxHeight: "80vh" } }) }, idx));
|
|
48
|
+
}) }) })] }));
|
|
49
|
+
};
|
|
50
|
+
export default VideoCollection;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export declare enum MediaCollectionTabKey {
|
|
2
|
+
Image = "image",
|
|
3
|
+
Video = "video",
|
|
4
|
+
File = "file",
|
|
5
|
+
Link = "link"
|
|
6
|
+
}
|
|
7
|
+
export declare const TOP_OFFSET = 128;
|
|
8
|
+
declare const MediaCollection: () => import("react/jsx-runtime").JSX.Element;
|
|
9
|
+
export default MediaCollection;
|
|
10
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/mediaCollection/index.tsx"],"names":[],"mappings":"AAaA,oBAAY,qBAAqB;IAC/B,KAAK,UAAU;IACf,KAAK,UAAU;IACf,IAAI,SAAS;IACb,IAAI,SAAS;CACd;AAED,eAAO,MAAM,UAAU,MAAM,CAAC;AAE9B,QAAA,MAAM,eAAe,+CA8EpB,CAAC;AAEF,eAAe,eAAe,CAAC"}
|