@droppii-org/chat-sdk 0.1.2 → 0.1.4
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/svg/cannedResponse.d.ts +7 -0
- package/dist/assets/svg/cannedResponse.d.ts.map +1 -0
- package/dist/assets/svg/cannedResponse.js +3 -0
- package/dist/assets/svg/cannedResponse.tsx +48 -0
- package/dist/assets/svg/index.d.ts +1 -0
- package/dist/assets/svg/index.d.ts.map +1 -1
- package/dist/assets/svg/index.js +1 -0
- package/dist/assets/svg/index.ts +1 -0
- package/dist/components/cannedResponse/CannedResponseBody.d.ts +8 -0
- package/dist/components/cannedResponse/CannedResponseBody.d.ts.map +1 -0
- package/dist/components/cannedResponse/CannedResponseBody.js +58 -0
- package/dist/components/cannedResponse/CannedResponseFooter.d.ts +6 -0
- package/dist/components/cannedResponse/CannedResponseFooter.d.ts.map +1 -0
- package/dist/components/cannedResponse/CannedResponseFooter.js +8 -0
- package/dist/components/cannedResponse/CannedResponseHeader.d.ts +8 -0
- package/dist/components/cannedResponse/CannedResponseHeader.d.ts.map +1 -0
- package/dist/components/cannedResponse/CannedResponseHeader.js +11 -0
- package/dist/components/cannedResponse/index.d.ts +8 -0
- package/dist/components/cannedResponse/index.d.ts.map +1 -0
- package/dist/components/cannedResponse/index.js +34 -0
- package/dist/components/cannedResponse/team/TeamItem.d.ts +11 -0
- package/dist/components/cannedResponse/team/TeamItem.d.ts.map +1 -0
- package/dist/components/cannedResponse/team/TeamItem.js +31 -0
- package/dist/components/conversation/ConversationBySessionItem.d.ts.map +1 -1
- package/dist/components/conversation/ConversationBySessionItem.js +6 -2
- package/dist/components/mediaCollection/LinkCollection.js +1 -1
- package/dist/components/message/MediaPreviewIcon.d.ts +7 -0
- package/dist/components/message/MediaPreviewIcon.d.ts.map +1 -0
- package/dist/components/message/MediaPreviewIcon.js +24 -0
- package/dist/components/message/MessageHeader.js +1 -1
- package/dist/components/message/MessageList.d.ts +1 -0
- package/dist/components/message/MessageList.d.ts.map +1 -1
- package/dist/components/message/MessageList.js +49 -6
- package/dist/components/message/footer/ActionBar.d.ts.map +1 -1
- package/dist/components/message/footer/ActionBar.js +15 -86
- package/dist/components/message/footer/CannedResponsePlugin.d.ts +7 -0
- package/dist/components/message/footer/CannedResponsePlugin.d.ts.map +1 -0
- package/dist/components/message/footer/CannedResponsePlugin.js +31 -0
- package/dist/components/message/footer/EmojiPicker.d.ts.map +1 -1
- package/dist/components/message/footer/EmojiPicker.js +9 -5
- package/dist/components/message/footer/EnterHandler.d.ts.map +1 -1
- package/dist/components/message/footer/EnterHandler.js +16 -5
- package/dist/components/message/footer/FilePreview.d.ts +5 -0
- package/dist/components/message/footer/FilePreview.d.ts.map +1 -1
- package/dist/components/message/footer/FilePreview.js +15 -12
- package/dist/components/message/footer/MediaActions.d.ts +10 -0
- package/dist/components/message/footer/MediaActions.d.ts.map +1 -0
- package/dist/components/message/footer/MediaActions.js +98 -0
- package/dist/components/message/footer/QuotedMessage.d.ts +2 -0
- package/dist/components/message/footer/QuotedMessage.d.ts.map +1 -0
- package/dist/components/message/footer/QuotedMessage.js +24 -0
- package/dist/components/message/footer/editorConfig.d.ts +24 -0
- package/dist/components/message/footer/editorConfig.d.ts.map +1 -0
- package/dist/components/message/footer/editorConfig.js +33 -0
- package/dist/components/message/footer/index.d.ts +2 -1
- package/dist/components/message/footer/index.d.ts.map +1 -1
- package/dist/components/message/footer/index.js +33 -28
- package/dist/components/message/item/QuoteMessage.d.ts +9 -0
- package/dist/components/message/item/QuoteMessage.d.ts.map +1 -0
- package/dist/components/message/item/QuoteMessage.js +41 -0
- package/dist/components/message/item/RevokeMessage.d.ts +5 -0
- package/dist/components/message/item/RevokeMessage.d.ts.map +1 -0
- package/dist/components/message/item/RevokeMessage.js +8 -0
- package/dist/components/message/item/TextMessage.js +1 -1
- package/dist/components/message/item/UrlTextMessage.d.ts.map +1 -1
- package/dist/components/message/item/UrlTextMessage.js +3 -3
- package/dist/components/message/item/index.d.ts +6 -1
- package/dist/components/message/item/index.d.ts.map +1 -1
- package/dist/components/message/item/index.js +79 -25
- package/dist/components/richTextEditor/RichTextEditor.d.ts +12 -0
- package/dist/components/richTextEditor/RichTextEditor.d.ts.map +1 -0
- package/dist/components/richTextEditor/RichTextEditor.js +62 -0
- package/dist/components/searchConversation/SearchDrawer.js +1 -1
- package/dist/components/searchConversation/item/SearchItemAsMessage.d.ts +3 -1
- package/dist/components/searchConversation/item/SearchItemAsMessage.d.ts.map +1 -1
- package/dist/components/searchConversation/item/SearchItemAsMessage.js +5 -2
- package/dist/components/thread/AssignConfirmModal.d.ts +12 -0
- package/dist/components/thread/AssignConfirmModal.d.ts.map +1 -0
- package/dist/components/thread/AssignConfirmModal.js +11 -0
- package/dist/components/thread/ManualAssignPopover.d.ts +14 -0
- package/dist/components/thread/ManualAssignPopover.d.ts.map +1 -0
- package/dist/components/thread/ManualAssignPopover.js +83 -0
- package/dist/components/thread/SessionSection.d.ts.map +1 -1
- package/dist/components/thread/SessionSection.js +11 -6
- package/dist/components/thread/UserSection.js +1 -1
- package/dist/hooks/cannedResponse/useFetchCannedCategories.d.ts +3 -0
- package/dist/hooks/cannedResponse/useFetchCannedCategories.d.ts.map +1 -0
- package/dist/hooks/cannedResponse/useFetchCannedCategories.js +13 -0
- package/dist/hooks/cannedResponse/useFetchCannedResponse.d.ts +219 -0
- package/dist/hooks/cannedResponse/useFetchCannedResponse.d.ts.map +1 -0
- package/dist/hooks/cannedResponse/useFetchCannedResponse.js +55 -0
- package/dist/hooks/message/useMessage.d.ts.map +1 -1
- package/dist/hooks/message/useMessage.js +18 -1
- package/dist/hooks/message/useRevokeMessage.d.ts +5 -0
- package/dist/hooks/message/useRevokeMessage.d.ts.map +1 -0
- package/dist/hooks/message/useRevokeMessage.js +16 -0
- package/dist/hooks/message/useSendMessage.d.ts +1 -0
- package/dist/hooks/message/useSendMessage.d.ts.map +1 -1
- package/dist/hooks/message/useSendMessage.js +40 -9
- package/dist/hooks/session/useAssignSession.d.ts +8 -0
- package/dist/hooks/session/useAssignSession.d.ts.map +1 -0
- package/dist/hooks/session/useAssignSession.js +15 -0
- package/dist/hooks/session/useCreateNote.d.ts.map +1 -1
- package/dist/hooks/session/useCreateNote.js +2 -1
- package/dist/hooks/session/useGetTeamSupporters.d.ts +8 -0
- package/dist/hooks/session/useGetTeamSupporters.d.ts.map +1 -0
- package/dist/hooks/session/useGetTeamSupporters.js +20 -0
- package/dist/hooks/team/useFetchMyTeam.d.ts +3 -0
- package/dist/hooks/team/useFetchMyTeam.d.ts.map +1 -0
- package/dist/hooks/team/useFetchMyTeam.js +12 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/locales/vi/common.json +54 -53
- package/dist/screens/deskMessage/index.d.ts +4 -1
- package/dist/screens/deskMessage/index.d.ts.map +1 -1
- package/dist/screens/deskMessage/index.js +2 -2
- package/dist/services/query.d.ts +5 -0
- package/dist/services/query.d.ts.map +1 -1
- package/dist/services/query.js +5 -0
- package/dist/services/routes.d.ts +5 -0
- package/dist/services/routes.d.ts.map +1 -1
- package/dist/services/routes.js +5 -0
- package/dist/store/conversation.d.ts.map +1 -1
- package/dist/store/conversation.js +7 -1
- package/dist/styles/global.css +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/dist/types/chat.d.ts +7 -1
- package/dist/types/chat.d.ts.map +1 -1
- package/dist/types/chat.js +5 -0
- package/dist/types/dto.d.ts +53 -1
- package/dist/types/dto.d.ts.map +1 -1
- package/dist/utils/common.d.ts +3 -2
- package/dist/utils/common.d.ts.map +1 -1
- package/dist/utils/common.js +43 -19
- package/dist/utils/fileValidation.d.ts.map +1 -1
- package/dist/utils/fileValidation.js +2 -8
- package/dist/utils/queryHelpers.d.ts +3 -0
- package/dist/utils/queryHelpers.d.ts.map +1 -0
- package/dist/utils/queryHelpers.js +11 -0
- package/package.json +1 -1
|
@@ -7,52 +7,41 @@ import { LexicalErrorBoundary } from "@lexical/react/LexicalErrorBoundary";
|
|
|
7
7
|
import { ToolbarPlugin } from "./ToolbarPlugin";
|
|
8
8
|
import { LinkPlugin } from "@lexical/react/LexicalLinkPlugin";
|
|
9
9
|
import { ListPlugin } from "@lexical/react/LexicalListPlugin";
|
|
10
|
-
import {
|
|
11
|
-
import { HeadingNode, QuoteNode } from "@lexical/rich-text";
|
|
12
|
-
import { ListItemNode, ListNode } from "@lexical/list";
|
|
10
|
+
import { editorTheme, editorNodes, editorOnError } from "./editorConfig";
|
|
13
11
|
import { createContext, useCallback, useContext, useState } from "react";
|
|
14
12
|
import EnterHandler from "./EnterHandler";
|
|
15
13
|
import ActionBar from "./ActionBar";
|
|
16
14
|
import { useSendMessage } from "../../../hooks/message/useSendMessage";
|
|
15
|
+
import { Popover } from "antd";
|
|
17
16
|
import FilePreview from "./FilePreview";
|
|
18
17
|
import { useTranslation } from "react-i18next";
|
|
19
18
|
import PasteAndDropPlugin from "./PasteAndDropPlugin";
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
underline: "underline",
|
|
26
|
-
},
|
|
27
|
-
quote: "border-l-4 border-gray-300 pl-4 italic text-gray-600",
|
|
28
|
-
list: {
|
|
29
|
-
nested: {
|
|
30
|
-
listitem: "list-none",
|
|
31
|
-
},
|
|
32
|
-
ol: "list-decimal list-inside",
|
|
33
|
-
ul: "list-disc list-inside",
|
|
34
|
-
},
|
|
35
|
-
link: "text-blue-500 underline hover:text-blue-700",
|
|
36
|
-
};
|
|
37
|
-
const onError = (error) => {
|
|
38
|
-
console.error(error);
|
|
39
|
-
};
|
|
19
|
+
import { QuotedMessageFooter } from "./QuotedMessage";
|
|
20
|
+
import CannedResponse from "../../cannedResponse";
|
|
21
|
+
import { CannedResponseTriggerPlugin } from "./CannedResponsePlugin";
|
|
22
|
+
import { useBoolean } from "ahooks";
|
|
23
|
+
import useAuthStore from "../../../store/auth";
|
|
40
24
|
const initialConfig = {
|
|
41
25
|
namespace: "ChatInput",
|
|
42
|
-
theme,
|
|
43
|
-
onError,
|
|
44
|
-
nodes:
|
|
26
|
+
theme: editorTheme,
|
|
27
|
+
onError: editorOnError,
|
|
28
|
+
nodes: editorNodes,
|
|
45
29
|
};
|
|
46
30
|
export const MessageFooterContext = createContext({
|
|
47
31
|
onSendMessage: () => { },
|
|
48
32
|
listUploadFiles: [],
|
|
49
33
|
setListUploadFiles: () => { },
|
|
34
|
+
isOpenCanned: false,
|
|
35
|
+
setIsOpenCanned: () => { },
|
|
50
36
|
});
|
|
51
37
|
export const useMessageFooterContext = () => useContext(MessageFooterContext);
|
|
52
|
-
const MessageFooterProvider = ({ currentSession }) => {
|
|
38
|
+
const MessageFooterProvider = ({ currentSession, openCreateCannedModal, }) => {
|
|
53
39
|
const { t } = useTranslation();
|
|
54
40
|
const { sendTextMessage, sendMergeMessage } = useSendMessage();
|
|
55
41
|
const [listUploadFiles, setListUploadFiles] = useState([]);
|
|
42
|
+
const [isOpenCanned, { setTrue: openCanned, setFalse: closeCanned, toggle: toggleCanned },] = useBoolean(false);
|
|
43
|
+
const isCrm = useAuthStore((state) => state.isCrm);
|
|
44
|
+
const [cannedQuery, setCannedQuery] = useState("");
|
|
56
45
|
const onSendMessage = useCallback(async ({ plainText, richText, type, }) => {
|
|
57
46
|
if (type === "text") {
|
|
58
47
|
sendTextMessage({ plainText, richText, currentSession });
|
|
@@ -67,6 +56,22 @@ const MessageFooterProvider = ({ currentSession }) => {
|
|
|
67
56
|
}
|
|
68
57
|
setListUploadFiles([]);
|
|
69
58
|
}, [sendMergeMessage, sendTextMessage, listUploadFiles, currentSession]);
|
|
70
|
-
|
|
59
|
+
const onOpenCreateCannedModal = useCallback(() => {
|
|
60
|
+
closeCanned();
|
|
61
|
+
openCreateCannedModal === null || openCreateCannedModal === void 0 ? void 0 : openCreateCannedModal();
|
|
62
|
+
}, [closeCanned, openCreateCannedModal]);
|
|
63
|
+
const onOpenCanned = useCallback((query) => {
|
|
64
|
+
setCannedQuery(query);
|
|
65
|
+
openCanned();
|
|
66
|
+
}, [openCanned]);
|
|
67
|
+
return (_jsx(MessageFooterContext.Provider, { value: {
|
|
68
|
+
onSendMessage,
|
|
69
|
+
listUploadFiles,
|
|
70
|
+
setListUploadFiles,
|
|
71
|
+
isOpenCanned,
|
|
72
|
+
setIsOpenCanned: toggleCanned,
|
|
73
|
+
}, children: _jsxs(LexicalComposer, { initialConfig: initialConfig, children: [_jsx(Popover, { open: isOpenCanned, content: _jsx(CannedResponse, { onClose: closeCanned, openCreateCannedModal: onOpenCreateCannedModal, cannedQuery: cannedQuery }), placement: "topLeft", trigger: "click", arrow: false, classNames: {
|
|
74
|
+
body: "mx-1 !p-0",
|
|
75
|
+
}, destroyOnHidden: true, children: _jsxs("div", { className: "border-t pb-2 flex flex-col gap-1 bg-white", children: [_jsx(QuotedMessageFooter, {}), listUploadFiles.length > 0 && _jsx(FilePreview, {}), _jsx(ToolbarPlugin, {}), _jsx("div", { className: "relative px-4", children: _jsx(RichTextPlugin, { contentEditable: _jsx(ContentEditable, { className: "border border-indigo-500 rounded-md bg-blue-100 min-h-[64px] max-h-[140px] overflow-y-auto px-3 py-2 text-sm" }), ErrorBoundary: LexicalErrorBoundary, "aria-placeholder": t("enter_message"), placeholder: _jsx("div", { className: "absolute top-2 left-7 pointer-events-none", children: _jsx("p", { className: "text-gray-500 text-sm", children: t("enter_message") }) }) }) }), _jsx(ActionBar, {})] }) }), _jsx(LinkPlugin, {}), _jsx(ListPlugin, {}), _jsx(EnterHandler, {}), _jsx(PasteAndDropPlugin, {}), isCrm && (_jsx(CannedResponseTriggerPlugin, { onClose: closeCanned, onOpen: onOpenCanned }))] }) }));
|
|
71
76
|
};
|
|
72
77
|
export default MessageFooterProvider;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { MessageItem } from "@openim/wasm-client-sdk";
|
|
2
|
+
interface QuoteMessageItemProps {
|
|
3
|
+
message: MessageItem;
|
|
4
|
+
isMine: boolean;
|
|
5
|
+
onPressQuoteMessage?: (clientMsgID: string) => void;
|
|
6
|
+
}
|
|
7
|
+
declare const QuoteMessageItem: ({ message, isMine, onPressQuoteMessage, }: QuoteMessageItemProps) => import("react/jsx-runtime").JSX.Element;
|
|
8
|
+
export default QuoteMessageItem;
|
|
9
|
+
//# sourceMappingURL=QuoteMessage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"QuoteMessage.d.ts","sourceRoot":"","sources":["../../../../src/components/message/item/QuoteMessage.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAe,MAAM,yBAAyB,CAAC;AAUnE,UAAU,qBAAqB;IAC7B,OAAO,EAAE,WAAW,CAAC;IACrB,MAAM,EAAE,OAAO,CAAC;IAChB,mBAAmB,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;CACrD;AAED,QAAA,MAAM,gBAAgB,GAAI,2CAIvB,qBAAqB,4CA+DvB,CAAC;AAEF,eAAe,gBAAgB,CAAC"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { generateContentBasedOnMessageType } from "../../../utils/common";
|
|
3
|
+
import { Icon } from "../../icon";
|
|
4
|
+
import { useTranslation } from "react-i18next";
|
|
5
|
+
import clsx from "clsx";
|
|
6
|
+
import MediaPreviewIcon from "../MediaPreviewIcon";
|
|
7
|
+
import useAuthStore from "../../../store/auth";
|
|
8
|
+
import { useMemo } from "react";
|
|
9
|
+
import useConversationStore from "../../../store/conversation";
|
|
10
|
+
const QuoteMessageItem = ({ message, isMine, onPressQuoteMessage, }) => {
|
|
11
|
+
var _a, _b, _c, _d, _e, _f;
|
|
12
|
+
const userID = useAuthStore((state) => state.userID);
|
|
13
|
+
const isCrm = useAuthStore((state) => state.isCrm);
|
|
14
|
+
const conversationData = useConversationStore((state) => state.conversationData);
|
|
15
|
+
const { t } = useTranslation();
|
|
16
|
+
const { from, to } = useMemo(() => {
|
|
17
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
18
|
+
const isChatSupport = (_d = (_c = (_b = (_a = JSON === null || JSON === void 0 ? void 0 : JSON.parse) === null || _a === void 0 ? void 0 : _a.call(JSON, (conversationData === null || conversationData === void 0 ? void 0 : conversationData.ex) || "{}")) === null || _b === void 0 ? void 0 : _b.sessionInfo) === null || _c === void 0 ? void 0 : _c.data) === null || _d === void 0 ? void 0 : _d.botId;
|
|
19
|
+
const isQuoteFromYourself = ((_f = (_e = message === null || message === void 0 ? void 0 : message.quoteElem) === null || _e === void 0 ? void 0 : _e.quoteMessage) === null || _f === void 0 ? void 0 : _f.sendID) === (message === null || message === void 0 ? void 0 : message.sendID);
|
|
20
|
+
return {
|
|
21
|
+
from: isChatSupport && !isCrm
|
|
22
|
+
? isMine
|
|
23
|
+
? t("you")
|
|
24
|
+
: conversationData === null || conversationData === void 0 ? void 0 : conversationData.showName
|
|
25
|
+
: message === null || message === void 0 ? void 0 : message.senderNickname,
|
|
26
|
+
to: isQuoteFromYourself
|
|
27
|
+
? t("your_self")
|
|
28
|
+
: isChatSupport && !isCrm
|
|
29
|
+
? conversationData === null || conversationData === void 0 ? void 0 : conversationData.showName
|
|
30
|
+
: (_h = (_g = message === null || message === void 0 ? void 0 : message.quoteElem) === null || _g === void 0 ? void 0 : _g.quoteMessage) === null || _h === void 0 ? void 0 : _h.senderNickname,
|
|
31
|
+
};
|
|
32
|
+
}, [isMine, message, t, conversationData, userID]);
|
|
33
|
+
return (_jsxs("div", { className: clsx("mb-[-4px] flex flex-col gap-1 flex-1 w-full", isMine ? "items-end" : "items-start"), children: [_jsxs("div", { className: "flex flex-row flex-1 items-center gap-2", children: [_jsx(Icon, { icon: "arrow-reply-b", size: 16, className: "text-blue-500" }), _jsx("span", { className: "text-xs text-gray-500", children: t("replied_to", {
|
|
34
|
+
from: from,
|
|
35
|
+
to: to,
|
|
36
|
+
}) })] }), _jsxs("div", { className: "flex flex-row flex-1 max-w-full items-center gap-2 border border-gray-200 rounded-2xl min-w-0 px-3 py-2 bg-gray-100 cursor-pointer", onClick: () => {
|
|
37
|
+
var _a, _b;
|
|
38
|
+
return onPressQuoteMessage === null || onPressQuoteMessage === void 0 ? void 0 : onPressQuoteMessage(((_b = (_a = message === null || message === void 0 ? void 0 : message.quoteElem) === null || _a === void 0 ? void 0 : _a.quoteMessage) === null || _b === void 0 ? void 0 : _b.clientMsgID) || "");
|
|
39
|
+
}, children: [_jsx(MediaPreviewIcon, { message: (_a = message === null || message === void 0 ? void 0 : message.quoteElem) === null || _a === void 0 ? void 0 : _a.quoteMessage }), _jsx("span", { className: "text-sm text-gray-500 truncate", children: generateContentBasedOnMessageType((_c = (_b = message === null || message === void 0 ? void 0 : message.quoteElem) === null || _b === void 0 ? void 0 : _b.quoteMessage) === null || _c === void 0 ? void 0 : _c.contentType, ((_f = (_e = (_d = message === null || message === void 0 ? void 0 : message.quoteElem) === null || _d === void 0 ? void 0 : _d.quoteMessage) === null || _e === void 0 ? void 0 : _e.textElem) === null || _f === void 0 ? void 0 : _f.content) || "") })] })] }));
|
|
40
|
+
};
|
|
41
|
+
export default QuoteMessageItem;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RevokeMessage.d.ts","sourceRoot":"","sources":["../../../../src/components/message/item/RevokeMessage.tsx"],"names":[],"mappings":"AAIA,UAAU,sBAAsB;CAAG;AACnC,QAAA,MAAM,iBAAiB,GAAI,GAAG,sBAAsB,4CAQnD,CAAC;AAEF,eAAe,iBAAiB,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { useTranslation } from "react-i18next";
|
|
4
|
+
const RevokeMessageItem = (_) => {
|
|
5
|
+
const { t } = useTranslation();
|
|
6
|
+
return (_jsx("span", { className: "!text-sm sm:text-base whitespace-pre-wrap italic text-gray-500", children: t("revoked") }));
|
|
7
|
+
};
|
|
8
|
+
export default RevokeMessageItem;
|
|
@@ -23,7 +23,7 @@ const TextMessageItem = (props) => {
|
|
|
23
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) || "";
|
|
24
24
|
// 🔒 Sanitize HTML to prevent XSS attacks
|
|
25
25
|
const sanitizedContent = sanitizeHtml(htmlContent);
|
|
26
|
-
return (_jsx("div", { className: "!text-sm sm:text-base break-
|
|
26
|
+
return (_jsx("div", { className: "!text-sm sm:text-base break-normal whitespace-pre-line flex-1", style: { overflowWrap: "anywhere" }, dangerouslySetInnerHTML: { __html: sanitizedContent } }));
|
|
27
27
|
}
|
|
28
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) || "" }));
|
|
29
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;
|
|
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;AAUtD,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, sanitizeHtml } 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) => {
|
|
@@ -25,8 +25,8 @@ const UrlTextMessageItem = (props) => {
|
|
|
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
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-
|
|
28
|
+
return (_jsxs("div", { className: "flex flex-col gap-2", children: [_jsx("div", { className: "!text-sm sm:text-base break-normal whitespace-pre-line flex-1", style: { 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 break-normal", 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 }))] }))] }));
|
|
29
29
|
}
|
|
30
|
-
return (_jsx("span", { className: "!text-sm sm:text-base break-
|
|
30
|
+
return (_jsx("span", { className: "!text-sm sm:text-base break-normal whitespace-pre-line flex-1", style: { 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]) || "" }));
|
|
31
31
|
};
|
|
32
32
|
export default UrlTextMessageItem;
|
|
@@ -2,7 +2,12 @@ import { MessageItem as MessageItemType } from "@openim/wasm-client-sdk";
|
|
|
2
2
|
interface MessageItemProps {
|
|
3
3
|
message: MessageItemType;
|
|
4
4
|
allMessages: MessageItemType[];
|
|
5
|
+
contextMenuOpen?: boolean;
|
|
6
|
+
onContextMenuOpenChange?: (open: boolean) => void;
|
|
7
|
+
onRevokeMessage?: (clientMsgID: string) => void;
|
|
8
|
+
onQuoteMessage?: (message: MessageItemType) => void;
|
|
9
|
+
onPressQuoteMessage?: (clientMsgID: string) => void;
|
|
5
10
|
}
|
|
6
|
-
declare const MessageItem: ({ message, allMessages }: MessageItemProps) => import("react/jsx-runtime").JSX.Element | null;
|
|
11
|
+
declare const MessageItem: ({ message, allMessages, contextMenuOpen, onContextMenuOpenChange, onRevokeMessage, onQuoteMessage, onPressQuoteMessage, }: MessageItemProps) => import("react/jsx-runtime").JSX.Element | null;
|
|
7
12
|
export default MessageItem;
|
|
8
13
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -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,EAG/B,MAAM,yBAAyB,CAAC;
|
|
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;AA2BjC,UAAU,gBAAgB;IACxB,OAAO,EAAE,eAAe,CAAC;IACzB,WAAW,EAAE,eAAe,EAAE,CAAC;IAC/B,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,uBAAuB,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IAClD,eAAe,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;IAChD,cAAc,CAAC,EAAE,CAAC,OAAO,EAAE,eAAe,KAAK,IAAI,CAAC;IACpD,mBAAmB,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;CACrD;AAED,QAAA,MAAM,WAAW,GAAI,2HAQlB,gBAAgB,mDA0PlB,CAAC;AAEF,eAAe,WAAW,CAAC"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import dayjs from "dayjs";
|
|
3
3
|
import clsx from "clsx";
|
|
4
|
-
import { Avatar } from "antd";
|
|
4
|
+
import { Avatar, Dropdown } from "antd";
|
|
5
5
|
import { MessageStatus, MessageType, } from "@openim/wasm-client-sdk";
|
|
6
6
|
import TextMessageItem from "./TextMessage";
|
|
7
7
|
import ImageMessageItem from "./ImageMessage";
|
|
@@ -12,32 +12,26 @@ import { MSG_ITEM_CONTENT_PREFIX, MSG_ITEM_PREFIX } from "../../../constants";
|
|
|
12
12
|
import { formatTimestamp } from "../../../utils/common";
|
|
13
13
|
import useAuthStore from "../../../store/auth";
|
|
14
14
|
import useConversationStore from "../../../store/conversation";
|
|
15
|
-
import { useMemo } from "react";
|
|
15
|
+
import { useCallback, useMemo } from "react";
|
|
16
16
|
import { Trans, useTranslation } from "react-i18next";
|
|
17
17
|
import UrlTextMessageItem from "./UrlTextMessage";
|
|
18
18
|
import MessageStatusIndicator from "./MessageStatusIndicator";
|
|
19
|
-
import { useSendMessage, isMediaResendable } from "../../../hooks/message/useSendMessage";
|
|
20
|
-
|
|
19
|
+
import { useSendMessage, isMediaResendable, } from "../../../hooks/message/useSendMessage";
|
|
20
|
+
import { Icon } from "../../icon";
|
|
21
|
+
import RevokeMessageItem from "./RevokeMessage";
|
|
22
|
+
import QuoteMessageItem from "./QuoteMessage";
|
|
23
|
+
const ICON_COLOR = "#3278f7";
|
|
24
|
+
const MessageItem = ({ message, allMessages, contextMenuOpen, onContextMenuOpenChange, onRevokeMessage, onQuoteMessage, onPressQuoteMessage, }) => {
|
|
21
25
|
var _a, _b, _c, _d, _e;
|
|
22
26
|
const { t } = useTranslation();
|
|
23
27
|
const { resendMessage } = useSendMessage();
|
|
24
28
|
const userID = useAuthStore((state) => state.userID);
|
|
25
29
|
const isCrm = useAuthStore((state) => state.isCrm);
|
|
26
30
|
const conversationData = useConversationStore((state) => state.conversationData);
|
|
27
|
-
const
|
|
28
|
-
var _a, _b, _c;
|
|
29
|
-
try {
|
|
30
|
-
const isChatSupport = (_c = (_b = (_a = JSON.parse((conversationData === null || conversationData === void 0 ? void 0 : conversationData.ex) || "{}")) === null || _a === void 0 ? void 0 : _a.sessionInfo) === null || _b === void 0 ? void 0 : _b.data) === null || _c === void 0 ? void 0 : _c.botId;
|
|
31
|
-
return isChatSupport && isCrm;
|
|
32
|
-
}
|
|
33
|
-
catch (_d) {
|
|
34
|
-
console.log("Failed to parse conversationData.ex");
|
|
35
|
-
}
|
|
36
|
-
}, [conversationData === null || conversationData === void 0 ? void 0 : conversationData.ex, isCrm]);
|
|
37
|
-
const isVisibleGroup = visibleTypeMessage.includes(message === null || message === void 0 ? void 0 : message.contentType);
|
|
38
|
-
const renderMessageByType = (message) => {
|
|
31
|
+
const renderMessageByType = useCallback((message) => {
|
|
39
32
|
switch (message === null || message === void 0 ? void 0 : message.contentType) {
|
|
40
33
|
case MessageType.TextMessage:
|
|
34
|
+
case MessageType.QuoteMessage:
|
|
41
35
|
return _jsx(TextMessageItem, { message: message });
|
|
42
36
|
case MessageType.PictureMessage:
|
|
43
37
|
return _jsx(ImageMessageItem, { message: message });
|
|
@@ -47,13 +41,68 @@ const MessageItem = ({ message, allMessages }) => {
|
|
|
47
41
|
return _jsx(VideoMessageItem, { message: message });
|
|
48
42
|
case MessageType.UrlTextMessage:
|
|
49
43
|
return _jsx(UrlTextMessageItem, { message: message });
|
|
44
|
+
case MessageType.RevokeMessage:
|
|
45
|
+
return _jsx(RevokeMessageItem, {});
|
|
50
46
|
default:
|
|
51
47
|
return _jsx(TextMessageItem, { message: message });
|
|
52
48
|
}
|
|
53
|
-
};
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
49
|
+
}, [message]);
|
|
50
|
+
const { isReplyable, isRevocable, isMine } = useMemo(() => {
|
|
51
|
+
const isMyMessage = (message === null || message === void 0 ? void 0 : message.sendID) === userID;
|
|
52
|
+
const isOlderThanOneDay = dayjs().diff(dayjs(message === null || message === void 0 ? void 0 : message.sendTime), "days", true) >= 1;
|
|
53
|
+
return {
|
|
54
|
+
isReplyable: message.status === MessageStatus.Succeed,
|
|
55
|
+
isRevocable: isMyMessage &&
|
|
56
|
+
message.status === MessageStatus.Succeed &&
|
|
57
|
+
!isOlderThanOneDay,
|
|
58
|
+
isMine: isMyMessage,
|
|
59
|
+
};
|
|
60
|
+
}, [userID, message]);
|
|
61
|
+
const contextMenuItems = useMemo(() => {
|
|
62
|
+
if ((message === null || message === void 0 ? void 0 : message.contentType) === MessageType.RevokeMessage)
|
|
63
|
+
return [];
|
|
64
|
+
return [
|
|
65
|
+
...(isReplyable
|
|
66
|
+
? [
|
|
67
|
+
{
|
|
68
|
+
key: "TB01",
|
|
69
|
+
label: t("context_menu_reply"),
|
|
70
|
+
icon: (_jsx(Icon, { icon: "arrow-reply-alt-o", size: 18, color: ICON_COLOR })),
|
|
71
|
+
onClick: () => onQuoteMessage === null || onQuoteMessage === void 0 ? void 0 : onQuoteMessage(message),
|
|
72
|
+
},
|
|
73
|
+
]
|
|
74
|
+
: []),
|
|
75
|
+
...(isRevocable
|
|
76
|
+
? [
|
|
77
|
+
{
|
|
78
|
+
key: "TB05",
|
|
79
|
+
label: t("context_menu_revoke"),
|
|
80
|
+
icon: _jsx(Icon, { icon: "arrow-reload-o", size: 18, color: ICON_COLOR }),
|
|
81
|
+
onClick: () => onRevokeMessage === null || onRevokeMessage === void 0 ? void 0 : onRevokeMessage((message === null || message === void 0 ? void 0 : message.clientMsgID) || ""),
|
|
82
|
+
},
|
|
83
|
+
]
|
|
84
|
+
: []),
|
|
85
|
+
];
|
|
86
|
+
}, [
|
|
87
|
+
isReplyable,
|
|
88
|
+
isRevocable,
|
|
89
|
+
t,
|
|
90
|
+
onRevokeMessage,
|
|
91
|
+
message === null || message === void 0 ? void 0 : message.contentType,
|
|
92
|
+
message === null || message === void 0 ? void 0 : message.clientMsgID,
|
|
93
|
+
onQuoteMessage,
|
|
94
|
+
]);
|
|
95
|
+
const showSenderInfo = useMemo(() => {
|
|
96
|
+
var _a, _b, _c;
|
|
97
|
+
try {
|
|
98
|
+
const isChatSupport = (_c = (_b = (_a = JSON.parse((conversationData === null || conversationData === void 0 ? void 0 : conversationData.ex) || "{}")) === null || _a === void 0 ? void 0 : _a.sessionInfo) === null || _b === void 0 ? void 0 : _b.data) === null || _c === void 0 ? void 0 : _c.botId;
|
|
99
|
+
return isChatSupport && isCrm && !isMine;
|
|
100
|
+
}
|
|
101
|
+
catch (_d) {
|
|
102
|
+
console.log("Failed to parse conversationData.ex");
|
|
103
|
+
}
|
|
104
|
+
}, [conversationData === null || conversationData === void 0 ? void 0 : conversationData.ex, isCrm, isMine]);
|
|
105
|
+
const hasContextMenu = contextMenuItems.length > 0;
|
|
57
106
|
const isLatestMine = ((_a = allMessages.find((m) => m.sendID === userID)) === null || _a === void 0 ? void 0 : _a.clientMsgID) ===
|
|
58
107
|
message.clientMsgID;
|
|
59
108
|
const previousMessage = getVisibleNeighbor(allMessages, message, "prev");
|
|
@@ -65,15 +114,20 @@ const MessageItem = ({ message, allMessages }) => {
|
|
|
65
114
|
const showTimeBreak = prevTimeBreak;
|
|
66
115
|
const showSenderAvatar = !nextSameUser;
|
|
67
116
|
const showSenderName = !prevSameUser && !isMine;
|
|
68
|
-
if (!isCrm &&
|
|
117
|
+
if (!isCrm &&
|
|
118
|
+
(MessageType.CustomMessage === (message === null || message === void 0 ? void 0 : message.contentType) ||
|
|
119
|
+
!visibleTypeMessage.includes(message === null || message === void 0 ? void 0 : message.contentType))) {
|
|
69
120
|
return null;
|
|
70
121
|
}
|
|
71
122
|
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, {
|
|
72
123
|
dateMonthFormat: "DD MMMM",
|
|
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: [
|
|
74
|
-
|
|
75
|
-
|
|
124
|
+
}) }) })), _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: [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 max-w-[75%] min-w-0", isMine ? "items-end" : "items-start"), children: [showSenderName && showSenderInfo && (_jsx("span", { className: "text-xs font-bold mb-1 px-3 mt-2", children: message === null || message === void 0 ? void 0 : message.senderNickname })), _jsxs("div", { className: clsx("flex flex-col flex-1 w-full", isMine ? "items-end" : "items-start"), children: [(message === null || message === void 0 ? void 0 : message.quoteElem) && (_jsx(QuoteMessageItem, { message: message, isMine: isMine, onPressQuoteMessage: onPressQuoteMessage })), _jsxs("div", { className: "flex items-end gap-1.5", children: [isMine && (_jsx(MessageStatusIndicator, { message: message, isLatest: isLatestMine })), _jsx(Dropdown, { menu: { items: contextMenuItems }, trigger: hasContextMenu ? ["contextMenu"] : [], open: contextMenuOpen, onOpenChange: onContextMenuOpenChange, children: _jsxs("div", { className: clsx("px-3 py-2 rounded-2xl max-w-full min-w-0 break-normal flex flex-col flex-1 text-gray-900 gap-1 w-fit", isMine ? "bg-blue-100" : "bg-white"), style: {
|
|
125
|
+
wordBreak: "break-word",
|
|
126
|
+
overflowWrap: "anywhere",
|
|
127
|
+
}, 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) => {
|
|
128
|
+
return renderMessageByType(item);
|
|
129
|
+
}), (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
130
|
bold: (_jsx("strong", { className: "cursor-pointer", onClick: () => resendMessage(message) })),
|
|
77
|
-
} })) : (t("message_send_failed_no_retry")) }))] })] }) }
|
|
131
|
+
} })) : (t("message_send_failed_no_retry")) }))] })] }) })] }, message === null || message === void 0 ? void 0 : message.clientMsgID));
|
|
78
132
|
};
|
|
79
133
|
export default MessageItem;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { UploadFile } from "antd";
|
|
2
|
+
interface RichTextEditorProps {
|
|
3
|
+
initialHtml?: string;
|
|
4
|
+
placeholder?: string;
|
|
5
|
+
onChange?: (html: string, plainText: string) => void;
|
|
6
|
+
onFilesChange?: (files: UploadFile[]) => void;
|
|
7
|
+
minHeight?: string;
|
|
8
|
+
showMediaUpload?: boolean;
|
|
9
|
+
}
|
|
10
|
+
export default function RichTextEditor({ initialHtml, placeholder, onChange, onFilesChange, minHeight, showMediaUpload, }: RichTextEditorProps): import("react/jsx-runtime").JSX.Element;
|
|
11
|
+
export {};
|
|
12
|
+
//# sourceMappingURL=RichTextEditor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RichTextEditor.d.ts","sourceRoot":"","sources":["../../../src/components/richTextEditor/RichTextEditor.tsx"],"names":[],"mappings":"AAYA,OAAO,EAAE,UAAU,EAAE,MAAM,MAAM,CAAC;AA0ClC,UAAU,mBAAmB;IAC3B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IACrD,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,EAAE,KAAK,IAAI,CAAC;IAC9C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED,MAAM,CAAC,OAAO,UAAU,cAAc,CAAC,EACrC,WAAW,EACX,WAAW,EACX,QAAQ,EACR,aAAa,EACb,SAAmB,EACnB,eAAsB,GACvB,EAAE,mBAAmB,2CA6DrB"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useState } from "react";
|
|
4
|
+
import { LexicalComposer } from "@lexical/react/LexicalComposer";
|
|
5
|
+
import { RichTextPlugin } from "@lexical/react/LexicalRichTextPlugin";
|
|
6
|
+
import { ContentEditable } from "@lexical/react/LexicalContentEditable";
|
|
7
|
+
import { LexicalErrorBoundary } from "@lexical/react/LexicalErrorBoundary";
|
|
8
|
+
import { LinkPlugin } from "@lexical/react/LexicalLinkPlugin";
|
|
9
|
+
import { ListPlugin } from "@lexical/react/LexicalListPlugin";
|
|
10
|
+
import { OnChangePlugin } from "@lexical/react/LexicalOnChangePlugin";
|
|
11
|
+
import { $generateHtmlFromNodes, $generateNodesFromDOM } from "@lexical/html";
|
|
12
|
+
import { $getRoot } from "lexical";
|
|
13
|
+
import { useLexicalComposerContext } from "@lexical/react/LexicalComposerContext";
|
|
14
|
+
import { useEffect } from "react";
|
|
15
|
+
import { ToolbarPlugin } from "../message/footer/ToolbarPlugin";
|
|
16
|
+
import MediaActions from "../message/footer/MediaActions";
|
|
17
|
+
import { FilePreviewList } from "../message/footer/FilePreview";
|
|
18
|
+
import { editorTheme, editorNodes, editorOnError, } from "../message/footer/editorConfig";
|
|
19
|
+
const EDITOR_CONFIG = {
|
|
20
|
+
namespace: "CannedResponseEditor",
|
|
21
|
+
theme: editorTheme,
|
|
22
|
+
onError: editorOnError,
|
|
23
|
+
nodes: editorNodes,
|
|
24
|
+
};
|
|
25
|
+
function HtmlPlugin({ initialHtml }) {
|
|
26
|
+
const [editor] = useLexicalComposerContext();
|
|
27
|
+
useEffect(() => {
|
|
28
|
+
if (!initialHtml)
|
|
29
|
+
return;
|
|
30
|
+
editor.update(() => {
|
|
31
|
+
const parser = new DOMParser();
|
|
32
|
+
const dom = parser.parseFromString(initialHtml, "text/html");
|
|
33
|
+
const nodes = $generateNodesFromDOM(editor, dom);
|
|
34
|
+
const root = $getRoot();
|
|
35
|
+
root.clear();
|
|
36
|
+
root.append(...nodes);
|
|
37
|
+
}, { tag: "initial-html" });
|
|
38
|
+
}, [editor, initialHtml]);
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
export default function RichTextEditor({ initialHtml, placeholder, onChange, onFilesChange, minHeight = "160px", showMediaUpload = true, }) {
|
|
42
|
+
const [listUploadFiles, setListUploadFiles] = useState([]);
|
|
43
|
+
const handleChange = (editorState, editor, tags) => {
|
|
44
|
+
if (tags.has("initial-html"))
|
|
45
|
+
return;
|
|
46
|
+
editorState.read(() => {
|
|
47
|
+
const html = $generateHtmlFromNodes(editor);
|
|
48
|
+
const plainText = $getRoot().getTextContent().trim();
|
|
49
|
+
onChange === null || onChange === void 0 ? void 0 : onChange(html, plainText);
|
|
50
|
+
});
|
|
51
|
+
};
|
|
52
|
+
const handleRemoveFile = (file) => {
|
|
53
|
+
const newList = listUploadFiles.filter((f) => f.uid !== file.uid);
|
|
54
|
+
setListUploadFiles(newList);
|
|
55
|
+
onFilesChange === null || onFilesChange === void 0 ? void 0 : onFilesChange(newList);
|
|
56
|
+
};
|
|
57
|
+
const handleFilesChange = (files) => {
|
|
58
|
+
setListUploadFiles(files);
|
|
59
|
+
onFilesChange === null || onFilesChange === void 0 ? void 0 : onFilesChange(files);
|
|
60
|
+
};
|
|
61
|
+
return (_jsxs(LexicalComposer, { initialConfig: EDITOR_CONFIG, children: [_jsxs("div", { className: "border border-gray-200 rounded-lg", children: [_jsx(FilePreviewList, { files: listUploadFiles, onRemove: handleRemoveFile }), _jsx("div", { className: "relative", children: _jsx(RichTextPlugin, { contentEditable: _jsx(ContentEditable, { className: "px-3 py-2 text-sm outline-none", style: { minHeight } }), ErrorBoundary: LexicalErrorBoundary, placeholder: placeholder ? (_jsx("div", { className: "absolute top-2 left-3 pointer-events-none", children: _jsx("p", { className: "text-gray-400 text-sm", children: placeholder }) })) : null }) }), _jsxs("div", { className: "flex items-center border-t border-gray-100 px-2 py-1", children: [_jsx(ToolbarPlugin, {}), _jsx(MediaActions, { listUploadFiles: listUploadFiles, onFilesChange: handleFilesChange, showMediaUpload: showMediaUpload })] })] }), _jsx(LinkPlugin, {}), _jsx(ListPlugin, {}), _jsx(OnChangePlugin, { onChange: handleChange, ignoreSelectionChange: true }), _jsx(HtmlPlugin, { initialHtml: initialHtml })] }));
|
|
62
|
+
}
|
|
@@ -26,7 +26,7 @@ const SearchDrawer = () => {
|
|
|
26
26
|
padding: 0,
|
|
27
27
|
height: "100%",
|
|
28
28
|
},
|
|
29
|
-
}, getContainer: false, width: isMobile ? "100%" : 360, children: _jsxs("div", { className: "flex flex-col h-full", children: [_jsxs("div", { className: "flex items-center justify-between p-3", children: [_jsx("span", { className: "text-lg font-medium", children: "
|
|
29
|
+
}, getContainer: false, width: isMobile ? "100%" : 360, children: _jsxs("div", { className: "flex flex-col h-full", children: [_jsxs("div", { className: "flex items-center justify-between p-3", children: [_jsx("span", { className: "text-lg font-medium", children: t("search_message_title") }), _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("div", { className: "px-3", children: _jsx(Input, { ref: searchInputRef, placeholder: t("search"), prefix: _jsx(Icon, { icon: "search-o", size: 18, className: "text-gray-400" }), onChange: (e) => {
|
|
30
30
|
setSearch(e.target.value);
|
|
31
31
|
}, className: "rounded-lg text-sm", size: "large", allowClear: true, value: search, autoFocus: false }) }), _jsx("div", { className: "flex-1 py-3 overflow-auto", children: _jsx(SearchMessageOnCurrentConversation, { searchTerm: search, onClose: toggle }) })] }) })] }));
|
|
32
32
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SearchItemAsMessage.d.ts","sourceRoot":"","sources":["../../../../src/components/searchConversation/item/SearchItemAsMessage.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,
|
|
1
|
+
{"version":3,"file":"SearchItemAsMessage.d.ts","sourceRoot":"","sources":["../../../../src/components/searchConversation/item/SearchItemAsMessage.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAA4B,MAAM,yBAAyB,CAAC;AAehF,UAAU,wBAAwB;IAChC,OAAO,EAAE,WAAW,GAAG;QAAE,SAAS,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC;IAC/C,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB;AAED,QAAA,MAAM,mBAAmB,GAAI,OAAO,wBAAwB,4CAkG3D,CAAC;AAEF,eAAe,mBAAmB,CAAC"}
|
|
@@ -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, sanitizeHtml } 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";
|
|
@@ -44,7 +44,10 @@ const SearchItemAsMessage = (props) => {
|
|
|
44
44
|
};
|
|
45
45
|
let msgContent = "";
|
|
46
46
|
try {
|
|
47
|
-
msgContent =
|
|
47
|
+
msgContent =
|
|
48
|
+
(message === null || message === void 0 ? void 0 : message.isRevoked) === true
|
|
49
|
+
? t("revoked")
|
|
50
|
+
: ((_a = JSON.parse((message === null || message === void 0 ? void 0 : message.content) || "{}")) === null || _a === void 0 ? void 0 : _a.content) || "";
|
|
48
51
|
}
|
|
49
52
|
catch (error) {
|
|
50
53
|
console.error("Failed to parse message content", error);
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { ISupporterResponse } from "../../types/dto";
|
|
2
|
+
interface AssignConfirmModalProps {
|
|
3
|
+
open: boolean;
|
|
4
|
+
agent: ISupporterResponse | null;
|
|
5
|
+
loading: boolean;
|
|
6
|
+
onCancel: () => void;
|
|
7
|
+
onConfirm: () => void;
|
|
8
|
+
afterClose?: () => void;
|
|
9
|
+
}
|
|
10
|
+
declare const AssignConfirmModal: ({ open, agent, loading, onCancel, onConfirm, afterClose, }: AssignConfirmModalProps) => import("react/jsx-runtime").JSX.Element;
|
|
11
|
+
export default AssignConfirmModal;
|
|
12
|
+
//# sourceMappingURL=AssignConfirmModal.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AssignConfirmModal.d.ts","sourceRoot":"","sources":["../../../src/components/thread/AssignConfirmModal.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAGrD,UAAU,uBAAuB;IAC/B,IAAI,EAAE,OAAO,CAAC;IACd,KAAK,EAAE,kBAAkB,GAAG,IAAI,CAAC;IACjC,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,SAAS,EAAE,MAAM,IAAI,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,IAAI,CAAC;CACzB;AAED,QAAA,MAAM,kBAAkB,GAAI,4DAOzB,uBAAuB,4CAwDzB,CAAC;AAEF,eAAe,kBAAkB,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Modal, Button, Avatar } from "antd";
|
|
3
|
+
import { useTranslation, Trans } from "react-i18next";
|
|
4
|
+
const AssignConfirmModal = ({ open, agent, loading, onCancel, onConfirm, afterClose, }) => {
|
|
5
|
+
var _a;
|
|
6
|
+
const { t } = useTranslation();
|
|
7
|
+
return (_jsx(Modal, { open: open, onCancel: onCancel, footer: null, closable: !loading, centered: true, forceRender: true, width: 400, maskClosable: !loading, keyboard: !loading, afterClose: afterClose, children: _jsxs("div", { className: "flex flex-col items-center gap-4 pt-2", role: "alertdialog", "aria-label": t("manual_assign_confirm_question", {
|
|
8
|
+
name: agent === null || agent === void 0 ? void 0 : agent.displayName,
|
|
9
|
+
}), children: [_jsx(Avatar, { src: agent === null || agent === void 0 ? void 0 : agent.avatar, size: 48, children: ((_a = agent === null || agent === void 0 ? void 0 : agent.displayName) === null || _a === void 0 ? void 0 : _a.charAt(0)) || "A" }), _jsx("p", { className: "text-base text-center", children: _jsx(Trans, { i18nKey: "manual_assign_confirm_question", values: { name: agent === null || agent === void 0 ? void 0 : agent.displayName }, components: { bold: _jsx("strong", {}) } }) }), _jsxs("div", { className: "flex gap-3 w-full", children: [_jsx(Button, { className: "flex-1", size: "large", onClick: onCancel, disabled: loading, children: t("cancel") }), _jsx(Button, { type: "primary", className: "flex-1", size: "large", onClick: onConfirm, loading: loading, disabled: !agent, children: t("manual_assign_button_reassign") })] })] }) }));
|
|
10
|
+
};
|
|
11
|
+
export default AssignConfirmModal;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
interface SupporterInfo {
|
|
2
|
+
avatar: string;
|
|
3
|
+
username: string;
|
|
4
|
+
fullName: string;
|
|
5
|
+
id: string;
|
|
6
|
+
}
|
|
7
|
+
interface ManualAssignPopoverProps {
|
|
8
|
+
sessionId: string;
|
|
9
|
+
supporter: SupporterInfo;
|
|
10
|
+
teamId?: string;
|
|
11
|
+
}
|
|
12
|
+
declare const ManualAssignPopover: ({ sessionId, supporter, teamId: propTeamId, }: ManualAssignPopoverProps) => import("react/jsx-runtime").JSX.Element;
|
|
13
|
+
export default ManualAssignPopover;
|
|
14
|
+
//# sourceMappingURL=ManualAssignPopover.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ManualAssignPopover.d.ts","sourceRoot":"","sources":["../../../src/components/thread/ManualAssignPopover.tsx"],"names":[],"mappings":"AAgBA,UAAU,aAAa;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,EAAE,EAAE,MAAM,CAAC;CACZ;AAED,UAAU,wBAAwB;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,aAAa,CAAC;IACzB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AA0CD,QAAA,MAAM,mBAAmB,GAAI,+CAI1B,wBAAwB,4CA8J1B,CAAC;AAEF,eAAe,mBAAmB,CAAC"}
|