@droppii-org/chat-sdk 0.0.29 → 0.0.31

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