@droppii-org/chat-sdk 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/assets/sdk/sql-wasm.wasm +0 -0
- package/dist/components/message/MessageList.d.ts.map +1 -1
- package/dist/components/message/MessageList.js +8 -2
- package/dist/components/message/item/MessageStatusIndicator.d.ts +8 -0
- package/dist/components/message/item/MessageStatusIndicator.d.ts.map +1 -0
- package/dist/components/message/item/MessageStatusIndicator.js +16 -0
- package/dist/components/message/item/TextMessage.d.ts.map +1 -1
- package/dist/components/message/item/TextMessage.js +4 -1
- package/dist/components/message/item/UrlTextMessage.d.ts.map +1 -1
- package/dist/components/message/item/UrlTextMessage.js +5 -3
- package/dist/components/message/item/index.d.ts.map +1 -1
- package/dist/components/message/item/index.js +15 -6
- package/dist/components/searchConversation/item/SearchItemAsMessage.js +2 -2
- package/dist/components/searchConversation/item/SearchItemAsUser.js +2 -2
- package/dist/hooks/message/useMessage.d.ts +1 -0
- package/dist/hooks/message/useMessage.d.ts.map +1 -1
- package/dist/hooks/message/useMessage.js +6 -0
- package/dist/hooks/message/useSendMessage.d.ts +5 -0
- package/dist/hooks/message/useSendMessage.d.ts.map +1 -1
- package/dist/hooks/message/useSendMessage.js +134 -27
- package/dist/locales/vi/common.json +19 -2
- package/dist/styles/global.css +1 -1
- package/dist/utils/common.d.ts +13 -0
- package/dist/utils/common.d.ts.map +1 -1
- package/dist/utils/common.js +51 -0
- package/dist/utils/events.d.ts +1 -0
- package/dist/utils/events.d.ts.map +1 -1
- package/package.json +13 -10
- package/dist/tsconfig.tsbuildinfo +0 -1
|
File without changes
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MessageList.d.ts","sourceRoot":"","sources":["../../../src/components/message/MessageList.tsx"],"names":[],"mappings":"AAwBA,UAAU,gBAAgB;IACxB,cAAc,EAAE,MAAM,CAAC;IACvB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB;AAGD,QAAA,MAAM,WAAW,GAAI,OAAO,gBAAgB,
|
|
1
|
+
{"version":3,"file":"MessageList.d.ts","sourceRoot":"","sources":["../../../src/components/message/MessageList.tsx"],"names":[],"mappings":"AAwBA,UAAU,gBAAgB;IACxB,cAAc,EAAE,MAAM,CAAC;IACvB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB;AAGD,QAAA,MAAM,WAAW,GAAI,OAAO,gBAAgB,4CAqN3C,CAAC;AAEF,eAAe,WAAW,CAAC"}
|
|
@@ -126,10 +126,11 @@ const MessageList = (props) => {
|
|
|
126
126
|
if (!conversationData) {
|
|
127
127
|
return (_jsx("div", { className: "flex flex-1 items-center justify-center h-full", children: _jsx(Empty, { description: t("no_conversation_data") }) }));
|
|
128
128
|
}
|
|
129
|
-
return (_jsxs("div", { className: "flex flex-col flex-1 relative h-full", style: {
|
|
129
|
+
return (_jsxs("div", { className: "flex flex-col flex-1 relative h-full min-w-0", style: {
|
|
130
130
|
backgroundImage: `url(${images.conversationBg})`,
|
|
131
131
|
backgroundSize: "cover",
|
|
132
132
|
backgroundPosition: "center",
|
|
133
|
+
overflowX: "hidden",
|
|
133
134
|
}, children: [_jsx(MessageHeader, { onClose: onClose, currentSession: currentSession }), _jsx("div", { id: "scrollableMessagesDiv", ref: scrollRef, style: {
|
|
134
135
|
height: "100%",
|
|
135
136
|
overflowY: "auto",
|
|
@@ -137,7 +138,12 @@ const MessageList = (props) => {
|
|
|
137
138
|
display: "flex",
|
|
138
139
|
flexDirection: "column-reverse",
|
|
139
140
|
paddingBottom: 12,
|
|
140
|
-
}, children: _jsx(InfiniteScroll, { dataLength: ((_a = loadState.messageList) === null || _a === void 0 ? void 0 : _a.length) || 0, next: loadMoreOldMessage, style: {
|
|
141
|
+
}, children: _jsx(InfiniteScroll, { dataLength: ((_a = loadState.messageList) === null || _a === void 0 ? void 0 : _a.length) || 0, next: loadMoreOldMessage, style: {
|
|
142
|
+
display: "flex",
|
|
143
|
+
flexDirection: "column-reverse",
|
|
144
|
+
minWidth: 0,
|
|
145
|
+
width: "100%"
|
|
146
|
+
}, inverse: true, hasMore: loadState.hasMoreOld, loader: _jsx("div", { className: "flex items-center justify-center py-2", children: _jsx(Spin, {}) }), scrollableTarget: "scrollableMessagesDiv", onScroll: (e) => {
|
|
141
147
|
const target = e.target;
|
|
142
148
|
if (target.scrollTop > BOTTOM_THRESHOLD) {
|
|
143
149
|
handleMarkConversationMessageAsRead();
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { MessageItem } from "@openim/wasm-client-sdk";
|
|
2
|
+
interface Props {
|
|
3
|
+
message: MessageItem;
|
|
4
|
+
isLatest: boolean;
|
|
5
|
+
}
|
|
6
|
+
declare const MessageStatusIndicator: ({ message, isLatest }: Props) => import("react/jsx-runtime").JSX.Element | null;
|
|
7
|
+
export default MessageStatusIndicator;
|
|
8
|
+
//# sourceMappingURL=MessageStatusIndicator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MessageStatusIndicator.d.ts","sourceRoot":"","sources":["../../../../src/components/message/item/MessageStatusIndicator.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAiB,MAAM,yBAAyB,CAAC;AAOrE,UAAU,KAAK;IACb,OAAO,EAAE,WAAW,CAAC;IACrB,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED,QAAA,MAAM,sBAAsB,GAAI,uBAAuB,KAAK,mDAkB3D,CAAC;AAEF,eAAe,sBAAsB,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { MessageStatus } from "@openim/wasm-client-sdk";
|
|
3
|
+
import { LoadingOutlined, CheckCircleFilled, ExclamationCircleFilled, } from "@ant-design/icons";
|
|
4
|
+
const MessageStatusIndicator = ({ message, isLatest }) => {
|
|
5
|
+
if (message.status === MessageStatus.Sending) {
|
|
6
|
+
return _jsx(LoadingOutlined, { className: "text-gray-400 text-sm" });
|
|
7
|
+
}
|
|
8
|
+
if (message.status === MessageStatus.Succeed && isLatest) {
|
|
9
|
+
return _jsx(CheckCircleFilled, { className: "text-blue-500 text-sm" });
|
|
10
|
+
}
|
|
11
|
+
if (message.status === MessageStatus.Failed) {
|
|
12
|
+
return (_jsx(ExclamationCircleFilled, { className: "text-red-500 text-sm" }));
|
|
13
|
+
}
|
|
14
|
+
return null;
|
|
15
|
+
};
|
|
16
|
+
export default MessageStatusIndicator;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TextMessage.d.ts","sourceRoot":"","sources":["../../../../src/components/message/item/TextMessage.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAe,MAAM,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"TextMessage.d.ts","sourceRoot":"","sources":["../../../../src/components/message/item/TextMessage.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAe,MAAM,yBAAyB,CAAC;AAKnE,UAAU,oBAAoB;IAC5B,OAAO,EAAE,WAAW,CAAC;CACtB;AACD,QAAA,MAAM,eAAe,GAAI,OAAO,oBAAoB,mDAoCnD,CAAC;AAEF,eAAe,eAAe,CAAC"}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
3
|
import { MessageType } from "@openim/wasm-client-sdk";
|
|
4
4
|
import { useAuthStore } from "../../..";
|
|
5
|
+
import { sanitizeHtml } from "../../../utils/common";
|
|
5
6
|
const TextMessageItem = (props) => {
|
|
6
7
|
var _a, _b, _c;
|
|
7
8
|
const { message } = props;
|
|
@@ -20,7 +21,9 @@ const TextMessageItem = (props) => {
|
|
|
20
21
|
if (Object.keys(extendMessageInfo).length > 0 &&
|
|
21
22
|
(extendMessageInfo === null || extendMessageInfo === void 0 ? void 0 : extendMessageInfo.messageInfo)) {
|
|
22
23
|
const htmlContent = ((_b = (_a = extendMessageInfo === null || extendMessageInfo === void 0 ? void 0 : extendMessageInfo.messageInfo) === null || _a === void 0 ? void 0 : _a.data) === null || _b === void 0 ? void 0 : _b.content) || "";
|
|
23
|
-
|
|
24
|
+
// 🔒 Sanitize HTML to prevent XSS attacks
|
|
25
|
+
const sanitizedContent = sanitizeHtml(htmlContent);
|
|
26
|
+
return (_jsx("div", { className: "!text-sm sm:text-base break-words whitespace-pre-line flex-1", style: { wordBreak: "break-word", overflowWrap: "anywhere" }, dangerouslySetInnerHTML: { __html: sanitizedContent } }));
|
|
24
27
|
}
|
|
25
28
|
return (_jsx("span", { 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) || "" }));
|
|
26
29
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"UrlTextMessage.d.ts","sourceRoot":"","sources":["../../../../src/components/message/item/UrlTextMessage.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAMtD,UAAU,uBAAuB;IAC/B,OAAO,EAAE,WAAW,CAAC;CACtB;AACD,QAAA,MAAM,kBAAkB,GAAI,OAAO,uBAAuB,
|
|
1
|
+
{"version":3,"file":"UrlTextMessage.d.ts","sourceRoot":"","sources":["../../../../src/components/message/item/UrlTextMessage.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAMtD,UAAU,uBAAuB;IAC/B,OAAO,EAAE,WAAW,CAAC;CACtB;AACD,QAAA,MAAM,kBAAkB,GAAI,OAAO,uBAAuB,4CAwEzD,CAAC;AAEF,eAAe,kBAAkB,CAAC"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
-
import { getHostFromUrl, wrapLinksInHtml } from "../../../utils/common";
|
|
3
|
+
import { getHostFromUrl, wrapLinksInHtml, sanitizeHtml } from "../../../utils/common";
|
|
4
4
|
import { useFetchExternalLink } from "../../../hooks/common/useFetchExternalLink";
|
|
5
5
|
import { Image } from "antd";
|
|
6
6
|
const UrlTextMessageItem = (props) => {
|
|
@@ -23,8 +23,10 @@ const UrlTextMessageItem = (props) => {
|
|
|
23
23
|
if (Object.keys(extendMessageInfo).length > 0 &&
|
|
24
24
|
(extendMessageInfo === null || extendMessageInfo === void 0 ? void 0 : extendMessageInfo.messageInfo)) {
|
|
25
25
|
const htmlContent = ((_d = (_c = extendMessageInfo === null || extendMessageInfo === void 0 ? void 0 : extendMessageInfo.messageInfo) === null || _c === void 0 ? void 0 : _c.data) === null || _d === void 0 ? void 0 : _d.content) || "";
|
|
26
|
-
|
|
26
|
+
// 🔒 Sanitize HTML to prevent XSS attacks
|
|
27
|
+
const sanitizedContent = sanitizeHtml(wrapLinksInHtml(htmlContent));
|
|
28
|
+
return (_jsxs("div", { className: "flex flex-col gap-2", children: [_jsx("div", { className: "!text-sm sm:text-base break-words whitespace-pre-line flex-1", style: { wordBreak: "break-word", overflowWrap: "anywhere" }, dangerouslySetInnerHTML: { __html: sanitizedContent } }), !!externalLinkData && (_jsxs("div", { className: "flex items-center rounded-md px-3 py-2 border-l-4 border-l-blue-500 bg-blue-50 gap-2 cursor-pointer overflow-hidden", style: { wordBreak: "break-word", overflowWrap: "anywhere" }, onClick: () => onPressExternalLink((externalLinkData === null || externalLinkData === void 0 ? void 0 : externalLinkData.url) || ""), children: [_jsxs("div", { className: "flex flex-1 flex-col gap-1", children: [(externalLinkData === null || externalLinkData === void 0 ? void 0 : externalLinkData.title) && (_jsx("span", { className: "!text-sm font-semibold truncate", children: externalLinkData === null || externalLinkData === void 0 ? void 0 : externalLinkData.title })), (externalLinkData === null || externalLinkData === void 0 ? void 0 : externalLinkData.description) && (_jsx("span", { className: "!text-sm text-gray-500 line-clamp-2", children: externalLinkData === null || externalLinkData === void 0 ? void 0 : externalLinkData.description })), (externalLinkData === null || externalLinkData === void 0 ? void 0 : externalLinkData.url) && (_jsx("span", { className: "!text-sm font-medium text-blue-500", children: getHostFromUrl(externalLinkData === null || externalLinkData === void 0 ? void 0 : externalLinkData.url) }))] }), ((_e = externalLinkData === null || externalLinkData === void 0 ? void 0 : externalLinkData.logo) === null || _e === void 0 ? void 0 : _e.url) && (_jsx(Image, { src: (_f = externalLinkData === null || externalLinkData === void 0 ? void 0 : externalLinkData.logo) === null || _f === void 0 ? void 0 : _f.url, width: 48, height: 48 }))] }))] }));
|
|
27
29
|
}
|
|
28
|
-
return (_jsx("span", { className: "!text-sm sm:text-base break-words whitespace-pre-line flex-1 break-
|
|
30
|
+
return (_jsx("span", { className: "!text-sm sm:text-base break-words whitespace-pre-line flex-1", style: { wordBreak: "break-word", overflowWrap: "anywhere" }, children: ((_h = (_g = message === null || message === void 0 ? void 0 : message.urlTextElem) === null || _g === void 0 ? void 0 : _g.urls) === null || _h === void 0 ? void 0 : _h[0]) || "" }));
|
|
29
31
|
};
|
|
30
32
|
export default UrlTextMessageItem;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/message/item/index.tsx"],"names":[],"mappings":"AAGA,OAAO,EACL,WAAW,IAAI,eAAe,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/message/item/index.tsx"],"names":[],"mappings":"AAGA,OAAO,EACL,WAAW,IAAI,eAAe,EAG/B,MAAM,yBAAyB,CAAC;AAmBjC,UAAU,gBAAgB;IACxB,OAAO,EAAE,eAAe,CAAC;IACzB,WAAW,EAAE,eAAe,EAAE,CAAC;CAChC;AAED,QAAA,MAAM,WAAW,GAAI,0BAA0B,gBAAgB,mDA6J9D,CAAC;AAEF,eAAe,WAAW,CAAC"}
|
|
@@ -2,7 +2,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
import dayjs from "dayjs";
|
|
3
3
|
import clsx from "clsx";
|
|
4
4
|
import { Avatar } from "antd";
|
|
5
|
-
import { MessageType, } from "@openim/wasm-client-sdk";
|
|
5
|
+
import { MessageStatus, MessageType, } from "@openim/wasm-client-sdk";
|
|
6
6
|
import TextMessageItem from "./TextMessage";
|
|
7
7
|
import ImageMessageItem from "./ImageMessage";
|
|
8
8
|
import FileMessageItem from "./FileMessage";
|
|
@@ -13,9 +13,14 @@ import { formatTimestamp } from "../../../utils/common";
|
|
|
13
13
|
import useAuthStore from "../../../store/auth";
|
|
14
14
|
import useConversationStore from "../../../store/conversation";
|
|
15
15
|
import { useMemo } from "react";
|
|
16
|
+
import { Trans, useTranslation } from "react-i18next";
|
|
16
17
|
import UrlTextMessageItem from "./UrlTextMessage";
|
|
18
|
+
import MessageStatusIndicator from "./MessageStatusIndicator";
|
|
19
|
+
import { useSendMessage, isMediaResendable } from "../../../hooks/message/useSendMessage";
|
|
17
20
|
const MessageItem = ({ message, allMessages }) => {
|
|
18
|
-
var _a, _b, _c, _d;
|
|
21
|
+
var _a, _b, _c, _d, _e;
|
|
22
|
+
const { t } = useTranslation();
|
|
23
|
+
const { resendMessage } = useSendMessage();
|
|
19
24
|
const userID = useAuthStore((state) => state.userID);
|
|
20
25
|
const isCrm = useAuthStore((state) => state.isCrm);
|
|
21
26
|
const conversationData = useConversationStore((state) => state.conversationData);
|
|
@@ -49,6 +54,8 @@ const MessageItem = ({ message, allMessages }) => {
|
|
|
49
54
|
if (!isVisibleGroup)
|
|
50
55
|
return null;
|
|
51
56
|
const isMine = (message === null || message === void 0 ? void 0 : message.sendID) === userID;
|
|
57
|
+
const isLatestMine = ((_a = allMessages.find((m) => m.sendID === userID)) === null || _a === void 0 ? void 0 : _a.clientMsgID) ===
|
|
58
|
+
message.clientMsgID;
|
|
52
59
|
const previousMessage = getVisibleNeighbor(allMessages, message, "prev");
|
|
53
60
|
const nextMessage = getVisibleNeighbor(allMessages, message, "next");
|
|
54
61
|
const prevSameUser = (previousMessage === null || previousMessage === void 0 ? void 0 : previousMessage.sendID) === (message === null || message === void 0 ? void 0 : message.sendID);
|
|
@@ -61,10 +68,12 @@ const MessageItem = ({ message, allMessages }) => {
|
|
|
61
68
|
if (!isCrm && MessageType.CustomMessage === (message === null || message === void 0 ? void 0 : message.contentType)) {
|
|
62
69
|
return null;
|
|
63
70
|
}
|
|
64
|
-
return (_jsxs("div", { className: "flex flex-col gap-2 py-1 px-3 sm:
|
|
71
|
+
return (_jsxs("div", { className: "flex flex-col gap-2 py-1 px-3 sm:px-4 min-w-0", id: `${MSG_ITEM_PREFIX}${message === null || message === void 0 ? void 0 : message.clientMsgID}`, children: [showTimeBreak && (_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: formatTimestamp(message.sendTime, {
|
|
65
72
|
dateMonthFormat: "DD MMMM",
|
|
66
|
-
}) }) })), _jsx("div", { className: clsx("flex", isMine ? "justify-end" : "justify-start"), children: _jsxs("div", { className: clsx("flex flex-1 items-end gap-2", isMine ? "justify-end" : "justify-start"), children: [!isMine && showSenderInfo && (_jsx("div", { className: "flex items-center justify-center w-[32px] h-[32px]", children: showSenderAvatar && (_jsx(Avatar, { src: message === null || message === void 0 ? void 0 : message.senderFaceUrl, children: ((
|
|
67
|
-
|
|
68
|
-
|
|
73
|
+
}) }) })), _jsx("div", { className: clsx("flex min-w-0", isMine ? "justify-end" : "justify-start"), children: _jsxs("div", { className: clsx("flex flex-1 items-end gap-2 min-w-0", isMine ? "justify-end" : "justify-start"), children: [!isMine && showSenderInfo && (_jsx("div", { className: "flex items-center justify-center w-[32px] h-[32px]", children: showSenderAvatar && (_jsx(Avatar, { src: message === null || message === void 0 ? void 0 : message.senderFaceUrl, children: ((_c = (_b = message === null || message === void 0 ? void 0 : message.senderNickname) === null || _b === void 0 ? void 0 : _b.charAt) === null || _c === void 0 ? void 0 : _c.call(_b, 0)) || "A" })) })), _jsxs("div", { className: clsx("flex flex-col flex-[0.8] min-w-0", isMine ? "items-end" : "items-start"), children: [showSenderName && showSenderInfo && (_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: "flex items-end gap-1.5", children: [isMine && _jsx(MessageStatusIndicator, { message: message, isLatest: isLatestMine }), _jsxs("div", { className: clsx("px-3 py-2 rounded-2xl max-w-full min-w-0 break-words flex flex-col flex-1 text-gray-900 gap-1", isMine ? "bg-blue-100" : "bg-white"), style: { wordBreak: "break-word", overflowWrap: "anywhere" }, id: `${MSG_ITEM_CONTENT_PREFIX}${message === null || message === void 0 ? void 0 : message.clientMsgID}`, children: [(message === null || message === void 0 ? void 0 : message.contentType) === MessageType.MergeMessage ? (_jsxs("div", { children: [(_e = (_d = message === null || message === void 0 ? void 0 : message.mergeElem) === null || _d === void 0 ? void 0 : _d.multiMessage) === null || _e === void 0 ? void 0 : _e.map((item) => {
|
|
74
|
+
return renderMessageByType(item);
|
|
75
|
+
}), (message === null || message === void 0 ? void 0 : message.textElem) && _jsx(TextMessageItem, { message: message })] })) : (renderMessageByType(message)), _jsx("span", { className: clsx("text-xs text-gray-500 text-right"), children: dayjs(message === null || message === void 0 ? void 0 : message.sendTime).format("HH:mm") })] })] }), isMine && message.status === MessageStatus.Failed && (_jsx("span", { className: "text-red-500 text-xs mt-1", children: isMediaResendable(message) ? (_jsx(Trans, { i18nKey: "message_send_failed", components: {
|
|
76
|
+
bold: (_jsx("strong", { className: "cursor-pointer", onClick: () => resendMessage(message) })),
|
|
77
|
+
} })) : (t("message_send_failed_no_retry")) }))] })] }) }, message === null || message === void 0 ? void 0 : message.clientMsgID)] }, message === null || message === void 0 ? void 0 : message.clientMsgID));
|
|
69
78
|
};
|
|
70
79
|
export default MessageItem;
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { SessionType } from "@openim/wasm-client-sdk";
|
|
4
4
|
import { Avatar } from "antd";
|
|
5
|
-
import { formatTimestamp, highlightSearch } from "../../../utils/common";
|
|
5
|
+
import { formatTimestamp, highlightSearch, sanitizeHtml } from "../../../utils/common";
|
|
6
6
|
import { DChatSDK } from "../../../constants/sdk";
|
|
7
7
|
import { useChatContext } from "../../../context/ChatContext";
|
|
8
8
|
import { message as antdMessage } from "antd";
|
|
@@ -63,7 +63,7 @@ const SearchItemAsMessage = (props) => {
|
|
|
63
63
|
: conversationData === null || conversationData === void 0 ? void 0 : conversationData.showName }), _jsx("span", { className: "text-xs text-gray-500", children: formatTimestamp(message.sendTime, {
|
|
64
64
|
hasTime: true,
|
|
65
65
|
}) })] }), _jsx("div", { className: "flex flex-col flex-1 min-w-0", children: _jsx("span", { className: "text-xs flex-1 text-gray-500 truncate", dangerouslySetInnerHTML: {
|
|
66
|
-
__html: highlightSearch(msgContent, searchTerm),
|
|
66
|
+
__html: sanitizeHtml(highlightSearch(msgContent, searchTerm)),
|
|
67
67
|
} }) })] })] }, message.clientMsgID));
|
|
68
68
|
};
|
|
69
69
|
export default SearchItemAsMessage;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { Avatar, message } from "antd";
|
|
4
|
-
import { highlightSearch } from "../../../utils/common";
|
|
4
|
+
import { highlightSearch, sanitizeHtml } from "../../../utils/common";
|
|
5
5
|
import useConversationStore from "../../../store/conversation";
|
|
6
6
|
import { useTranslation } from "react-i18next";
|
|
7
7
|
const SearchItemAsUser = (props) => {
|
|
@@ -19,7 +19,7 @@ const SearchItemAsUser = (props) => {
|
|
|
19
19
|
.setSelectedConversationId(session.conversationId);
|
|
20
20
|
};
|
|
21
21
|
return (_jsxs("div", { className: "py-3 px-2 flex items-center gap-3 hover:bg-gray-100 hover:rounded-sm cursor-pointer border-b mx-1", onClick: onPressItem, children: [_jsx(Avatar, { size: "large", src: (_d = session.owner) === null || _d === void 0 ? void 0 : _d.avatar, alt: (_e = session.owner) === null || _e === void 0 ? void 0 : _e.username, children: (_f = session.owner) === null || _f === void 0 ? void 0 : _f.fullName.charAt(0).toUpperCase() }), _jsx("div", { className: "flex flex-col flex-1 min-w-0", children: _jsx("p", { className: "text-sm font-semibold truncate", dangerouslySetInnerHTML: {
|
|
22
|
-
__html: highlightSearch(ownerName, searchTerm),
|
|
22
|
+
__html: sanitizeHtml(highlightSearch(ownerName, searchTerm)),
|
|
23
23
|
} }) })] }, session.id));
|
|
24
24
|
};
|
|
25
25
|
export default SearchItemAsUser;
|
|
@@ -20,5 +20,6 @@ export declare const useMessage: (conversationId?: string, searchClientMsgID?: s
|
|
|
20
20
|
};
|
|
21
21
|
export declare const pushNewMessage: (message: MessageItem) => void;
|
|
22
22
|
export declare const updateOneMessage: (message: MessageItem) => void;
|
|
23
|
+
export declare const removeOneMessage: (clientMsgID: string) => void;
|
|
23
24
|
export declare const getVisibleNeighbor: (allMessages: MessageItem[], current: MessageItem, direction: "prev" | "next") => MessageItem | undefined;
|
|
24
25
|
//# sourceMappingURL=useMessage.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useMessage.d.ts","sourceRoot":"","sources":["../../../src/hooks/message/useMessage.ts"],"names":[],"mappings":"AACA,OAAO,EAAY,WAAW,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAQ7E,eAAO,MAAM,kBAAkB,eAc9B,CAAC;AAEF,eAAO,MAAM,UAAU,GACrB,iBAAiB,MAAM,EACvB,oBAAoB,MAAM;;;;;qBAML,WAAW,EAAE;;;;;;qBAAb,WAAW,EAAE;;;;;;
|
|
1
|
+
{"version":3,"file":"useMessage.d.ts","sourceRoot":"","sources":["../../../src/hooks/message/useMessage.ts"],"names":[],"mappings":"AACA,OAAO,EAAY,WAAW,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAQ7E,eAAO,MAAM,kBAAkB,eAc9B,CAAC;AAEF,eAAO,MAAM,UAAU,GACrB,iBAAiB,MAAM,EACvB,oBAAoB,MAAM;;;;;qBAML,WAAW,EAAE;;;;;;qBAAb,WAAW,EAAE;;;;;;CAkNnC,CAAC;AAEF,eAAO,MAAM,cAAc,GAAI,SAAS,WAAW,SACpB,CAAC;AAChC,eAAO,MAAM,gBAAgB,GAAI,SAAS,WAAW,SACpB,CAAC;AAClC,eAAO,MAAM,gBAAgB,GAAI,aAAa,MAAM,SACf,CAAC;AAEtC,eAAO,MAAM,kBAAkB,GAC7B,aAAa,WAAW,EAAE,EAC1B,SAAS,WAAW,EACpB,WAAW,MAAM,GAAG,MAAM,KACzB,WAAW,GAAG,SAkBhB,CAAC"}
|
|
@@ -143,11 +143,16 @@ export const useMessage = (conversationId, searchClientMsgID) => {
|
|
|
143
143
|
return Object.assign(Object.assign({}, preState), { messageList: tmpList });
|
|
144
144
|
});
|
|
145
145
|
};
|
|
146
|
+
const removeOneMessage = (clientMsgID) => {
|
|
147
|
+
setLoadState((preState) => (Object.assign(Object.assign({}, preState), { messageList: preState.messageList.filter((msg) => msg.clientMsgID !== clientMsgID) })));
|
|
148
|
+
};
|
|
146
149
|
emitter.on("PUSH_NEW_MSG", pushNewMessage);
|
|
147
150
|
emitter.on("UPDATE_ONE_MSG", updateOneMessage);
|
|
151
|
+
emitter.on("REMOVE_ONE_MSG", removeOneMessage);
|
|
148
152
|
return () => {
|
|
149
153
|
emitter.off("PUSH_NEW_MSG", pushNewMessage);
|
|
150
154
|
emitter.off("UPDATE_ONE_MSG", updateOneMessage);
|
|
155
|
+
emitter.off("REMOVE_ONE_MSG", removeOneMessage);
|
|
151
156
|
};
|
|
152
157
|
}, []);
|
|
153
158
|
useEffect(() => {
|
|
@@ -179,6 +184,7 @@ export const useMessage = (conversationId, searchClientMsgID) => {
|
|
|
179
184
|
};
|
|
180
185
|
export const pushNewMessage = (message) => emit("PUSH_NEW_MSG", message);
|
|
181
186
|
export const updateOneMessage = (message) => emit("UPDATE_ONE_MSG", message);
|
|
187
|
+
export const removeOneMessage = (clientMsgID) => emit("REMOVE_ONE_MSG", clientMsgID);
|
|
182
188
|
export const getVisibleNeighbor = (allMessages, current, direction) => {
|
|
183
189
|
const currentIndex = allMessages.findIndex((m) => m.clientMsgID === current.clientMsgID);
|
|
184
190
|
if (currentIndex === -1)
|
|
@@ -2,6 +2,10 @@ import { MergerMsgParams, MessageItem } from "@openim/wasm-client-sdk";
|
|
|
2
2
|
import { ExtendMessageInfo, FileMsgParamsByFile, ImageMsgParamsByFile, VideoMsgParamsByFile } from "../../types/chat";
|
|
3
3
|
import { UploadFile } from "antd";
|
|
4
4
|
import { ISessionByStatus } from "../../store/type";
|
|
5
|
+
export declare const isMediaResendable: (message: {
|
|
6
|
+
clientMsgID: string;
|
|
7
|
+
contentType: number;
|
|
8
|
+
}) => boolean;
|
|
5
9
|
export declare const createTextMessage: (text: string) => Promise<MessageItem | null>;
|
|
6
10
|
export declare const createImageMessageByFile: (file: ImageMsgParamsByFile) => Promise<MessageItem | null>;
|
|
7
11
|
export declare const createMergerMessage: (mergerMsgParams: MergerMsgParams) => Promise<MessageItem | null>;
|
|
@@ -20,6 +24,7 @@ export declare const useSendMessage: () => {
|
|
|
20
24
|
files: UploadFile[];
|
|
21
25
|
currentSession?: ISessionByStatus;
|
|
22
26
|
}) => Promise<void>;
|
|
27
|
+
resendMessage: (failedMessage: MessageItem) => Promise<void>;
|
|
23
28
|
};
|
|
24
29
|
export declare const generateExtendMessageInfo: ({ richText, currentSession, }: {
|
|
25
30
|
richText?: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useSendMessage.d.ts","sourceRoot":"","sources":["../../../src/hooks/message/useSendMessage.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,eAAe,EACf,WAAW,
|
|
1
|
+
{"version":3,"file":"useSendMessage.d.ts","sourceRoot":"","sources":["../../../src/hooks/message/useSendMessage.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,eAAe,EACf,WAAW,EAGZ,MAAM,yBAAyB,CAAC;AAEjC,OAAO,EACL,iBAAiB,EACjB,mBAAmB,EACnB,oBAAoB,EACpB,oBAAoB,EACrB,MAAM,kBAAkB,CAAC;AAM1B,OAAO,EAAE,UAAU,EAAE,MAAM,MAAM,CAAC;AAQlC,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAepD,eAAO,MAAM,iBAAiB,GAAI,SAAS;IAAE,WAAW,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,YACK,CAAC;AAE7F,eAAO,MAAM,iBAAiB,GAAU,MAAM,MAAM,gCAanD,CAAC;AAEF,eAAO,MAAM,wBAAwB,GAAU,MAAM,oBAAoB,gCAaxE,CAAC;AAEF,eAAO,MAAM,mBAAmB,GAAU,iBAAiB,eAAe,gCAazE,CAAC;AAEF,eAAO,MAAM,wBAAwB,GAAU,MAAM,oBAAoB,gCAaxE,CAAC;AAEF,eAAO,MAAM,uBAAuB,GAAU,MAAM,mBAAmB,gCAatE,CAAC;AAEF,eAAO,MAAM,oBAAoB,GAAU,MAAM,MAAM,EAAE,MAAM,MAAM,EAAE,gCActE,CAAC;AAEF,eAAO,MAAM,cAAc;gEAmJpB;QACD,SAAS,EAAE,MAAM,CAAC;QAClB,QAAQ,EAAE,MAAM,CAAC;QACjB,cAAc,CAAC,EAAE,gBAAgB,CAAC;KACnC;wEA+BE;QACD,QAAQ,EAAE,MAAM,CAAC;QACjB,SAAS,EAAE,MAAM,CAAC;QAClB,KAAK,EAAE,UAAU,EAAE,CAAC;QACpB,cAAc,CAAC,EAAE,gBAAgB,CAAC;KACnC;mCAtIqB,WAAW;CA+PpC,CAAC;AAEF,eAAO,MAAM,yBAAyB,GAAI,+BAGvC;IACD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,cAAc,CAAC,EAAE,gBAAgB,CAAC;CACnC,KAWM,iBACN,CAAC"}
|
|
@@ -1,13 +1,20 @@
|
|
|
1
|
-
import { MessageStatus, } from "@openim/wasm-client-sdk";
|
|
1
|
+
import { MessageStatus, MessageType, } from "@openim/wasm-client-sdk";
|
|
2
2
|
import { DChatSDK } from "../../constants/sdk";
|
|
3
3
|
import { v4 as uuidv4 } from "uuid";
|
|
4
4
|
import { useChatContext } from "../../context/ChatContext";
|
|
5
5
|
import { useCallback } from "react";
|
|
6
|
-
import { pushNewMessage, updateOneMessage } from "./useMessage";
|
|
6
|
+
import { pushNewMessage, removeOneMessage, updateOneMessage } from "./useMessage";
|
|
7
7
|
import { emit } from "../../utils/events";
|
|
8
8
|
import useConversationStore from "../../store/conversation";
|
|
9
9
|
import useAuthStore from "../../store/auth";
|
|
10
10
|
import { extractLinks, generateContentBasedOnMessageType, } from "../../utils/common";
|
|
11
|
+
const messageFileStore = new Map();
|
|
12
|
+
const MEDIA_CONTENT_TYPES = new Set([
|
|
13
|
+
MessageType.PictureMessage,
|
|
14
|
+
MessageType.VideoMessage,
|
|
15
|
+
MessageType.FileMessage,
|
|
16
|
+
]);
|
|
17
|
+
export const isMediaResendable = (message) => !MEDIA_CONTENT_TYPES.has(message.contentType) || messageFileStore.has(message.clientMsgID);
|
|
11
18
|
export const createTextMessage = async (text) => {
|
|
12
19
|
let textMessage = await DChatSDK.createTextMessage(text, new Date().getTime().toString())
|
|
13
20
|
.then(({ data }) => {
|
|
@@ -78,34 +85,119 @@ export const useSendMessage = () => {
|
|
|
78
85
|
const { user } = useChatContext();
|
|
79
86
|
const conversationData = useConversationStore((state) => state.conversationData);
|
|
80
87
|
const { userID: recvID, groupID } = conversationData || {};
|
|
88
|
+
const dispatchMessage = useCallback(async (message) => {
|
|
89
|
+
var _a;
|
|
90
|
+
const desc = generateContentBasedOnMessageType(message.contentType, ((_a = message === null || message === void 0 ? void 0 : message.textElem) === null || _a === void 0 ? void 0 : _a.content) || "") || "Bạn có tin nhắn mới";
|
|
91
|
+
const { data: successMessage } = await DChatSDK.sendMessage({
|
|
92
|
+
recvID: recvID || "",
|
|
93
|
+
groupID: groupID || "",
|
|
94
|
+
message,
|
|
95
|
+
offlinePushInfo: {
|
|
96
|
+
title: (conversationData === null || conversationData === void 0 ? void 0 : conversationData.showName) || "Droppii Chat",
|
|
97
|
+
desc,
|
|
98
|
+
ex: JSON.stringify({
|
|
99
|
+
icon: (conversationData === null || conversationData === void 0 ? void 0 : conversationData.faceURL) || "",
|
|
100
|
+
conversationId: (conversationData === null || conversationData === void 0 ? void 0 : conversationData.conversationID) || "",
|
|
101
|
+
title: (conversationData === null || conversationData === void 0 ? void 0 : conversationData.showName) || "Droppii Chat",
|
|
102
|
+
desc,
|
|
103
|
+
}),
|
|
104
|
+
iOSPushSound: "default",
|
|
105
|
+
iOSBadgeCount: true,
|
|
106
|
+
},
|
|
107
|
+
});
|
|
108
|
+
updateOneMessage(successMessage);
|
|
109
|
+
messageFileStore.delete(message.clientMsgID);
|
|
110
|
+
}, [recvID, groupID]);
|
|
81
111
|
const sendMessage = useCallback(async (message) => {
|
|
82
|
-
|
|
112
|
+
pushNewMessage(message);
|
|
113
|
+
emit("CHAT_LIST_SCROLL_TO_BOTTOM");
|
|
83
114
|
try {
|
|
84
|
-
|
|
85
|
-
emit("CHAT_LIST_SCROLL_TO_BOTTOM");
|
|
86
|
-
const { data: successMessage } = await DChatSDK.sendMessage({
|
|
87
|
-
recvID: recvID || "",
|
|
88
|
-
groupID: groupID || "",
|
|
89
|
-
message: message,
|
|
90
|
-
offlinePushInfo: {
|
|
91
|
-
title: (conversationData === null || conversationData === void 0 ? void 0 : conversationData.showName) || "Droppii Chat",
|
|
92
|
-
desc: `${generateContentBasedOnMessageType(message.contentType, ((_a = message === null || message === void 0 ? void 0 : message.textElem) === null || _a === void 0 ? void 0 : _a.content) || "")}` || "Bạn có tin nhắn mới",
|
|
93
|
-
ex: JSON.stringify({
|
|
94
|
-
icon: (conversationData === null || conversationData === void 0 ? void 0 : conversationData.faceURL) || "",
|
|
95
|
-
conversationId: (conversationData === null || conversationData === void 0 ? void 0 : conversationData.conversationID) || "",
|
|
96
|
-
title: (conversationData === null || conversationData === void 0 ? void 0 : conversationData.showName) || "Droppii Chat",
|
|
97
|
-
desc: `${generateContentBasedOnMessageType(message.contentType, ((_b = message === null || message === void 0 ? void 0 : message.textElem) === null || _b === void 0 ? void 0 : _b.content) || "")}` || "Bạn có tin nhắn mới",
|
|
98
|
-
}),
|
|
99
|
-
iOSPushSound: "default",
|
|
100
|
-
iOSBadgeCount: true,
|
|
101
|
-
},
|
|
102
|
-
});
|
|
103
|
-
updateOneMessage(successMessage);
|
|
115
|
+
await dispatchMessage(message);
|
|
104
116
|
}
|
|
105
|
-
catch (
|
|
117
|
+
catch (_a) {
|
|
106
118
|
updateOneMessage(Object.assign(Object.assign({}, message), { status: MessageStatus.Failed }));
|
|
107
119
|
}
|
|
108
|
-
}, [
|
|
120
|
+
}, [dispatchMessage]);
|
|
121
|
+
const resendMessage = useCallback(async (failedMessage) => {
|
|
122
|
+
var _a;
|
|
123
|
+
const storedFiles = messageFileStore.get(failedMessage.clientMsgID);
|
|
124
|
+
if (!storedFiles) {
|
|
125
|
+
let newTextPayload = null;
|
|
126
|
+
const textContent = ((_a = failedMessage.textElem) === null || _a === void 0 ? void 0 : _a.content) || failedMessage.content || "";
|
|
127
|
+
if (failedMessage.contentType === MessageType.UrlTextMessage && failedMessage.urlTextElem) {
|
|
128
|
+
newTextPayload = await createUrlTextMessage(textContent, failedMessage.urlTextElem.urls);
|
|
129
|
+
}
|
|
130
|
+
else {
|
|
131
|
+
newTextPayload = await createTextMessage(textContent);
|
|
132
|
+
}
|
|
133
|
+
if (!newTextPayload) {
|
|
134
|
+
updateOneMessage(Object.assign(Object.assign({}, failedMessage), { status: MessageStatus.Failed }));
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
const conversationID = (conversationData === null || conversationData === void 0 ? void 0 : conversationData.conversationID) || "";
|
|
138
|
+
await DChatSDK.deleteMessageFromLocalStorage({
|
|
139
|
+
conversationID,
|
|
140
|
+
clientMsgID: failedMessage.clientMsgID,
|
|
141
|
+
});
|
|
142
|
+
removeOneMessage(failedMessage.clientMsgID);
|
|
143
|
+
await sendMessage(Object.assign(Object.assign({}, newTextPayload), { ex: failedMessage.ex }));
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
let newPayload = null;
|
|
147
|
+
if (storedFiles.type === "image" && failedMessage.pictureElem) {
|
|
148
|
+
const { sourcePicture, bigPicture, snapshotPicture, sourcePath } = failedMessage.pictureElem;
|
|
149
|
+
newPayload = await createImageMessageByFile({
|
|
150
|
+
sourcePicture,
|
|
151
|
+
bigPicture,
|
|
152
|
+
snapshotPicture,
|
|
153
|
+
sourcePath,
|
|
154
|
+
file: storedFiles.file,
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
else if (storedFiles.type === "video" && failedMessage.videoElem) {
|
|
158
|
+
const elem = failedMessage.videoElem;
|
|
159
|
+
newPayload = await createVideoMessageByFile({
|
|
160
|
+
videoPath: elem.videoPath,
|
|
161
|
+
duration: elem.duration,
|
|
162
|
+
videoType: elem.videoType,
|
|
163
|
+
snapshotPath: elem.snapshotPath,
|
|
164
|
+
videoUUID: elem.videoUUID,
|
|
165
|
+
videoUrl: elem.videoUrl,
|
|
166
|
+
videoSize: elem.videoSize,
|
|
167
|
+
snapshotUUID: elem.snapshotUUID,
|
|
168
|
+
snapshotSize: elem.snapshotSize,
|
|
169
|
+
snapshotUrl: elem.snapshotUrl,
|
|
170
|
+
snapshotWidth: elem.snapshotWidth,
|
|
171
|
+
snapshotHeight: elem.snapshotHeight,
|
|
172
|
+
videoFile: storedFiles.videoFile,
|
|
173
|
+
snapshotFile: storedFiles.snapshotFile,
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
else if (storedFiles.type === "file" && failedMessage.fileElem) {
|
|
177
|
+
const elem = failedMessage.fileElem;
|
|
178
|
+
newPayload = await createFileMessageByFile({
|
|
179
|
+
filePath: elem.filePath,
|
|
180
|
+
fileName: elem.fileName,
|
|
181
|
+
uuid: elem.uuid,
|
|
182
|
+
sourceUrl: elem.sourceUrl,
|
|
183
|
+
fileSize: elem.fileSize,
|
|
184
|
+
file: storedFiles.file,
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
if (!newPayload) {
|
|
188
|
+
updateOneMessage(Object.assign(Object.assign({}, failedMessage), { status: MessageStatus.Failed }));
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
messageFileStore.delete(failedMessage.clientMsgID);
|
|
192
|
+
messageFileStore.set(newPayload.clientMsgID, storedFiles);
|
|
193
|
+
const conversationID = (conversationData === null || conversationData === void 0 ? void 0 : conversationData.conversationID) || "";
|
|
194
|
+
await DChatSDK.deleteMessageFromLocalStorage({
|
|
195
|
+
conversationID,
|
|
196
|
+
clientMsgID: failedMessage.clientMsgID,
|
|
197
|
+
});
|
|
198
|
+
removeOneMessage(failedMessage.clientMsgID);
|
|
199
|
+
await sendMessage(Object.assign(Object.assign({}, newPayload), { ex: failedMessage.ex }));
|
|
200
|
+
}, [sendMessage]);
|
|
109
201
|
const sendTextMessage = useCallback(async ({ plainText, richText, currentSession, }) => {
|
|
110
202
|
if (!recvID && !groupID)
|
|
111
203
|
return;
|
|
@@ -159,6 +251,10 @@ export const useSendMessage = () => {
|
|
|
159
251
|
const imageMessage = await createImageMessageByFile(parsedImage);
|
|
160
252
|
if (!imageMessage)
|
|
161
253
|
continue;
|
|
254
|
+
messageFileStore.set(imageMessage.clientMsgID, {
|
|
255
|
+
type: "image",
|
|
256
|
+
file: file,
|
|
257
|
+
});
|
|
162
258
|
messageList.push(imageMessage);
|
|
163
259
|
}
|
|
164
260
|
else if (isVideo) {
|
|
@@ -185,10 +281,15 @@ export const useSendMessage = () => {
|
|
|
185
281
|
});
|
|
186
282
|
if (!videoMessage)
|
|
187
283
|
continue;
|
|
284
|
+
messageFileStore.set(videoMessage.clientMsgID, {
|
|
285
|
+
type: "video",
|
|
286
|
+
videoFile: file,
|
|
287
|
+
snapshotFile: thumbFile,
|
|
288
|
+
});
|
|
188
289
|
messageList.push(videoMessage);
|
|
189
290
|
}
|
|
190
291
|
else if (isDocument) {
|
|
191
|
-
const
|
|
292
|
+
const fileParams = {
|
|
192
293
|
filePath: "",
|
|
193
294
|
fileName: file.name,
|
|
194
295
|
uuid: uuidv4(),
|
|
@@ -196,9 +297,14 @@ export const useSendMessage = () => {
|
|
|
196
297
|
fileSize: file.size,
|
|
197
298
|
fileType: file.type,
|
|
198
299
|
file: file,
|
|
199
|
-
}
|
|
300
|
+
};
|
|
301
|
+
const fileMessage = await createFileMessageByFile(fileParams);
|
|
200
302
|
if (!fileMessage)
|
|
201
303
|
continue;
|
|
304
|
+
messageFileStore.set(fileMessage.clientMsgID, {
|
|
305
|
+
type: "file",
|
|
306
|
+
file: file,
|
|
307
|
+
});
|
|
202
308
|
messageList.push(fileMessage);
|
|
203
309
|
}
|
|
204
310
|
}
|
|
@@ -224,6 +330,7 @@ export const useSendMessage = () => {
|
|
|
224
330
|
return {
|
|
225
331
|
sendTextMessage,
|
|
226
332
|
sendMergeMessage,
|
|
333
|
+
resendMessage,
|
|
227
334
|
};
|
|
228
335
|
};
|
|
229
336
|
export const generateExtendMessageInfo = ({ richText, currentSession, }) => {
|
|
@@ -74,9 +74,26 @@
|
|
|
74
74
|
"create_new_group": "Tạo nhóm CS mới",
|
|
75
75
|
"open_session": "Mở phiên",
|
|
76
76
|
"close_session": "Đóng phiên",
|
|
77
|
+
"message_send_failed": "Gửi tin nhắn thất bại, bạn vui lòng <bold>nhấn để gửi lại</bold>",
|
|
78
|
+
"message_send_failed_no_retry": "Gửi tin nhắn thất bại",
|
|
79
|
+
"general_info": "Thông tin chung",
|
|
80
|
+
"member_name": "Tên thành viên",
|
|
81
|
+
"activity_status": "Trạng thái hoạt động",
|
|
82
|
+
"online": "Trực tuyến",
|
|
83
|
+
"offline": "Ngoại tuyến",
|
|
84
|
+
"add_member_button": "Thêm thành viên",
|
|
85
|
+
"member_username": "Tên thành viên",
|
|
86
|
+
"change_status": "Thay đổi trạng thái",
|
|
87
|
+
"change_status_online_to_offline": "<bold>Bạn đang ở trạng thái Trực tuyến</bold>, khi chuyển sang Ngoại tuyến hệ thống sẽ không tự động gửi yêu cầu hỗ trợ mới cho bạn.\nBạn có chắc chắn muốn thay đổi trạng thái?",
|
|
88
|
+
"change_status_offline_to_online": "<bold>Bạn đang ở trạng thái Ngoại tuyến</bold>, khi chuyển sang Trực tuyến hệ thống sẽ tự động thêm bạn vào phiên hỗ trợ.\nBạn có chắc chắn muốn thay đổi trạng thái?",
|
|
89
|
+
"confirm": "Xác nhận",
|
|
90
|
+
"update_status_success": "Cập nhật trạng thái thành công",
|
|
91
|
+
"update_status_failed": "Cập nhật trạng thái thất bại",
|
|
92
|
+
"missing_field": "Thiếu {{field}}",
|
|
77
93
|
"validation": {
|
|
78
94
|
"default_message": "Nhập nội dung tin nhắn mặc định",
|
|
79
95
|
"group_name": "Thiếu tên nhóm",
|
|
80
|
-
"group_name_length": "Số ký tự tối đa của tên nhóm là 200"
|
|
96
|
+
"group_name_length": "Số ký tự tối đa của tên nhóm là 200",
|
|
97
|
+
"group_description_length": "Số ký tự đối đa là 200."
|
|
81
98
|
}
|
|
82
|
-
}
|
|
99
|
+
}
|