@droppii-org/chat-sdk 0.0.20 → 0.0.21

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 (57) hide show
  1. package/dist/assets/openIM.wasm +0 -0
  2. package/dist/components/ChatBubble.d.ts +10 -0
  3. package/dist/components/ChatBubble.d.ts.map +1 -0
  4. package/dist/components/ChatBubble.js +28 -0
  5. package/dist/components/conversation/DeskConversationList.d.ts.map +1 -1
  6. package/dist/components/conversation/DeskConversationList.js +10 -10
  7. package/dist/components/message/MessageHeader.d.ts +8 -0
  8. package/dist/components/message/MessageHeader.d.ts.map +1 -0
  9. package/dist/components/message/MessageHeader.js +9 -0
  10. package/dist/components/message/MessageItem.d.ts +7 -0
  11. package/dist/components/message/MessageItem.d.ts.map +1 -0
  12. package/dist/components/message/MessageItem.js +21 -0
  13. package/dist/components/message/MessageList.d.ts +1 -1
  14. package/dist/components/message/MessageList.d.ts.map +1 -1
  15. package/dist/components/message/MessageList.js +42 -92
  16. package/dist/components/message/footer/BottomSection.d.ts +3 -0
  17. package/dist/components/message/footer/BottomSection.d.ts.map +1 -0
  18. package/dist/components/message/footer/BottomSection.js +6 -0
  19. package/dist/components/message/footer/index.d.ts +3 -0
  20. package/dist/components/message/footer/index.d.ts.map +1 -0
  21. package/dist/components/message/footer/index.js +25 -0
  22. package/dist/context/ChatContext.d.ts.map +1 -1
  23. package/dist/context/ChatContext.js +5 -2
  24. package/dist/hooks/conversation/useConversation.d.ts +1 -0
  25. package/dist/hooks/conversation/useConversation.d.ts.map +1 -1
  26. package/dist/hooks/conversation/useConversation.js +12 -4
  27. package/dist/hooks/conversation/useConversationStore.d.ts +11 -0
  28. package/dist/hooks/conversation/useConversationStore.d.ts.map +1 -0
  29. package/dist/hooks/{zustand/useMessageStore.js → conversation/useConversationStore.js} +4 -2
  30. package/dist/hooks/global/useGlobalEvent.d.ts +2 -0
  31. package/dist/hooks/global/useGlobalEvent.d.ts.map +1 -0
  32. package/dist/hooks/global/useGlobalEvent.js +78 -0
  33. package/dist/hooks/message/useMessage.d.ts +17 -8
  34. package/dist/hooks/message/useMessage.d.ts.map +1 -1
  35. package/dist/hooks/message/useMessage.js +95 -49
  36. package/dist/hooks/message/useSendMessage.d.ts +1 -1
  37. package/dist/hooks/message/useSendMessage.d.ts.map +1 -1
  38. package/dist/hooks/message/useSendMessage.js +15 -9
  39. package/dist/layout/index.d.ts +7 -0
  40. package/dist/layout/index.d.ts.map +1 -0
  41. package/dist/layout/index.js +11 -0
  42. package/dist/screens/desk-message/index.d.ts +3 -0
  43. package/dist/screens/desk-message/index.d.ts.map +1 -0
  44. package/dist/screens/desk-message/index.js +15 -0
  45. package/dist/screens/deskMessage/index.d.ts.map +1 -1
  46. package/dist/screens/deskMessage/index.js +3 -3
  47. package/dist/styles/global.css +1 -1
  48. package/dist/tsconfig.tsbuildinfo +1 -0
  49. package/dist/types/chat.d.ts +7 -0
  50. package/dist/types/chat.d.ts.map +1 -1
  51. package/dist/types/chat.js +8 -0
  52. package/dist/utils/events.d.ts +13 -0
  53. package/dist/utils/events.d.ts.map +1 -0
  54. package/dist/utils/events.js +4 -0
  55. package/package.json +14 -6
  56. package/dist/hooks/zustand/useMessageStore.d.ts +0 -9
  57. package/dist/hooks/zustand/useMessageStore.d.ts.map +0 -1
Binary file
@@ -0,0 +1,10 @@
1
+ import { SessionType } from "@openim/wasm-client-sdk";
2
+ interface ChatBubbleProps {
3
+ conversationId: string;
4
+ sourceID: string;
5
+ sessionType: SessionType;
6
+ className?: string;
7
+ }
8
+ declare const ChatBubble: ({ conversationId, sourceID, sessionType, className, }: ChatBubbleProps) => import("react/jsx-runtime").JSX.Element;
9
+ export default ChatBubble;
10
+ //# sourceMappingURL=ChatBubble.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ChatBubble.d.ts","sourceRoot":"","sources":["../../src/components/ChatBubble.tsx"],"names":[],"mappings":"AAKA,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAGtD,UAAU,eAAe;IACvB,cAAc,EAAE,MAAM,CAAC;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,WAAW,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,QAAA,MAAM,UAAU,GAAI,uDAKjB,eAAe,4CAmDjB,CAAC;AAEF,eAAe,UAAU,CAAC"}
@@ -0,0 +1,28 @@
1
+ "use client";
2
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { useState } from "react";
4
+ import { FloatButton, Drawer } from "antd";
5
+ import { MessageOutlined, CloseOutlined } from "@ant-design/icons";
6
+ import MessageList from "./message/MessageList";
7
+ import { useConversationDetail } from "../hooks/conversation/useConversation";
8
+ const ChatBubble = ({ conversationId, sourceID, sessionType, className, }) => {
9
+ const { conversationDetail } = useConversationDetail({
10
+ sourceID,
11
+ sessionType,
12
+ });
13
+ const [isOpen, setIsOpen] = useState(false);
14
+ const toggleChat = () => {
15
+ setIsOpen(!isOpen);
16
+ };
17
+ return (_jsxs(_Fragment, { children: [_jsx(FloatButton, { icon: isOpen ? _jsx(CloseOutlined, {}) : _jsx(MessageOutlined, {}), type: "primary", style: {
18
+ right: 24,
19
+ bottom: 24,
20
+ width: 60,
21
+ height: 60,
22
+ }, onClick: toggleChat, className: className }), _jsx(Drawer, { placement: "right", onClose: () => setIsOpen(false), open: isOpen, mask: true, closable: false, styles: {
23
+ body: { padding: 0 },
24
+ }, classNames: {
25
+ wrapper: "!z-[9999]",
26
+ }, children: _jsx(MessageList, { conversationId: conversationId, conversationData: conversationDetail, className: "flex-1", onClose: () => setIsOpen(false) }) })] }));
27
+ };
28
+ export default ChatBubble;
@@ -1 +1 @@
1
- {"version":3,"file":"DeskConversationList.d.ts","sourceRoot":"","sources":["../../../src/components/conversation/DeskConversationList.tsx"],"names":[],"mappings":"AAwGA,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,4CAiL3B,CAAC;AAEF,eAAe,oBAAoB,CAAC"}
1
+ {"version":3,"file":"DeskConversationList.d.ts","sourceRoot":"","sources":["../../../src/components/conversation/DeskConversationList.tsx"],"names":[],"mappings":"AAuGA,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,4CAuL3B,CAAC;AAEF,eAAe,oBAAoB,CAAC"}
@@ -7,8 +7,7 @@ import { SessionType } from "@openim/wasm-client-sdk";
7
7
  import { useConversationList } from "../../hooks/conversation/useConversation";
8
8
  import { Icon } from "../icon";
9
9
  import { useChatContext } from "../../context/ChatContext";
10
- import useMessageStore from "../../hooks/zustand/useMessageStore";
11
- import { useMessage } from "../../hooks/message/useMessage";
10
+ import useConversationStore from "../../hooks/conversation/useConversationStore";
12
11
  const parseLatestMessage = (latestMsg, currentUserId) => {
13
12
  var _a;
14
13
  if (!latestMsg)
@@ -74,16 +73,17 @@ const DeskConversationList = ({ onConversationSelect, className = "", }) => {
74
73
  const pathname = usePathname();
75
74
  const searchParams = useSearchParams();
76
75
  const { user } = useChatContext();
77
- const selectedThreadId = useMessageStore((state) => state.selectedThreadId);
78
- const setSelectedThreadId = useMessageStore((state) => state.setSelectedThreadId);
79
- const setSelectedSourceId = useMessageStore((state) => state.setSelectedSourceId);
80
- const { markConversationMessageAsRead } = useMessage(selectedThreadId);
81
- const { conversationList } = useConversationList(selectedThreadId);
76
+ const setConversationData = useConversationStore((state) => state.setConversationData);
77
+ const selectedThreadId = useConversationStore((state) => state.selectedThreadId);
78
+ const setSelectedThreadId = useConversationStore((state) => state.setSelectedThreadId);
79
+ const setSelectedSourceId = useConversationStore((state) => state.setSelectedSourceId);
80
+ const { conversationList, markConversationMessageAsRead } = useConversationList(selectedThreadId);
82
81
  // Transform real conversation data from the API
83
82
  const conversations = transformConversationData(conversationList || [], user === null || user === void 0 ? void 0 : user.userID);
84
83
  const filteredConversations = conversations.filter((conv) => conv.name.toLowerCase().includes(searchQuery.toLowerCase()) ||
85
84
  conv.lastMessage.toLowerCase().includes(searchQuery.toLowerCase()));
86
85
  const handleConversationClick = (conversation) => {
86
+ setConversationData(conversation);
87
87
  const newSearchParams = new URLSearchParams(searchParams);
88
88
  newSearchParams.set("threadId", conversation.id);
89
89
  router.push(`${pathname}?${newSearchParams.toString()}`);
@@ -114,11 +114,11 @@ const DeskConversationList = ({ onConversationSelect, className = "", }) => {
114
114
  }, [searchParams, conversations.length]);
115
115
  useEffect(() => {
116
116
  if (!!selectedThreadId) {
117
- markConversationMessageAsRead();
117
+ markConversationMessageAsRead(selectedThreadId);
118
118
  onSetSelectedSourceId();
119
119
  }
120
- }, [selectedThreadId, onSetSelectedSourceId, markConversationMessageAsRead]);
121
- return (_jsxs("div", { className: `flex flex-col h-full bg-white border-r border-gray-200 ${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 ${selectedThreadId === conversation.threadId
120
+ }, [selectedThreadId, onSetSelectedSourceId]);
121
+ 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 ${selectedThreadId === conversation.threadId
122
122
  ? "bg-blue-50"
123
123
  : "bg-white"}`, children: [selectedThreadId === 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 }) }) }), _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
124
124
  ? "Thử tìm kiếm với từ khóa khác"
@@ -0,0 +1,8 @@
1
+ import { ConversationItem } from "@openim/wasm-client-sdk";
2
+ interface MessageHeaderProps {
3
+ conversationData: ConversationItem | null;
4
+ onClose?: () => void;
5
+ }
6
+ declare const MessageHeader: ({ conversationData, onClose }: MessageHeaderProps) => import("react/jsx-runtime").JSX.Element;
7
+ export default MessageHeader;
8
+ //# sourceMappingURL=MessageHeader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MessageHeader.d.ts","sourceRoot":"","sources":["../../../src/components/message/MessageHeader.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAI3D,UAAU,kBAAkB;IAC1B,gBAAgB,EAAE,gBAAgB,GAAG,IAAI,CAAC;IAC1C,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB;AAED,QAAA,MAAM,aAAa,GAAI,+BAA+B,kBAAkB,4CA6CvE,CAAC;AAEF,eAAe,aAAa,CAAC"}
@@ -0,0 +1,9 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { Avatar, Button } from "antd";
4
+ import { Icon } from "../icon";
5
+ const MessageHeader = ({ conversationData, onClose }) => {
6
+ var _a, _b;
7
+ return (_jsxs("div", { className: "px-4 py-3 flex items-center border-b gap-3", children: [_jsx(Avatar, { src: conversationData === null || conversationData === void 0 ? void 0 : conversationData.faceURL, size: "large", children: ((_b = (_a = conversationData === null || conversationData === void 0 ? void 0 : conversationData.showName) === null || _a === void 0 ? void 0 : _a.charAt) === null || _b === void 0 ? void 0 : _b.call(_a, 0)) || "A" }), _jsxs("div", { className: "flex flex-col flex-1", children: [_jsx("p", { children: (conversationData === null || conversationData === void 0 ? void 0 : conversationData.showName) || "" }), _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 }) }))] })] }));
8
+ };
9
+ export default MessageHeader;
@@ -0,0 +1,7 @@
1
+ import { GroupMessageItem } from "../../types/chat";
2
+ interface MessageItemProps {
3
+ groupMessage: GroupMessageItem;
4
+ }
5
+ declare const MessageItem: ({ groupMessage }: MessageItemProps) => import("react/jsx-runtime").JSX.Element;
6
+ export default MessageItem;
7
+ //# sourceMappingURL=MessageItem.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MessageItem.d.ts","sourceRoot":"","sources":["../../../src/components/message/MessageItem.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAUpD,UAAU,gBAAgB;IACxB,YAAY,EAAE,gBAAgB,CAAC;CAChC;AACD,QAAA,MAAM,WAAW,GAAI,kBAAkB,gBAAgB,4CAwEtD,CAAC;AAEF,eAAe,WAAW,CAAC"}
@@ -0,0 +1,21 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import dayjs from "dayjs";
3
+ import clsx from "clsx";
4
+ import { Avatar } from "antd";
5
+ import isToday from "dayjs/plugin/isToday";
6
+ import { useChatContext } from "../../context/ChatContext";
7
+ import { SessionType } from "@openim/wasm-client-sdk";
8
+ dayjs.extend(isToday);
9
+ const MessageItem = ({ groupMessage }) => {
10
+ const { user } = useChatContext();
11
+ const messagesInGroup = (groupMessage === null || groupMessage === void 0 ? void 0 : groupMessage.messages) || [];
12
+ const isToday = dayjs(groupMessage === null || groupMessage === void 0 ? void 0 : groupMessage.sendTime).isToday();
13
+ return (_jsxs("div", { className: "flex flex-col gap-2 my-4 mx-3 sm:mx-4", children: [_jsx("div", { className: "flex justify-center", children: _jsx("span", { className: "text-xs text-gray-600 text-center bg-neutral-100 px-2 py-1 rounded-full", children: dayjs(groupMessage === null || groupMessage === void 0 ? void 0 : groupMessage.sendTime).format(isToday ? "HH:mm" : "HH:mm, DD MMMM") }) }), messagesInGroup === null || messagesInGroup === void 0 ? void 0 : messagesInGroup.map((message, messageIndex) => {
14
+ var _a, _b, _c;
15
+ const isMine = (message === null || message === void 0 ? void 0 : message.sendID) === (user === null || user === void 0 ? void 0 : user.userID);
16
+ const showAvatar = messageIndex === messagesInGroup.length - 1;
17
+ const showSenderName = messageIndex === 0 && (message === null || message === void 0 ? void 0 : message.sessionType) === SessionType.Group;
18
+ return (_jsx("div", { className: clsx("flex", isMine ? "justify-end" : "justify-start"), children: _jsxs("div", { className: clsx("flex items-end gap-2", isMine ? "justify-end" : "justify-start"), children: [!isMine && (_jsx("div", { className: "flex items-center justify-center w-[32px] h-[32px]", children: showAvatar && (_jsx(Avatar, { children: ((_b = (_a = message === null || message === void 0 ? void 0 : message.senderNickname) === null || _a === void 0 ? void 0 : _a.charAt) === null || _b === void 0 ? void 0 : _b.call(_a, 0)) || "A" })) })), _jsxs("div", { className: "flex flex-col items-start flex-[0.8]", children: [!isMine && showSenderName && (_jsx("span", { className: "text-xs text-gray-500 mb-1 px-3", children: message === null || message === void 0 ? void 0 : message.senderNickname })), _jsxs("div", { className: clsx("px-3 py-2 rounded-2xl max-w-full break-words flex flex-col text-gray-900", isMine ? "bg-blue-100" : "bg-gray-100"), children: [_jsx("p", { className: "text-sm sm:text-base whitespace-pre-wrap", children: ((_c = message === null || message === void 0 ? void 0 : message.textElem) === null || _c === void 0 ? void 0 : _c.content) || "Tin nhắn không khả dụng" }), _jsx("span", { className: clsx("text-xs text-gray-500 text-right text-gray-500"), children: dayjs(message === null || message === void 0 ? void 0 : message.sendTime).format("HH:mm") })] })] })] }) }, message === null || message === void 0 ? void 0 : message.clientMsgID));
19
+ })] }, groupMessage === null || groupMessage === void 0 ? void 0 : groupMessage.groupMessageID));
20
+ };
21
+ export default MessageItem;
@@ -1,4 +1,4 @@
1
- import { type ConversationItem } from "@openim/wasm-client-sdk";
1
+ import { ConversationItem } from "@openim/wasm-client-sdk";
2
2
  interface MessageListProps {
3
3
  conversationId: string;
4
4
  conversationData: ConversationItem | null;
@@ -1 +1 @@
1
- {"version":3,"file":"MessageList.d.ts","sourceRoot":"","sources":["../../../src/components/message/MessageList.tsx"],"names":[],"mappings":"AACA,OAAO,EACL,KAAK,gBAAgB,EAGtB,MAAM,yBAAyB,CAAC;AAkBjC,UAAU,gBAAgB;IACxB,cAAc,EAAE,MAAM,CAAC;IACvB,gBAAgB,EAAE,gBAAgB,GAAG,IAAI,CAAC;IAC1C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB;AAED,QAAA,MAAM,WAAW,GAAI,OAAO,gBAAgB,4CA0O3C,CAAC;AAEF,eAAe,WAAW,CAAC"}
1
+ {"version":3,"file":"MessageList.d.ts","sourceRoot":"","sources":["../../../src/components/message/MessageList.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAe,MAAM,yBAAyB,CAAC;AAgBxE,UAAU,gBAAgB;IACxB,cAAc,EAAE,MAAM,CAAC;IACvB,gBAAgB,EAAE,gBAAgB,GAAG,IAAI,CAAC;IAC1C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB;AAED,QAAA,MAAM,WAAW,GAAI,OAAO,gBAAgB,4CAqH3C,CAAC;AAEF,eAAe,WAAW,CAAC"}
@@ -1,35 +1,23 @@
1
1
  "use client";
2
- var __rest = (this && this.__rest) || function (s, e) {
3
- var t = {};
4
- for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
5
- t[p] = s[p];
6
- if (s != null && typeof Object.getOwnPropertySymbols === "function")
7
- for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
8
- if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
9
- t[p[i]] = s[p[i]];
10
- }
11
- return t;
12
- };
13
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
14
- import { SessionType, } from "@openim/wasm-client-sdk";
15
- import { useChatContext } from "../../context/ChatContext";
3
+ import { SessionType } from "@openim/wasm-client-sdk";
16
4
  import { useMessage } from "../../hooks/message/useMessage";
17
- import { Avatar, Button, Input, Tooltip } from "antd";
5
+ import { Button, Input, Spin, Tooltip } from "antd";
18
6
  import { Icon } from "../icon";
19
7
  import { useCallback, useEffect, useRef, useState } from "react";
20
- import clsx from "clsx";
21
- import { useSendMessage, } from "../../hooks/message/useSendMessage";
22
- import InfiniteLoader from "react-window-infinite-loader";
23
- import { VariableSizeList as List, } from "react-window";
24
- import AutoSizer from "react-virtualized-auto-sizer";
8
+ import { useSendMessage } from "../../hooks/message/useSendMessage";
9
+ import dayjs from "dayjs";
10
+ import isToday from "dayjs/plugin/isToday";
11
+ import emitter from "../../utils/events";
12
+ import MessageItem from "./MessageItem";
13
+ import InfiniteScroll from "react-infinite-scroll-component";
14
+ import MessageHeader from "./MessageHeader";
15
+ dayjs.extend(isToday);
25
16
  const MessageList = (props) => {
26
17
  var _a, _b;
27
- const { conversationId, conversationData, onClose } = props;
28
- const { messageList, groupMessages, refetch } = useMessage(conversationId);
18
+ const { conversationData, onClose, conversationId } = props;
29
19
  const scrollRef = useRef(null);
30
- const shouldScrollToBottomRef = useRef(true);
31
- const lastMessageCountRef = useRef((messageList === null || messageList === void 0 ? void 0 : messageList.length) || 0);
32
- const { user } = useChatContext();
20
+ const { getMoreOldMessages, moreOldLoading, loadState, latestLoadState } = useMessage(conversationId);
33
21
  const { sendTextMessage } = useSendMessage({
34
22
  recvID: (conversationData === null || conversationData === void 0 ? void 0 : conversationData.conversationType) !== SessionType.Single
35
23
  ? ""
@@ -40,78 +28,40 @@ const MessageList = (props) => {
40
28
  });
41
29
  const [textMessage, setTextMessage] = useState("");
42
30
  const [composing, setComposing] = useState(false);
43
- const [showScrollToBottomButton, setShowScrollToBottomButton] = useState(false);
44
- const scrollToBottom = useCallback((force = false) => {
45
- if (scrollRef.current) {
46
- scrollRef.current.scrollTop = scrollRef.current.scrollHeight;
47
- if (force) {
48
- shouldScrollToBottomRef.current = true; // If forced, ensure auto-scroll is re-enabled
49
- }
50
- }
51
- }, []);
52
- const handleScroll = useCallback(() => {
53
- if (!scrollRef.current)
54
- return;
55
- const { scrollTop, scrollHeight, clientHeight } = scrollRef.current;
56
- const distanceFromBottom = scrollHeight - scrollTop - clientHeight;
57
- const SCROLL_UP_THRESHOLD = 200; // If user scrolls up more than 200px from bottom, disable auto-scroll
58
- const SCROLL_DOWN_THRESHOLD = 5; // If user scrolls within 5px of bottom, re-enable auto-scroll
59
- if (distanceFromBottom > SCROLL_UP_THRESHOLD) {
60
- shouldScrollToBottomRef.current = false;
61
- }
62
- else if (distanceFromBottom <= SCROLL_DOWN_THRESHOLD) {
63
- shouldScrollToBottomRef.current = true;
64
- }
65
- // Show button if not at bottom AND auto-scroll is disabled
66
- setShowScrollToBottomButton(distanceFromBottom > SCROLL_DOWN_THRESHOLD &&
67
- !shouldScrollToBottomRef.current);
68
- }, []);
31
+ const scrollToBottom = () => {
32
+ setTimeout(() => {
33
+ var _a, _b;
34
+ (_a = scrollRef.current) === null || _a === void 0 ? void 0 : _a.scrollTo({
35
+ top: (_b = scrollRef.current) === null || _b === void 0 ? void 0 : _b.scrollHeight,
36
+ behavior: "smooth",
37
+ });
38
+ });
39
+ };
69
40
  const onSendTextMessage = useCallback(async () => {
41
+ var _a;
42
+ const messageList = (_a = latestLoadState.current) === null || _a === void 0 ? void 0 : _a.messageList;
70
43
  setTextMessage("");
71
44
  const lastMessage = messageList === null || messageList === void 0 ? void 0 : messageList[(messageList === null || messageList === void 0 ? void 0 : messageList.length) - 1];
72
- const res = await sendTextMessage(textMessage, lastMessage);
73
- if (res) {
74
- refetch();
75
- }
76
- }, [textMessage, sendTextMessage, refetch, messageList]);
77
- const renderMessageItem = useCallback((listItemProps) => {
78
- const { index } = listItemProps;
79
- const groupMessage = groupMessages === null || groupMessages === void 0 ? void 0 : groupMessages[index];
80
- const messagesInGroup = (groupMessage === null || groupMessage === void 0 ? void 0 : groupMessage.messages) || [];
81
- return (_jsxs("div", { children: [_jsx("div", { children: groupMessage === null || groupMessage === void 0 ? void 0 : groupMessage.sendTime }), messagesInGroup === null || messagesInGroup === void 0 ? void 0 : messagesInGroup.map((message) => {
82
- var _a, _b, _c;
83
- const isMine = (message === null || message === void 0 ? void 0 : message.sendID) === (user === null || user === void 0 ? void 0 : user.userID);
84
- return (_jsx("div", { className: clsx("flex", isMine ? "justify-end" : "justify-start"), children: _jsxs("div", { className: "flex items-end gap-2", children: [!isMine && (_jsx(Avatar, { children: ((_b = (_a = message === null || message === void 0 ? void 0 : message.senderNickname) === null || _a === void 0 ? void 0 : _a.charAt) === null || _b === void 0 ? void 0 : _b.call(_a, 0)) || "A" })), _jsxs("div", { className: "flex flex-col items-start", children: [!isMine && (_jsx("span", { className: "text-xs text-gray-500 mb-1 px-3", children: message === null || message === void 0 ? void 0 : message.senderNickname })), _jsx("div", { className: clsx("px-3 py-2 sm:px-4 sm:py-2 rounded-2xl max-w-full break-words", isMine
85
- ? "bg-blue-500 text-white"
86
- : "bg-gray-100 text-gray-900"), children: _jsx("p", { className: "text-sm sm:text-base whitespace-pre-wrap", children: ((_c = message === null || message === void 0 ? void 0 : message.textElem) === null || _c === void 0 ? void 0 : _c.content) ||
87
- "Tin nhắn không khả dụng" }) })] })] }) }, message === null || message === void 0 ? void 0 : message.clientMsgID));
88
- })] }));
89
- }, [user === null || user === void 0 ? void 0 : user.userID, groupMessages]);
45
+ sendTextMessage(textMessage, lastMessage);
46
+ }, [textMessage, sendTextMessage, latestLoadState]);
47
+ const loadMoreMessage = () => {
48
+ if (!loadState.hasMoreOld || moreOldLoading)
49
+ return;
50
+ getMoreOldMessages();
51
+ };
90
52
  useEffect(() => {
91
- const currentMessageCount = (messageList === null || messageList === void 0 ? void 0 : messageList.length) || 0;
92
- const previousMessageCount = lastMessageCountRef.current;
93
- if (currentMessageCount > previousMessageCount) {
94
- const newMessages = messageList === null || messageList === void 0 ? void 0 : messageList.slice(previousMessageCount);
95
- const hasNewMessageFromCurrentUser = newMessages === null || newMessages === void 0 ? void 0 : newMessages.some((msg) => msg.sendID === (user === null || user === void 0 ? void 0 : user.userID));
96
- // If current user sent a message, always scroll to bottom
97
- // If another user sent a message, only scroll if shouldScrollToBottomRef is true (user is already at bottom)
98
- if (hasNewMessageFromCurrentUser) {
99
- setTimeout(() => scrollToBottom(true), 50); // Force scroll for own messages
100
- }
101
- else if (shouldScrollToBottomRef.current) {
102
- setTimeout(() => scrollToBottom(), 50); // Scroll if auto-scroll is enabled for others' messages
103
- }
104
- }
105
- lastMessageCountRef.current = currentMessageCount;
106
- }, [messageList, user === null || user === void 0 ? void 0 : user.userID, scrollToBottom]);
107
- return (_jsxs("div", { className: "flex flex-col flex-1 relative h-full bg-white", children: [_jsxs("div", { className: "px-4 py-3 flex items-center border-b gap-3", children: [_jsx(Avatar, { src: conversationData === null || conversationData === void 0 ? void 0 : conversationData.faceURL, children: ((_b = (_a = conversationData === null || conversationData === void 0 ? void 0 : conversationData.showName) === null || _a === void 0 ? void 0 : _a.charAt) === null || _b === void 0 ? void 0 : _b.call(_a, 0)) || "A" }), _jsxs("div", { className: "flex flex-col flex-1", children: [_jsx("p", { children: (conversationData === null || conversationData === void 0 ? void 0 : conversationData.showName) || "" }), _jsx("p", { className: "text-xs text-gray-500", children: "2 thành viên" })] }), _jsx(Button, { type: "text", shape: "circle", icon: _jsx(Icon, { icon: "align-justify-o", size: 24 }) }), !!onClose && (_jsx(Button, { type: "text", shape: "circle", icon: _jsx(Icon, { icon: "close-b", size: 24 }), onClick: onClose }))] }), _jsx("div", { className: "flex flex-col flex-1 min-h-0", children: _jsx("div", { className: "relative h-full", children: _jsx(AutoSizer, { children: ({ height, width }) => (_jsx(InfiniteLoader, { isItemLoaded: () => true, loadMoreItems: () => { }, itemCount: (groupMessages === null || groupMessages === void 0 ? void 0 : groupMessages.length) || 0, children: (_a) => {
108
- var { onItemsRendered, ref } = _a, rest = __rest(_a, ["onItemsRendered", "ref"]);
109
- return (_jsx(List, Object.assign({ ref: ref }, rest, { itemCount: (groupMessages === null || groupMessages === void 0 ? void 0 : groupMessages.length) || 0, onItemsRendered: onItemsRendered, height: height, width: width, itemSize: (index) => {
110
- const groupMessage = groupMessages === null || groupMessages === void 0 ? void 0 : groupMessages[index];
111
- const messagesInGroup = (groupMessage === null || groupMessage === void 0 ? void 0 : groupMessage.messages) || [];
112
- return (messagesInGroup === null || messagesInGroup === void 0 ? void 0 : messagesInGroup.length) * 50;
113
- }, children: renderMessageItem })));
114
- } })) }) }) }), _jsx("div", { className: "border-t px-4 py-3", children: _jsx("div", { className: "border rounded-lg bg-gray-50", children: _jsxs("div", { className: "px-4 py-3 flex items-center gap-4", children: [_jsx(Input, { placeholder: "Nh\u1EADp tin nh\u1EAFn", size: "small", variant: "borderless", value: textMessage, onChange: (e) => setTextMessage(e.target.value), onKeyDown: (e) => {
53
+ emitter.on("CHAT_LIST_SCROLL_TO_BOTTOM", scrollToBottom);
54
+ console.log("CHAT_LIST_SCROLL_TO_BOTTOM");
55
+ return () => {
56
+ emitter.off("CHAT_LIST_SCROLL_TO_BOTTOM", scrollToBottom);
57
+ };
58
+ }, []);
59
+ return (_jsxs("div", { className: "flex flex-col flex-1 relative h-full bg-white", children: [_jsx(MessageHeader, { conversationData: conversationData, onClose: onClose }), _jsx("div", { id: "scrollableDiv", style: {
60
+ height: "100%",
61
+ overflow: "auto",
62
+ display: "flex",
63
+ flexDirection: "column-reverse",
64
+ }, children: _jsx(InfiniteScroll, { dataLength: ((_a = loadState.groupMessageList) === null || _a === void 0 ? void 0 : _a.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: (_b = loadState.groupMessageList) === null || _b === void 0 ? void 0 : _b.toReversed().map((message) => _jsx(MessageItem, { groupMessage: message })) }) }), _jsx("div", { className: "border-t px-4 py-3", children: _jsx("div", { className: "border rounded-lg bg-gray-50", children: _jsxs("div", { className: "px-4 py-3 flex items-center gap-4", children: [_jsx(Input, { placeholder: "Nh\u1EADp tin nh\u1EAFn", size: "small", variant: "borderless", value: textMessage, onChange: (e) => setTextMessage(e.target.value), onKeyDown: (e) => {
115
65
  if (composing) {
116
66
  return;
117
67
  }
@@ -0,0 +1,3 @@
1
+ declare const FooterBottomSection: () => import("react/jsx-runtime").JSX.Element;
2
+ export default FooterBottomSection;
3
+ //# sourceMappingURL=BottomSection.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BottomSection.d.ts","sourceRoot":"","sources":["../../../../src/components/message/footer/BottomSection.tsx"],"names":[],"mappings":"AAEA,QAAA,MAAM,mBAAmB,+CAMxB,CAAC;AAEF,eAAe,mBAAmB,CAAC"}
@@ -0,0 +1,6 @@
1
+ "use client";
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ const FooterBottomSection = () => {
4
+ return (_jsx("div", { className: "flex items-center gap-2", children: _jsx("div", {}) }));
5
+ };
6
+ export default FooterBottomSection;
@@ -0,0 +1,3 @@
1
+ declare const MessageFooter: () => import("react/jsx-runtime").JSX.Element;
2
+ export default MessageFooter;
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/message/footer/index.tsx"],"names":[],"mappings":"AAwBA,QAAA,MAAM,aAAa,+CAsBlB,CAAC;AACF,eAAe,aAAa,CAAC"}
@@ -0,0 +1,25 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { LexicalComposer } from "@lexical/react/LexicalComposer";
4
+ import { RichTextPlugin } from "@lexical/react/LexicalRichTextPlugin";
5
+ import { ContentEditable } from "@lexical/react/LexicalContentEditable";
6
+ import { LexicalErrorBoundary } from "@lexical/react/LexicalErrorBoundary";
7
+ import FooterBottomSection from "./BottomSection";
8
+ const theme = {
9
+ // Theme styling goes here
10
+ };
11
+ // Catch any errors that occur during Lexical updates and log them
12
+ // or throw them as needed. If you don't throw them, Lexical will
13
+ // try to recover gracefully without losing user data.
14
+ const onError = (error) => {
15
+ console.error(error);
16
+ };
17
+ const initialConfig = {
18
+ namespace: "ChatInput",
19
+ theme,
20
+ onError,
21
+ };
22
+ const MessageFooter = () => {
23
+ return (_jsx(LexicalComposer, { initialConfig: initialConfig, children: _jsxs("div", { className: "border-t px-4 py-3", children: [_jsx("div", { className: "relative", children: _jsx(RichTextPlugin, { contentEditable: _jsx(ContentEditable, { className: "border border-indigo-500 rounded-md bg-blue-100 min-h-[64px] px-3 py-2 text-sm" }), ErrorBoundary: LexicalErrorBoundary, "aria-placeholder": "Nh\u1EADp tin nh\u1EAFn", placeholder: _jsx("div", { className: "absolute top-2 left-3", children: _jsx("p", { className: "text-gray-500 text-sm", children: "Nh\u1EADp tin nh\u1EAFn" }) }) }) }), _jsx(FooterBottomSection, {})] }) }));
24
+ };
25
+ export default MessageFooter;
@@ -1 +1 @@
1
- {"version":3,"file":"ChatContext.d.ts","sourceRoot":"","sources":["../../src/context/ChatContext.tsx"],"names":[],"mappings":"AAIA,OAAO,EACL,eAAe,EACf,iBAAiB,EAElB,MAAM,eAAe,CAAC;AAGvB,eAAO,MAAM,WAAW,0CAGtB,CAAC;AAEH,eAAO,MAAM,cAAc,uBAAgC,CAAC;AAE5D,eAAO,MAAM,YAAY,GAAI,qCAI1B,iBAAiB,4CAyEnB,CAAC"}
1
+ {"version":3,"file":"ChatContext.d.ts","sourceRoot":"","sources":["../../src/context/ChatContext.tsx"],"names":[],"mappings":"AAIA,OAAO,EACL,eAAe,EACf,iBAAiB,EAElB,MAAM,eAAe,CAAC;AAIvB,eAAO,MAAM,WAAW,0CAGtB,CAAC;AAEH,eAAO,MAAM,cAAc,uBAAgC,CAAC;AAE5D,eAAO,MAAM,YAAY,GAAI,qCAI1B,iBAAiB,4CA2EnB,CAAC"}
@@ -4,6 +4,7 @@ import { createContext, useContext, useEffect, useState } from "react";
4
4
  import { CbEvents } from "@openim/wasm-client-sdk";
5
5
  import { ConnectStatus, } from "../types/chat";
6
6
  import { DChatSDK } from "../constants/sdk";
7
+ import MainLayout from "../layout";
7
8
  export const ChatContext = createContext({
8
9
  user: null,
9
10
  connectStatus: ConnectStatus.Disconnected,
@@ -31,7 +32,9 @@ export const ChatProvider = ({ children, config, refetchToken, }) => {
31
32
  });
32
33
  };
33
34
  useEffect(() => {
34
- handleLogin();
35
+ if (config) {
36
+ handleLogin();
37
+ }
35
38
  }, [config]);
36
39
  useEffect(() => {
37
40
  DChatSDK.on(CbEvents.OnUserTokenExpired, () => {
@@ -67,5 +70,5 @@ export const ChatProvider = ({ children, config, refetchToken, }) => {
67
70
  DChatSDK.off(CbEvents.OnConnecting, () => { });
68
71
  };
69
72
  }, [refetchToken]);
70
- return (_jsx(ChatContext.Provider, { value: { user, connectStatus }, children: children }));
73
+ return (_jsx(ChatContext.Provider, { value: { user, connectStatus }, children: _jsx(MainLayout, { children: children }) }));
71
74
  };
@@ -2,6 +2,7 @@ import { ConversationItem, SessionType } from "@openim/wasm-client-sdk";
2
2
  export declare const useConversationList: (selectedThreadId?: string) => {
3
3
  conversationList: ConversationItem[];
4
4
  getAllConversationList: () => Promise<void>;
5
+ markConversationMessageAsRead: (conversationId: string) => void;
5
6
  };
6
7
  export declare const useConversationDetail: ({ sourceID, sessionType, }: {
7
8
  sourceID: string;
@@ -1 +1 @@
1
- {"version":3,"file":"useConversation.d.ts","sourceRoot":"","sources":["../../../src/hooks/conversation/useConversation.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,gBAAgB,EAChB,WAAW,EAEZ,MAAM,yBAAyB,CAAC;AAIjC,eAAO,MAAM,mBAAmB,GAAI,mBAAmB,MAAM;;;CA0C5D,CAAC;AAEF,eAAO,MAAM,qBAAqB,GAAI,4BAGnC;IACD,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,WAAW,CAAC;CAC1B;;CAuBA,CAAC"}
1
+ {"version":3,"file":"useConversation.d.ts","sourceRoot":"","sources":["../../../src/hooks/conversation/useConversation.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,gBAAgB,EAChB,WAAW,EAEZ,MAAM,yBAAyB,CAAC;AAIjC,eAAO,MAAM,mBAAmB,GAAI,mBAAmB,MAAM;;;oDAgBxC,MAAM;CAmC1B,CAAC;AAEF,eAAO,MAAM,qBAAqB,GAAI,4BAGnC;IACD,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,WAAW,CAAC;CAC1B;;CAuBA,CAAC"}
@@ -12,6 +12,15 @@ export const useConversationList = (selectedThreadId) => {
12
12
  console.log("getAllConversationList", err);
13
13
  });
14
14
  }, []);
15
+ const markConversationMessageAsRead = useCallback((conversationId) => {
16
+ if (!conversationId)
17
+ return;
18
+ DChatSDK.markConversationMessageAsRead(conversationId)
19
+ .then()
20
+ .catch(({ errCode, errMsg }) => {
21
+ // Failed call
22
+ });
23
+ }, []);
15
24
  useEffect(() => {
16
25
  getAllConversationList();
17
26
  }, [getAllConversationList]);
@@ -25,14 +34,13 @@ export const useConversationList = (selectedThreadId) => {
25
34
  }, []);
26
35
  useEffect(() => {
27
36
  if (selectedThreadId) {
28
- DChatSDK.markConversationMessageAsRead(selectedThreadId).catch(({ errCode, errMsg }) => {
29
- console.error("Failed to mark messages as read", errCode, errMsg);
30
- });
37
+ markConversationMessageAsRead(selectedThreadId);
31
38
  }
32
- }, [selectedThreadId]);
39
+ }, [selectedThreadId, markConversationMessageAsRead]);
33
40
  return {
34
41
  conversationList,
35
42
  getAllConversationList,
43
+ markConversationMessageAsRead,
36
44
  };
37
45
  };
38
46
  export const useConversationDetail = ({ sourceID, sessionType, }) => {
@@ -0,0 +1,11 @@
1
+ interface ConversationStore {
2
+ conversationData: any;
3
+ setConversationData: (data: any) => void;
4
+ selectedThreadId: string;
5
+ selectedSourceId: string;
6
+ setSelectedThreadId: (threadId: string) => void;
7
+ setSelectedSourceId: (sourceId: string) => void;
8
+ }
9
+ declare const useConversationStore: import("zustand").UseBoundStore<import("zustand").StoreApi<ConversationStore>>;
10
+ export default useConversationStore;
11
+ //# sourceMappingURL=useConversationStore.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useConversationStore.d.ts","sourceRoot":"","sources":["../../../src/hooks/conversation/useConversationStore.ts"],"names":[],"mappings":"AAEA,UAAU,iBAAiB;IACzB,gBAAgB,EAAE,GAAG,CAAC;IACtB,mBAAmB,EAAE,CAAC,IAAI,EAAE,GAAG,KAAK,IAAI,CAAC;IACzC,gBAAgB,EAAE,MAAM,CAAC;IACzB,gBAAgB,EAAE,MAAM,CAAC;IACzB,mBAAmB,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IAChD,mBAAmB,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;CACjD;AAED,QAAA,MAAM,oBAAoB,gFAOvB,CAAC;AAEJ,eAAe,oBAAoB,CAAC"}
@@ -1,8 +1,10 @@
1
1
  import { create } from "zustand";
2
- const useMessageStore = create((set) => ({
2
+ const useConversationStore = create((set) => ({
3
+ conversationData: null,
4
+ setConversationData: (data) => set({ conversationData: data }),
3
5
  selectedThreadId: "",
4
6
  setSelectedThreadId: (threadId) => set({ selectedThreadId: threadId }),
5
7
  selectedSourceId: "",
6
8
  setSelectedSourceId: (sourceId) => set({ selectedSourceId: sourceId }),
7
9
  }));
8
- export default useMessageStore;
10
+ export default useConversationStore;
@@ -0,0 +1,2 @@
1
+ export declare const useGlobalEvent: () => void;
2
+ //# sourceMappingURL=useGlobalEvent.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useGlobalEvent.d.ts","sourceRoot":"","sources":["../../../src/hooks/global/useGlobalEvent.ts"],"names":[],"mappings":"AAiBA,eAAO,MAAM,cAAc,YAqF1B,CAAC"}
@@ -0,0 +1,78 @@
1
+ import { useEffect } from "react";
2
+ import { DChatSDK } from "../../constants/sdk";
3
+ import { CbEvents, MessageType, SessionType, } from "@openim/wasm-client-sdk";
4
+ import { CustomType } from "../../types/chat";
5
+ import { pushNewMessage, updateOneMessage } from "../message/useMessage";
6
+ import { useChatContext } from "../../context/ChatContext";
7
+ import useConversationStore from "../conversation/useConversationStore";
8
+ const notPushType = [MessageType.TypingMessage, MessageType.RevokeMessage];
9
+ export const useGlobalEvent = () => {
10
+ const { user } = useChatContext();
11
+ const selectedSourceId = useConversationStore((state) => state.selectedSourceId);
12
+ const revokedMessageHandler = ({ data }) => {
13
+ updateOneMessage({
14
+ clientMsgID: data.clientMsgID,
15
+ contentType: MessageType.RevokeMessage,
16
+ notificationElem: {
17
+ detail: JSON.stringify(data),
18
+ },
19
+ });
20
+ };
21
+ const inCurrentConversation = (newServerMsg) => {
22
+ switch (newServerMsg.sessionType) {
23
+ case SessionType.Single:
24
+ return (newServerMsg.sendID === selectedSourceId ||
25
+ ((user === null || user === void 0 ? void 0 : user.userID) && newServerMsg.recvID === selectedSourceId));
26
+ case SessionType.Group:
27
+ case SessionType.WorkingGroup:
28
+ return newServerMsg.groupID === selectedSourceId;
29
+ case SessionType.Notification:
30
+ return newServerMsg.sendID === selectedSourceId;
31
+ default:
32
+ return false;
33
+ }
34
+ };
35
+ const handleNewMessage = (newServerMsg) => {
36
+ if (newServerMsg.contentType === MessageType.CustomMessage) {
37
+ const customData = JSON.parse(newServerMsg.customElem.data);
38
+ if (CustomType.CallingInvite <= customData.customType &&
39
+ customData.customType <= CustomType.CallingHungup) {
40
+ return;
41
+ }
42
+ }
43
+ if (!inCurrentConversation(newServerMsg))
44
+ return;
45
+ if (!notPushType.includes(newServerMsg.contentType)) {
46
+ pushNewMessage(newServerMsg);
47
+ }
48
+ };
49
+ const newMessageHandler = ({ data }) => {
50
+ data.map((message) => handleNewMessage(message));
51
+ };
52
+ const loginCheck = async () => {
53
+ // check openIM token and user info
54
+ };
55
+ const setIMListener = () => {
56
+ // message
57
+ DChatSDK.on(CbEvents.OnRecvNewMessages, newMessageHandler);
58
+ DChatSDK.on(CbEvents.OnNewRecvMessageRevoked, revokedMessageHandler);
59
+ };
60
+ const disposeIMListener = () => {
61
+ // message
62
+ DChatSDK.off(CbEvents.OnRecvNewMessages, newMessageHandler);
63
+ };
64
+ /** LIFE CYCLE */
65
+ useEffect(() => {
66
+ loginCheck();
67
+ setIMListener();
68
+ window.addEventListener("online", () => {
69
+ DChatSDK.networkStatusChanged();
70
+ });
71
+ window.addEventListener("offline", () => {
72
+ DChatSDK.networkStatusChanged();
73
+ });
74
+ return () => {
75
+ disposeIMListener();
76
+ };
77
+ }, []);
78
+ };