@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.
Files changed (166) hide show
  1. package/dist/assets/conversationBg.png +0 -0
  2. package/dist/assets/images/conversationBg.png +0 -0
  3. package/dist/assets/images/imageFailed.png +0 -0
  4. package/dist/assets/sdk/sql-wasm.wasm +0 -0
  5. package/dist/assets/sdk/version +1 -0
  6. package/dist/assets/sdk/wasm_exec.js +575 -0
  7. package/dist/assets/svg/document.d.ts +2 -0
  8. package/dist/assets/svg/document.d.ts.map +1 -0
  9. package/dist/assets/svg/document.js +2 -0
  10. package/dist/assets/svg/document.tsx +37 -0
  11. package/dist/assets/svg/index.d.ts +2 -0
  12. package/dist/assets/svg/index.d.ts.map +1 -0
  13. package/dist/assets/svg/index.js +1 -0
  14. package/dist/assets/svg/index.ts +1 -0
  15. package/dist/components/chatBubble/ChatBubble.d.ts.map +1 -1
  16. package/dist/components/chatBubble/ChatBubble.js +6 -11
  17. package/dist/components/conversation/ConversationBySessionItem.d.ts +7 -0
  18. package/dist/components/conversation/ConversationBySessionItem.d.ts.map +1 -0
  19. package/dist/components/conversation/ConversationBySessionItem.js +97 -0
  20. package/dist/components/conversation/ConversationItemList.d.ts +7 -0
  21. package/dist/components/conversation/ConversationItemList.d.ts.map +1 -0
  22. package/dist/components/conversation/ConversationItemList.js +20 -0
  23. package/dist/components/conversation/DeskConversationList.d.ts +1 -5
  24. package/dist/components/conversation/DeskConversationList.d.ts.map +1 -1
  25. package/dist/components/conversation/DeskConversationList.js +33 -87
  26. package/dist/components/mediaCollection/FileCollection.d.ts +3 -0
  27. package/dist/components/mediaCollection/FileCollection.d.ts.map +1 -0
  28. package/dist/components/mediaCollection/FileCollection.js +52 -0
  29. package/dist/components/mediaCollection/ImageCollection.d.ts +3 -0
  30. package/dist/components/mediaCollection/ImageCollection.d.ts.map +1 -0
  31. package/dist/components/mediaCollection/ImageCollection.js +51 -0
  32. package/dist/components/mediaCollection/LinkCollection.d.ts +3 -0
  33. package/dist/components/mediaCollection/LinkCollection.d.ts.map +1 -0
  34. package/dist/components/mediaCollection/LinkCollection.js +8 -0
  35. package/dist/components/mediaCollection/VideoCollection.d.ts +3 -0
  36. package/dist/components/mediaCollection/VideoCollection.d.ts.map +1 -0
  37. package/dist/components/mediaCollection/VideoCollection.js +50 -0
  38. package/dist/components/mediaCollection/index.d.ts +10 -0
  39. package/dist/components/mediaCollection/index.d.ts.map +1 -0
  40. package/dist/components/mediaCollection/index.js +58 -0
  41. package/dist/components/message/MessageHeader.d.ts.map +1 -1
  42. package/dist/components/message/MessageHeader.js +2 -1
  43. package/dist/components/message/MessageList.d.ts.map +1 -1
  44. package/dist/components/message/MessageList.js +14 -2
  45. package/dist/components/message/footer/FilePreview.d.ts +0 -1
  46. package/dist/components/message/footer/FilePreview.d.ts.map +1 -1
  47. package/dist/components/message/footer/FilePreview.js +4 -4
  48. package/dist/components/message/footer/ToolbarPlugin.d.ts.map +1 -1
  49. package/dist/components/message/footer/ToolbarPlugin.js +3 -6
  50. package/dist/components/message/footer/index.js +1 -1
  51. package/dist/components/message/item/FileMessage.d.ts.map +1 -1
  52. package/dist/components/message/item/FileMessage.js +2 -1
  53. package/dist/components/message/item/ImageMessage.js +3 -3
  54. package/dist/components/message/item/TextMessage.js +2 -2
  55. package/dist/components/message/item/index.js +1 -1
  56. package/dist/components/searchConversation/SearchAll.d.ts +3 -0
  57. package/dist/components/searchConversation/SearchAll.d.ts.map +1 -0
  58. package/dist/components/searchConversation/SearchAll.js +8 -0
  59. package/dist/components/searchConversation/SearchConversationAsMessages.d.ts +3 -0
  60. package/dist/components/searchConversation/SearchConversationAsMessages.d.ts.map +1 -0
  61. package/dist/components/searchConversation/SearchConversationAsMessages.js +8 -0
  62. package/dist/components/searchConversation/SearchConversationAsUsers.d.ts +3 -0
  63. package/dist/components/searchConversation/SearchConversationAsUsers.d.ts.map +1 -0
  64. package/dist/components/searchConversation/SearchConversationAsUsers.js +8 -0
  65. package/dist/components/searchConversation/index.d.ts +8 -0
  66. package/dist/components/searchConversation/index.d.ts.map +1 -0
  67. package/dist/components/searchConversation/index.js +38 -0
  68. package/dist/components/session/AssignedSessionFilter.js +9 -10
  69. package/dist/components/session/DeskAssignedSession.d.ts +3 -0
  70. package/dist/components/session/DeskAssignedSession.d.ts.map +1 -0
  71. package/dist/components/session/DeskAssignedSession.js +118 -0
  72. package/dist/constants/images.d.ts +5 -0
  73. package/dist/constants/images.d.ts.map +1 -0
  74. package/dist/constants/images.js +7 -0
  75. package/dist/context/ChatContext.d.ts +2 -1
  76. package/dist/context/ChatContext.d.ts.map +1 -1
  77. package/dist/context/ChatContext.js +17 -24
  78. package/dist/hooks/collection/useMediaCollection.d.ts +229 -0
  79. package/dist/hooks/collection/useMediaCollection.d.ts.map +1 -0
  80. package/dist/hooks/collection/useMediaCollection.js +66 -0
  81. package/dist/hooks/common/useIsMobile.d.ts +2 -0
  82. package/dist/hooks/common/useIsMobile.d.ts.map +1 -0
  83. package/dist/hooks/common/useIsMobile.js +15 -0
  84. package/dist/hooks/conversation/useConversation.js +1 -1
  85. package/dist/hooks/conversation/useConversationStore.d.ts +3 -2
  86. package/dist/hooks/conversation/useConversationStore.d.ts.map +1 -1
  87. package/dist/hooks/global/useGlobalEvent.d.ts.map +1 -1
  88. package/dist/hooks/global/useGlobalEvent.js +55 -6
  89. package/dist/hooks/init/useChatToken.d.ts +2 -0
  90. package/dist/hooks/init/useChatToken.d.ts.map +1 -0
  91. package/dist/hooks/init/useChatToken.js +11 -0
  92. package/dist/hooks/message/useSendMessage.d.ts.map +1 -1
  93. package/dist/hooks/message/useSendMessage.js +31 -12
  94. package/dist/hooks/search/useSearchConversation.d.ts +2 -0
  95. package/dist/hooks/search/useSearchConversation.d.ts.map +1 -0
  96. package/dist/hooks/search/useSearchConversation.js +1 -0
  97. package/dist/hooks/session/useGetSessionByTagOrStatus.d.ts +220 -0
  98. package/dist/hooks/session/useGetSessionByTagOrStatus.d.ts.map +1 -0
  99. package/dist/hooks/session/useGetSessionByTagOrStatus.js +72 -0
  100. package/dist/hooks/session/useGetSessionSummary.d.ts +3 -0
  101. package/dist/hooks/session/useGetSessionSummary.d.ts.map +1 -0
  102. package/dist/hooks/session/useGetSessionSummary.js +14 -0
  103. package/dist/index.d.ts +5 -5
  104. package/dist/index.d.ts.map +1 -1
  105. package/dist/index.js +3 -4
  106. package/dist/layout/index.d.ts.map +1 -1
  107. package/dist/layout/index.js +2 -5
  108. package/dist/locales/i18n.d.ts +3 -0
  109. package/dist/locales/i18n.d.ts.map +1 -0
  110. package/dist/locales/i18n.js +16 -0
  111. package/dist/locales/i18n.ts +18 -0
  112. package/dist/locales/vi/common.json +24 -0
  113. package/dist/screens/chatBubble/index.d.ts.map +1 -1
  114. package/dist/screens/chatBubble/index.js +20 -10
  115. package/dist/screens/deskMessage/index.d.ts.map +1 -1
  116. package/dist/screens/deskMessage/index.js +4 -4
  117. package/dist/services/api.d.ts +2 -0
  118. package/dist/services/api.d.ts.map +1 -0
  119. package/dist/services/api.js +16 -0
  120. package/dist/services/query.d.ts +7 -0
  121. package/dist/services/query.d.ts.map +1 -0
  122. package/dist/services/query.js +6 -0
  123. package/dist/services/routes.d.ts +15 -0
  124. package/dist/services/routes.d.ts.map +1 -0
  125. package/dist/services/routes.js +14 -0
  126. package/dist/store/auth.d.ts +4 -0
  127. package/dist/store/auth.d.ts.map +1 -0
  128. package/dist/store/auth.js +16 -0
  129. package/dist/store/conversation.d.ts.map +1 -1
  130. package/dist/store/conversation.js +0 -11
  131. package/dist/store/session.d.ts +8 -0
  132. package/dist/store/session.d.ts.map +1 -0
  133. package/dist/store/session.js +10 -0
  134. package/dist/styles/global.css +1 -1
  135. package/dist/types/chat.d.ts +10 -4
  136. package/dist/types/chat.d.ts.map +1 -1
  137. package/dist/types/dto.d.ts +55 -0
  138. package/dist/types/dto.d.ts.map +1 -0
  139. package/dist/types/dto.js +1 -0
  140. package/dist/utils/common.d.ts +2 -0
  141. package/dist/utils/common.d.ts.map +1 -0
  142. package/dist/utils/common.js +12 -0
  143. package/dist/utils/imCommon.d.ts +0 -1
  144. package/dist/utils/imCommon.d.ts.map +1 -1
  145. package/dist/utils/imCommon.js +0 -5
  146. package/package.json +15 -3
  147. package/dist/assets/openIM.wasm +0 -0
  148. package/dist/components/ChatBubble.d.ts +0 -10
  149. package/dist/components/ChatBubble.d.ts.map +0 -1
  150. package/dist/components/ChatBubble.js +0 -28
  151. package/dist/components/message/MessageItem.d.ts +0 -7
  152. package/dist/components/message/MessageItem.d.ts.map +0 -1
  153. package/dist/components/message/MessageItem.js +0 -21
  154. package/dist/components/message/footer/BottomSection.d.ts +0 -3
  155. package/dist/components/message/footer/BottomSection.d.ts.map +0 -1
  156. package/dist/components/message/footer/BottomSection.js +0 -6
  157. package/dist/screens/desk-message/index.d.ts +0 -3
  158. package/dist/screens/desk-message/index.d.ts.map +0 -1
  159. package/dist/screens/desk-message/index.js +0 -15
  160. package/dist/tsconfig.tsbuildinfo +0 -1
  161. package/dist/types/index.d.ts +0 -1
  162. package/dist/types/index.d.ts.map +0 -1
  163. package/dist/types/index.js +0 -1
  164. package/dist/types/sdk.d.ts +0 -1
  165. package/dist/types/sdk.d.ts.map +0 -1
  166. 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 { useEffect, useState } from "react";
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 [isMobile, setIsMobile] = useState(false);
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", { style: { width: 400, height: 640 }, 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: {
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
- }, onClick: toggleChat, className: className }) }));
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
- interface DeskConversationListProps {
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":"AA0FA,UAAU,yBAAyB;IACjC,oBAAoB,CAAC,EAAE,CAAC,cAAc,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1E,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,QAAA,MAAM,oBAAoB,GAAI,sCAG3B,yBAAyB,4CAqK3B,CAAC;AAEF,eAAe,oBAAoB,CAAC"}
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, Avatar, Badge, Empty } from "antd";
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
- const parseLatestMessage = (latestMsg, currentUserId) => {
10
- var _a;
11
- if (!latestMsg)
12
- return "";
13
- try {
14
- const msgData = JSON.parse(latestMsg);
15
- // Check for text message (textElem)
16
- if ((_a = msgData.textElem) === null || _a === void 0 ? void 0 : _a.content) {
17
- const isMe = currentUserId && msgData.sendID === currentUserId;
18
- const sender = isMe ? "Me" : (msgData === null || msgData === void 0 ? void 0 : msgData.senderNickname) || msgData.sendID;
19
- return `${sender}: ${msgData.textElem.content}`;
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
- console.log({ conversationList });
78
- // Transform real conversation data from the API
79
- const conversations = transformConversationData(conversationList || [], user === null || user === void 0 ? void 0 : user.userID);
80
- const handleConversationClick = (conversation) => {
81
- setConversationData(conversation);
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 = conversations.find((conv) => conv.conversationID === threadId);
35
+ const selectedConversation = conversationList.find((conv) => conv.conversationID === threadId);
93
36
  if (selectedConversation) {
94
37
  setConversationData(selectedConversation);
95
38
  }
96
39
  }
97
- else if (conversations.length > 0) {
98
- setSelectedConversationId(conversations[0].conversationID);
99
- setConversationData(conversations[0]);
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", conversations[0].conversationID);
44
+ newSearchParams.set("threadId", conversationList[0].conversationID);
102
45
  router.replace(`${pathname}?${newSearchParams.toString()}`);
103
46
  }
104
- }, [searchParams, conversations.length]);
105
- return (_jsxs("div", { className: `flex flex-col h-full bg-white border-r border-gray-200 w-[320px] ${className}`, children: [_jsx("div", { className: "p-3 border-b border-gray-200", children: _jsx(Input, { placeholder: "T\u00ECm ki\u1EBFm", prefix: _jsx(Icon, { icon: "search-o", size: 18, className: "text-gray-400" }), value: searchQuery, onChange: (e) => setSearchQuery(e.target.value), className: "rounded-lg" }) }), _jsxs("div", { className: "flex-1 overflow-y-auto", children: [conversations.map((conversation) => (_jsxs("div", { onClick: () => handleConversationClick(conversation), className: `relative p-3 border-b border-gray-100 hover:bg-gray-50 cursor-pointer transition-colors ${selectedConversationId === conversation.conversationID
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
108
- ? "Thử tìm kiếm với từ khóa khác"
109
- : "Chưa có cuộc trò chuyện nào" })] }) }) }))] })] }));
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,3 @@
1
+ declare const FileCollection: () => import("react/jsx-runtime").JSX.Element;
2
+ export default FileCollection;
3
+ //# sourceMappingURL=FileCollection.d.ts.map
@@ -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,3 @@
1
+ declare const ImageCollection: () => import("react/jsx-runtime").JSX.Element;
2
+ export default ImageCollection;
3
+ //# sourceMappingURL=ImageCollection.d.ts.map
@@ -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,3 @@
1
+ declare const LinkCollection: () => import("react/jsx-runtime").JSX.Element;
2
+ export default LinkCollection;
3
+ //# sourceMappingURL=LinkCollection.d.ts.map
@@ -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,3 @@
1
+ declare const VideoCollection: () => import("react/jsx-runtime").JSX.Element;
2
+ export default VideoCollection;
3
+ //# sourceMappingURL=VideoCollection.d.ts.map
@@ -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"}