@droppii-org/chat-sdk 0.1.56 → 0.1.58
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/components/conversation-detail/ConversationDetailInput.d.ts.map +1 -1
- package/dist/components/conversation-detail/ConversationDetailInput.js +2 -1
- package/dist/components/conversation-detail/ConversationMessageList.d.ts.map +1 -1
- package/dist/components/conversation-detail/ConversationMessageList.js +26 -5
- package/dist/components/message/MessageList.d.ts.map +1 -1
- package/dist/components/message/MessageList.js +1 -23
- package/dist/components/message/footer/index.js +2 -2
- package/dist/components/message/item/QuoteMessage.d.ts +1 -2
- package/dist/components/message/item/QuoteMessage.d.ts.map +1 -1
- package/dist/components/message/item/QuoteMessage.js +13 -49
- package/dist/components/message/item/index.d.ts +2 -1
- package/dist/components/message/item/index.d.ts.map +1 -1
- package/dist/components/message/item/index.js +54 -41
- package/dist/components/message/reply/ReplyPreviewBar.d.ts +3 -0
- package/dist/components/message/reply/ReplyPreviewBar.d.ts.map +1 -0
- package/dist/components/message/reply/ReplyPreviewBar.js +23 -0
- package/dist/components/message/reply/ReplyPreviewMedia.d.ts +7 -0
- package/dist/components/message/reply/ReplyPreviewMedia.d.ts.map +1 -0
- package/dist/components/message/reply/ReplyPreviewMedia.js +41 -0
- package/dist/components/message/reply/ReplyQuoteContent.d.ts +9 -0
- package/dist/components/message/reply/ReplyQuoteContent.d.ts.map +1 -0
- package/dist/components/message/reply/ReplyQuoteContent.js +17 -0
- package/dist/components/message/toolbox/MessageToolboxMenu.d.ts +5 -0
- package/dist/components/message/toolbox/MessageToolboxMenu.d.ts.map +1 -0
- package/dist/components/message/toolbox/MessageToolboxMenu.js +10 -0
- package/dist/components/message/toolbox/getCopyableMessageText.d.ts +4 -0
- package/dist/components/message/toolbox/getCopyableMessageText.d.ts.map +1 -0
- package/dist/components/message/toolbox/getCopyableMessageText.js +28 -0
- package/dist/components/message/toolbox/index.d.ts +5 -0
- package/dist/components/message/toolbox/index.d.ts.map +1 -0
- package/dist/components/message/toolbox/index.js +4 -0
- package/dist/components/message/toolbox/types.d.ts +15 -0
- package/dist/components/message/toolbox/types.d.ts.map +1 -0
- package/dist/components/message/toolbox/types.js +6 -0
- package/dist/components/message/toolbox/useMessageToolboxVisibility.d.ts +9 -0
- package/dist/components/message/toolbox/useMessageToolboxVisibility.d.ts.map +1 -0
- package/dist/components/message/toolbox/useMessageToolboxVisibility.js +15 -0
- package/dist/hooks/message/useMessageListScroll.d.ts +1 -0
- package/dist/hooks/message/useMessageListScroll.d.ts.map +1 -1
- package/dist/hooks/message/useMessageListScroll.js +22 -0
- package/dist/locales/vi/common.json +8 -4
- package/dist/styles/global.css +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/utils/common.js +2 -2
- package/package.json +126 -127
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ConversationDetailInput.d.ts","sourceRoot":"","sources":["../../../src/components/conversation-detail/ConversationDetailInput.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ConversationDetailInput.d.ts","sourceRoot":"","sources":["../../../src/components/conversation-detail/ConversationDetailInput.tsx"],"names":[],"mappings":"AA+BA,MAAM,WAAW,4BAA4B;IAC3C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACzC;AAED,QAAA,MAAM,uBAAuB,GAAI,gDAI9B,4BAA4B,4CA6Y9B,CAAC;AAEF,eAAe,uBAAuB,CAAC"}
|
|
@@ -16,6 +16,7 @@ import { useFetchUrlMetadata } from "../../hooks/common/useFetchUrlMetadata";
|
|
|
16
16
|
import { processAndValidateDocuments, processAndValidateFiles, } from "../../utils/fileValidation";
|
|
17
17
|
import { FilePreviewList } from "../../components/message/footer/FilePreview";
|
|
18
18
|
import LinkInputPreview from "../../components/message/footer/LinkInputPreview";
|
|
19
|
+
import { ReplyPreviewBar } from "../../components/message/reply/ReplyPreviewBar";
|
|
19
20
|
import ConversationMoreOptionPanel from "./ConversationMoreOptionPanel";
|
|
20
21
|
const MAX_LINES = 5;
|
|
21
22
|
const CONTAINER_MIN_HEIGHT = 48;
|
|
@@ -251,7 +252,7 @@ const ConversationDetailInput = ({ placeholder, onSendMessage, onInputChange, })
|
|
|
251
252
|
event.preventDefault();
|
|
252
253
|
void handleSend();
|
|
253
254
|
};
|
|
254
|
-
return (_jsxs("div", { ref: containerRef, "data-testid": "conversation-detail-input", className: "flex w-full shrink-0 flex-col bg-chat-bubble-neutral/[0.05]", children: [_jsx("input", { ref: mediaInputRef, type: "file", accept: "image/jpeg,image/png,image/jpg,video/*", multiple: true, className: "hidden", onChange: handleMediaInputChange }), _jsx("input", { ref: documentInputRef, type: "file", accept: ".pdf,.doc,.docx", multiple: true, className: "hidden", onChange: handleDocumentInputChange }), listUploadFiles.length > 0 && (_jsx(FilePreviewList, { files: listUploadFiles, onRemove: (file) => handleRemoveFile(file.uid), onVideoReady: () => setIsVideoLoading(false) })), showLinkPreview && previewUrl && (_jsx(LinkInputPreview, { url: previewUrl, onRemove: () => setPreviewDismissed(true) })), _jsxs("div", { className: "flex items-end gap-3 px-3 py-2", children: [_jsx("div", { className: "flex shrink-0 items-center", children: _jsx("button", { type: "button", onClick: handleToggleMoreOption, "aria-label": t("thread_detail.more_option.toggle"), "aria-expanded": isMoreOptionOpen, "data-testid": "conversation-detail-more-option-toggle", className: "flex py-3 items-center justify-center rounded-full", children: isMoreOptionOpen ? (_jsx(Icon, { icon: "close-circle-o", size: 24, className: "text-primary-400" })) : (_jsx(Icon, { icon: "plus-circle-o", size: 24, className: "text-gray-900" })) }) }), _jsx("div", { className: clsx("flex min-w-0 flex-1 overflow-hidden rounded-xl border bg-white transition-shadow", isFocused
|
|
255
|
+
return (_jsxs("div", { ref: containerRef, "data-testid": "conversation-detail-input", className: "flex w-full shrink-0 flex-col bg-chat-bubble-neutral/[0.05]", children: [_jsx("input", { ref: mediaInputRef, type: "file", accept: "image/jpeg,image/png,image/jpg,video/*", multiple: true, className: "hidden", onChange: handleMediaInputChange }), _jsx("input", { ref: documentInputRef, type: "file", accept: ".pdf,.doc,.docx", multiple: true, className: "hidden", onChange: handleDocumentInputChange }), _jsx(ReplyPreviewBar, {}), listUploadFiles.length > 0 && (_jsx(FilePreviewList, { files: listUploadFiles, onRemove: (file) => handleRemoveFile(file.uid), onVideoReady: () => setIsVideoLoading(false) })), showLinkPreview && previewUrl && (_jsx(LinkInputPreview, { url: previewUrl, onRemove: () => setPreviewDismissed(true) })), _jsxs("div", { className: "flex items-end gap-3 px-3 py-2", children: [_jsx("div", { className: "flex shrink-0 items-center", children: _jsx("button", { type: "button", onClick: handleToggleMoreOption, "aria-label": t("thread_detail.more_option.toggle"), "aria-expanded": isMoreOptionOpen, "data-testid": "conversation-detail-more-option-toggle", className: "flex py-3 items-center justify-center rounded-full", children: isMoreOptionOpen ? (_jsx(Icon, { icon: "close-circle-o", size: 24, className: "text-primary-400" })) : (_jsx(Icon, { icon: "plus-circle-o", size: 24, className: "text-gray-900" })) }) }), _jsx("div", { className: clsx("flex min-w-0 flex-1 overflow-hidden rounded-xl border bg-white transition-shadow", isFocused
|
|
255
256
|
? "border-primary-200 shadow-primary-focus"
|
|
256
257
|
: "border-gray-50"), style: { minHeight: CONTAINER_MIN_HEIGHT }, children: _jsx("div", { className: "flex min-w-0 flex-[1_0_0] items-center gap-2 self-stretch px-3 py-1", children: _jsx("textarea", { ref: textareaRef, value: value, rows: 1, onChange: (event) => handleChange(event.target.value), onFocus: handleFocus, onBlur: handleBlur, onKeyDown: handleKeyDown, placeholder: placeholder !== null && placeholder !== void 0 ? placeholder : t("thread_detail.input_placeholder"), "data-testid": "conversation-detail-message-input", className: "conversation-message-input-scrollbar min-h-0 min-w-0 flex-1 resize-none appearance-none border-0 bg-transparent p-0 text-[16px] leading-[1.6] tracking-[0.16px] text-black outline-none ring-0 placeholder:text-gray-400 focus:border-0 focus:outline-none focus:ring-0" }) }) }), _jsx("div", { className: "flex shrink-0 items-center pb-1", children: _jsx("button", { type: "button", onClick: () => void handleSend(), disabled: !canSend, "data-testid": "conversation-detail-send", className: clsx("flex h-10 w-10 items-center justify-center rounded-full", canSend ? "bg-chat-send" : "bg-chat-send opacity-25"), children: _jsx(Icon, { icon: "send-b", size: 20, className: "text-white" }) }) })] }), isMoreOptionOpen && (_jsx(ConversationMoreOptionPanel, { disabled: !isConversationReady, onTriggerMediaInput: () => { var _a; return (_a = mediaInputRef.current) === null || _a === void 0 ? void 0 : _a.click(); }, onTriggerDocumentInput: () => { var _a; return (_a = documentInputRef.current) === null || _a === void 0 ? void 0 : _a.click(); } }))] }));
|
|
257
258
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ConversationMessageList.d.ts","sourceRoot":"","sources":["../../../src/components/conversation-detail/ConversationMessageList.tsx"],"names":[],"mappings":"AAEA,OAAO,
|
|
1
|
+
{"version":3,"file":"ConversationMessageList.d.ts","sourceRoot":"","sources":["../../../src/components/conversation-detail/ConversationMessageList.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAoC,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAczE,MAAM,WAAW,4BAA4B;IAC3C,UAAU,CAAC,EAAE,SAAS,CAAC;CACxB;AAED,QAAA,MAAM,uBAAuB,GAAI,gBAAgB,4BAA4B,4CAsH5E,CAAC;AAEF,eAAe,uBAAuB,CAAC"}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
-
import { useEffect } from "react";
|
|
3
|
+
import { useCallback, useEffect, useState } from "react";
|
|
4
4
|
import { Empty, Spin } from "antd";
|
|
5
|
+
import { useEventListener } from "ahooks";
|
|
5
6
|
import { useTranslation } from "react-i18next";
|
|
6
7
|
import { useChatContext } from "../../context/ChatContext";
|
|
7
8
|
import MessageInfiniteScroll from "../../components/message/MessageInfiniteScroll";
|
|
@@ -18,18 +19,38 @@ const ConversationMessageList = ({ bottomSlot }) => {
|
|
|
18
19
|
const authUserID = useAuthStore((state) => state.userID);
|
|
19
20
|
const conversation = useConversationStore((state) => state.conversationData);
|
|
20
21
|
const selectedConversationId = useConversationStore((state) => state.selectedConversationId);
|
|
22
|
+
const setQuotedMessage = useConversationStore((state) => state.setQuotedMessage);
|
|
23
|
+
const searchClientMsgID = useConversationStore((state) => state.searchClientMsgID);
|
|
24
|
+
const setSearchClientMsgID = useConversationStore((state) => state.setSearchClientMsgID);
|
|
21
25
|
const conversationId = selectedConversationId || (conversation === null || conversation === void 0 ? void 0 : conversation.conversationID) || "";
|
|
22
26
|
const isGroupChat = conversation ? resolveIsGroupChat(conversation) : false;
|
|
23
|
-
const messageController = useMessage(conversationId);
|
|
24
|
-
const { scrollRef, loadMoreOldMessage, handleInfiniteScroll, scrollToBottomIfAtBottom, } = useMessageListScroll(Object.assign({ conversationId, userId: (user === null || user === void 0 ? void 0 : user.userID) || authUserID }, messageController));
|
|
27
|
+
const messageController = useMessage(conversationId, searchClientMsgID);
|
|
28
|
+
const { scrollRef, loadMoreOldMessage, handleInfiniteScroll, scrollToBottomIfAtBottom, scrollToMessage, } = useMessageListScroll(Object.assign({ conversationId, userId: (user === null || user === void 0 ? void 0 : user.userID) || authUserID }, messageController));
|
|
25
29
|
const { loadState, moreOldLoading } = messageController;
|
|
26
30
|
const isMessageLoading = !conversationId || loadState.initLoading;
|
|
31
|
+
const [openToolboxMessageId, setOpenToolboxMessageId] = useState(null);
|
|
32
|
+
const closeToolbox = useCallback(() => setOpenToolboxMessageId(null), []);
|
|
33
|
+
const onPressQuoteMessage = useCallback((clientMsgID) => {
|
|
34
|
+
const hasMessage = loadState.messageList.some((msg) => msg.clientMsgID === clientMsgID);
|
|
35
|
+
if (hasMessage) {
|
|
36
|
+
scrollToMessage(clientMsgID);
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
setSearchClientMsgID(clientMsgID);
|
|
40
|
+
}
|
|
41
|
+
}, [scrollToMessage, loadState.messageList, setSearchClientMsgID]);
|
|
27
42
|
useEffect(() => {
|
|
28
43
|
emitter.on("CONVERSATION_CHAT_SCROLL_TO_BOTTOM_IF_AT_BOTTOM", scrollToBottomIfAtBottom);
|
|
44
|
+
emitter.on("CHAT_LIST_SCROLL_TO_MESSAGE", scrollToMessage);
|
|
29
45
|
return () => {
|
|
30
46
|
emitter.off("CONVERSATION_CHAT_SCROLL_TO_BOTTOM_IF_AT_BOTTOM", scrollToBottomIfAtBottom);
|
|
47
|
+
emitter.off("CHAT_LIST_SCROLL_TO_MESSAGE", scrollToMessage);
|
|
31
48
|
};
|
|
32
|
-
}, [scrollToBottomIfAtBottom]);
|
|
33
|
-
|
|
49
|
+
}, [scrollToBottomIfAtBottom, scrollToMessage]);
|
|
50
|
+
useEventListener("scroll", closeToolbox, {
|
|
51
|
+
target: scrollRef,
|
|
52
|
+
enable: !!openToolboxMessageId,
|
|
53
|
+
});
|
|
54
|
+
return (_jsx("div", { "data-testid": "conversation-message-list", className: "relative flex min-h-0 min-w-0 flex-1 flex-col overflow-x-hidden bg-white", children: isMessageLoading ? (_jsx("div", { className: "flex flex-1 items-center justify-center py-12", children: _jsx(Spin, {}) })) : (_jsxs(MessageInfiniteScroll, { scrollRef: scrollRef, scrollableTargetId: "scrollableConversationMessagesDiv", loadState: loadState, moreOldLoading: moreOldLoading, onLoadMoreOld: loadMoreOldMessage, onScroll: handleInfiniteScroll, containerClassName: "h-full", empty: _jsx("div", { className: "flex flex-1 items-center justify-center py-12", children: _jsx(Empty, { description: t("empty.no_messages") }) }), children: [bottomSlot, loadState.messageList.map((message, index, array) => (_jsx(MessageItem, { message: message, allMessages: array, isGroupChat: isGroupChat, forceHideTip: index === 0 && !!bottomSlot, contextMenuOpen: openToolboxMessageId === message.clientMsgID, onContextMenuOpenChange: (open) => setOpenToolboxMessageId(open ? message.clientMsgID : null), onQuoteMessage: setQuotedMessage, onRevokeMessage: closeToolbox, onPressQuoteMessage: onPressQuoteMessage, enableLongPress: true }, message.clientMsgID)))] })) }));
|
|
34
55
|
};
|
|
35
56
|
export default ConversationMessageList;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MessageList.d.ts","sourceRoot":"","sources":["../../../src/components/message/MessageList.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"MessageList.d.ts","sourceRoot":"","sources":["../../../src/components/message/MessageList.tsx"],"names":[],"mappings":"AAyBA,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;IACrB,qBAAqB,CAAC,EAAE,MAAM,IAAI,CAAC;CACpC;AAED,QAAA,MAAM,WAAW,GAAI,OAAO,gBAAgB,4CAgO3C,CAAC;AAEF,eAAe,WAAW,CAAC"}
|
|
@@ -15,7 +15,6 @@ import { useTranslation } from "react-i18next";
|
|
|
15
15
|
import useConversationStore from "../../store/conversation";
|
|
16
16
|
import { useBoolean } from "ahooks";
|
|
17
17
|
import { useMessageListScroll } from "../../hooks/message/useMessageListScroll";
|
|
18
|
-
import { MSG_ITEM_CONTENT_PREFIX, MSG_ITEM_PREFIX } from "../../constants";
|
|
19
18
|
import { useChatContext } from "../../context/ChatContext";
|
|
20
19
|
import { useRevokeMessage } from "../../hooks/message/useRevokeMessage";
|
|
21
20
|
import { useConversationSessionState } from "../../hooks/session/useConversationSessionState";
|
|
@@ -49,7 +48,7 @@ const MessageList = (props) => {
|
|
|
49
48
|
customerUserID,
|
|
50
49
|
});
|
|
51
50
|
const { loadState, moreOldLoading, moreNewLoading } = messageController;
|
|
52
|
-
const { scrollRef, loadMoreOldMessage, handleInfiniteScroll, scrollToBottom } = useMessageListScroll(Object.assign({ conversationId, userId: user === null || user === void 0 ? void 0 : user.userID }, messageController));
|
|
51
|
+
const { scrollRef, loadMoreOldMessage, handleInfiniteScroll, scrollToBottom, scrollToMessage, } = useMessageListScroll(Object.assign({ conversationId, userId: user === null || user === void 0 ? void 0 : user.userID }, messageController));
|
|
53
52
|
const handleOpenRevoke = useCallback((clientMsgID) => {
|
|
54
53
|
setSelectedItem(clientMsgID);
|
|
55
54
|
openConfirmRevoke();
|
|
@@ -67,27 +66,6 @@ const MessageList = (props) => {
|
|
|
67
66
|
revokeMessage,
|
|
68
67
|
handleCloseRevoke,
|
|
69
68
|
]);
|
|
70
|
-
const scrollToMessage = (clientMsgID) => {
|
|
71
|
-
setTimeout(() => {
|
|
72
|
-
const targetElement = document.getElementById(`${MSG_ITEM_PREFIX}${clientMsgID}`);
|
|
73
|
-
targetElement === null || targetElement === void 0 ? void 0 : targetElement.scrollIntoView({
|
|
74
|
-
behavior: "auto",
|
|
75
|
-
block: "center",
|
|
76
|
-
});
|
|
77
|
-
setTimeout(() => {
|
|
78
|
-
const targetContentElement = document.getElementById(`${MSG_ITEM_CONTENT_PREFIX}${clientMsgID}`);
|
|
79
|
-
targetContentElement === null || targetContentElement === void 0 ? void 0 : targetContentElement.classList.add("zoom-in-out-element", "border-blue-500", "border");
|
|
80
|
-
// Khi animation kết thúc thì remove element
|
|
81
|
-
const onEnd = () => {
|
|
82
|
-
targetContentElement === null || targetContentElement === void 0 ? void 0 : targetContentElement.classList.remove("zoom-in-out-element", "border-blue-500", "border");
|
|
83
|
-
targetContentElement === null || targetContentElement === void 0 ? void 0 : targetContentElement.removeEventListener("animationend", onEnd);
|
|
84
|
-
};
|
|
85
|
-
targetContentElement === null || targetContentElement === void 0 ? void 0 : targetContentElement.addEventListener("animationend", onEnd, {
|
|
86
|
-
once: true,
|
|
87
|
-
});
|
|
88
|
-
}, 500);
|
|
89
|
-
}, 200);
|
|
90
|
-
};
|
|
91
69
|
const onPressQuoteMessage = useCallback((clientMsgID) => {
|
|
92
70
|
const hasMessage = loadState.messageList.some((msg) => msg.clientMsgID === clientMsgID);
|
|
93
71
|
if (hasMessage) {
|
|
@@ -18,7 +18,7 @@ import { extractLinkUrls } from "../../../utils/link";
|
|
|
18
18
|
import { useFetchUrlMetadata } from "../../../hooks/common/useFetchUrlMetadata";
|
|
19
19
|
import { useTranslation } from "react-i18next";
|
|
20
20
|
import PasteAndDropPlugin from "./PasteAndDropPlugin";
|
|
21
|
-
import {
|
|
21
|
+
import { ReplyPreviewBar } from "../../../components/message/reply/ReplyPreviewBar";
|
|
22
22
|
import CannedResponse from "../../../components/canned-response";
|
|
23
23
|
import { CannedResponseTriggerPlugin } from "./CannedResponsePlugin";
|
|
24
24
|
import { useBoolean } from "ahooks";
|
|
@@ -214,6 +214,6 @@ const MessageFooterProvider = ({ currentSession, openCreateCannedModal, }) => {
|
|
|
214
214
|
setMaxActiveCannedIndex,
|
|
215
215
|
}, 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: {
|
|
216
216
|
body: "mx-1 !p-0",
|
|
217
|
-
}, destroyOnHidden: true, children: _jsxs("div", { className: "border-t pb-2 flex flex-col gap-1 bg-white", children: [_jsx(
|
|
217
|
+
}, destroyOnHidden: true, children: _jsxs("div", { className: "border-t pb-2 flex flex-col gap-1 bg-white", children: [_jsx(ReplyPreviewBar, {}), listUploadFiles.length > 0 && _jsx(FilePreview, {}), showLinkPreview && previewUrl && (_jsx(LinkInputPreview, { url: previewUrl, onRemove: () => setIsLinkPreviewDismissed(true) })), _jsx(ToolbarPlugin, {}), _jsxs("div", { children: [_jsx(ComposerTabs, { canUseInternal: canUseInternal, hintText: t("canned_response_hint"), isInternal: isInternal, lockToInternal: lockToInternal, setIsInternal: setIsInternal }), _jsx(ComposerEditor, { isInternal: isInternal, placeholderText: placeholderText })] }), _jsx(ActionBar, {})] }) }), _jsx(LinkPlugin, {}), _jsx(ListPlugin, {}), _jsx(ComposerTextSyncPlugin, { onChange: setComposerText }), _jsx(EnterHandler, {}), _jsx(PasteAndDropPlugin, {}), isCrm && (_jsx(CannedResponseTriggerPlugin, { onClose: closeCanned, onOpen: onOpenCanned }))] }), _jsx(SessionClosedModal, { open: isSessionClosedModalOpen, loading: isSessionActionLoading, onReopen: handleReopenSession, onCreateNew: handleCreateNewSession, onClose: handleCloseSessionModal })] }));
|
|
218
218
|
};
|
|
219
219
|
export default MessageFooterProvider;
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import { MessageItem } from "@openim/wasm-client-sdk";
|
|
2
2
|
interface QuoteMessageItemProps {
|
|
3
3
|
message: MessageItem;
|
|
4
|
-
isMine: boolean;
|
|
5
4
|
onPressQuoteMessage?: (clientMsgID: string) => void;
|
|
6
5
|
}
|
|
7
|
-
declare const QuoteMessageItem: ({ message,
|
|
6
|
+
declare const QuoteMessageItem: ({ message, onPressQuoteMessage, }: QuoteMessageItemProps) => import("react/jsx-runtime").JSX.Element | null;
|
|
8
7
|
export default QuoteMessageItem;
|
|
9
8
|
//# sourceMappingURL=QuoteMessage.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"QuoteMessage.d.ts","sourceRoot":"","sources":["../../../../src/components/message/item/QuoteMessage.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,
|
|
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;AAOtD,UAAU,qBAAqB;IAC7B,OAAO,EAAE,WAAW,CAAC;IACrB,mBAAmB,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;CACrD;AAED,QAAA,MAAM,gBAAgB,GAAI,mCAGvB,qBAAqB,mDAkDvB,CAAC;AAEF,eAAe,gBAAgB,CAAC"}
|
|
@@ -1,15 +1,11 @@
|
|
|
1
|
-
import { jsx as _jsx
|
|
2
|
-
import { generateContentBasedOnMessageType } from "../../../utils/common";
|
|
3
|
-
import { Icon } from "../../../components/icon";
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
4
2
|
import { useTranslation } from "react-i18next";
|
|
5
|
-
import clsx from "clsx";
|
|
6
|
-
import MediaPreviewIcon from "../../../components/message/MediaPreviewIcon";
|
|
7
|
-
import useAuthStore from "../../../store/auth";
|
|
8
3
|
import { useCallback, useMemo } from "react";
|
|
4
|
+
import useAuthStore from "../../../store/auth";
|
|
9
5
|
import useConversationStore from "../../../store/conversation";
|
|
10
|
-
|
|
11
|
-
const QuoteMessageItem = ({ message,
|
|
12
|
-
var _a
|
|
6
|
+
import ReplyQuoteContent from "../../../components/message/reply/ReplyQuoteContent";
|
|
7
|
+
const QuoteMessageItem = ({ message, onPressQuoteMessage, }) => {
|
|
8
|
+
var _a;
|
|
13
9
|
const userID = useAuthStore((state) => state.userID);
|
|
14
10
|
const isCrm = useAuthStore((state) => state.isCrm);
|
|
15
11
|
const conversationData = useConversationStore((state) => state.conversationData);
|
|
@@ -33,45 +29,13 @@ const QuoteMessageItem = ({ message, isMine, onPressQuoteMessage, }) => {
|
|
|
33
29
|
return t("you");
|
|
34
30
|
return name;
|
|
35
31
|
}, [isCrm, isChatSupport, conversationData === null || conversationData === void 0 ? void 0 : conversationData.showName, userID, t]);
|
|
36
|
-
const
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
const targetName = quoteMsg === null || quoteMsg === void 0 ? void 0 : quoteMsg.senderNickname;
|
|
45
|
-
const isSelfReply = senderID === targetID;
|
|
46
|
-
const isFromMe = senderID === userID;
|
|
47
|
-
const isReplyToMe = targetID === userID;
|
|
48
|
-
const senderDisplay = getDisplayName({ name: senderName, id: senderID });
|
|
49
|
-
const targetDisplay = getDisplayName({ name: targetName, id: targetID });
|
|
50
|
-
if (isSelfReply) {
|
|
51
|
-
return isFromMe
|
|
52
|
-
? capitalize(t("replied_yourself"))
|
|
53
|
-
: `${senderDisplay} ${t("replied_yourself")}`;
|
|
54
|
-
}
|
|
55
|
-
if (isFromMe) {
|
|
56
|
-
return `${capitalize(t("replied"))} ${targetDisplay}`;
|
|
57
|
-
}
|
|
58
|
-
if (isReplyToMe) {
|
|
59
|
-
return `${senderDisplay} ${t("replied_you")}`;
|
|
60
|
-
}
|
|
61
|
-
return `${senderDisplay} ${t("replied")} ${targetDisplay}`;
|
|
62
|
-
}, [
|
|
63
|
-
message,
|
|
64
|
-
userID,
|
|
65
|
-
isCrm,
|
|
66
|
-
isChatSupport,
|
|
67
|
-
conversationData,
|
|
68
|
-
t,
|
|
69
|
-
getDisplayName,
|
|
70
|
-
]);
|
|
71
|
-
const replyText = useMemo(() => parseReplyText(), [parseReplyText]);
|
|
72
|
-
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: replyText })] }), _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: () => {
|
|
73
|
-
var _a, _b;
|
|
74
|
-
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) || "");
|
|
75
|
-
}, 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) || "") })] })] }));
|
|
32
|
+
const quoteMessage = (_a = message === null || message === void 0 ? void 0 : message.quoteElem) === null || _a === void 0 ? void 0 : _a.quoteMessage;
|
|
33
|
+
if (!quoteMessage)
|
|
34
|
+
return null;
|
|
35
|
+
const title = getDisplayName({
|
|
36
|
+
name: quoteMessage.senderNickname,
|
|
37
|
+
id: quoteMessage.sendID,
|
|
38
|
+
});
|
|
39
|
+
return (_jsx("div", { className: "flex cursor-pointer items-center overflow-hidden rounded-r-xl bg-white/70", onClick: () => onPressQuoteMessage === null || onPressQuoteMessage === void 0 ? void 0 : onPressQuoteMessage(quoteMessage.clientMsgID || ""), children: _jsx(ReplyQuoteContent, { message: quoteMessage, title: title || "" }) }));
|
|
76
40
|
};
|
|
77
41
|
export default QuoteMessageItem;
|
|
@@ -9,7 +9,8 @@ interface MessageItemProps {
|
|
|
9
9
|
onRevokeMessage?: (clientMsgID: string) => void;
|
|
10
10
|
onQuoteMessage?: (message: MessageItemType) => void;
|
|
11
11
|
onPressQuoteMessage?: (clientMsgID: string) => void;
|
|
12
|
+
enableLongPress?: boolean;
|
|
12
13
|
}
|
|
13
|
-
declare const MessageItem: ({ message, allMessages, isGroupChat, forceHideTip, contextMenuOpen, onContextMenuOpenChange, onRevokeMessage, onQuoteMessage, onPressQuoteMessage, }: MessageItemProps) => import("react/jsx-runtime").JSX.Element | null;
|
|
14
|
+
declare const MessageItem: ({ message, allMessages, isGroupChat, forceHideTip, contextMenuOpen, onContextMenuOpenChange, onRevokeMessage, onQuoteMessage, onPressQuoteMessage, enableLongPress, }: MessageItemProps) => import("react/jsx-runtime").JSX.Element | null;
|
|
14
15
|
export default MessageItem;
|
|
15
16
|
//# 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;AAuCjC,UAAU,gBAAgB;IACxB,OAAO,EAAE,eAAe,CAAC;IACzB,WAAW,EAAE,eAAe,EAAE,CAAC;IAC/B,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,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;IACpD,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAeD,QAAA,MAAM,WAAW,GAAI,uKAWlB,gBAAgB,mDA4RlB,CAAC;AAEF,eAAe,WAAW,CAAC"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { createElement as _createElement } from "react";
|
|
2
|
-
import { jsx as _jsx,
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
3
|
import dayjs from "dayjs";
|
|
4
4
|
import clsx from "clsx";
|
|
5
|
-
import { Dropdown } from "antd";
|
|
5
|
+
import { Dropdown, message as toastMessage } from "antd";
|
|
6
6
|
import { MessageStatus, MessageType, } from "@openim/wasm-client-sdk";
|
|
7
7
|
import TextMessageItem from "./TextMessage";
|
|
8
8
|
import ImageMessageItem from "./ImageMessage";
|
|
@@ -15,7 +15,8 @@ import { MSG_ITEM_CONTENT_PREFIX, MSG_ITEM_PREFIX } from "../../../constants";
|
|
|
15
15
|
import { formatTimestamp } from "../../../utils/common";
|
|
16
16
|
import useAuthStore from "../../../store/auth";
|
|
17
17
|
import useConversationStore from "../../../store/conversation";
|
|
18
|
-
import { useCallback, useMemo } from "react";
|
|
18
|
+
import { useCallback, useMemo, useRef } from "react";
|
|
19
|
+
import { useLongPress } from "ahooks";
|
|
19
20
|
import { Trans, useTranslation } from "react-i18next";
|
|
20
21
|
import UrlTextMessageItem from "./UrlTextMessage";
|
|
21
22
|
import MessageStatusIndicator from "./MessageStatusIndicator";
|
|
@@ -25,8 +26,9 @@ import RevokeMessageItem from "./RevokeMessage";
|
|
|
25
26
|
import QuoteMessageItem from "./QuoteMessage";
|
|
26
27
|
import SystemLogMessageItem from "./SystemLogMessage";
|
|
27
28
|
import { isSystemLogMessageType } from "../../../utils/messageLog";
|
|
29
|
+
import { buildMessageToolboxMenuItems, getCopyableMessageText, isCopyableMessageType, MessageToolboxActionKey, MESSAGE_TOOLBOX_OVERLAY_CLASSNAME, useMessageToolboxVisibility, } from "../../../components/message/toolbox";
|
|
28
30
|
const MessageAvatar = ({ avatarUrl }) => avatarUrl ? (_jsx("img", { src: avatarUrl, alt: "", className: "h-6 w-6 shrink-0 self-end rounded-full object-cover" })) : (_jsx("div", { className: "flex h-6 w-6 shrink-0 items-center justify-center self-end rounded-full bg-chat-avatar", children: _jsx(Icon, { icon: "droppii-o-1", size: 14, className: "text-white" }) }));
|
|
29
|
-
const MessageItem = ({ message, allMessages, isGroupChat = false, forceHideTip = false, contextMenuOpen, onContextMenuOpenChange, onRevokeMessage, onQuoteMessage, onPressQuoteMessage, }) => {
|
|
31
|
+
const MessageItem = ({ message, allMessages, isGroupChat = false, forceHideTip = false, contextMenuOpen, onContextMenuOpenChange, onRevokeMessage, onQuoteMessage, onPressQuoteMessage, enableLongPress = false, }) => {
|
|
30
32
|
var _a;
|
|
31
33
|
const { t } = useTranslation();
|
|
32
34
|
const { resendMessage } = useSendMessage();
|
|
@@ -56,52 +58,63 @@ const MessageItem = ({ message, allMessages, isGroupChat = false, forceHideTip =
|
|
|
56
58
|
return _jsx(TextMessageItem, { message: item });
|
|
57
59
|
}
|
|
58
60
|
}, []);
|
|
59
|
-
const {
|
|
60
|
-
const isMyMessage = (message === null || message === void 0 ? void 0 : message.sendID) === userID;
|
|
61
|
-
const isOlderThanOneDay = dayjs().diff(dayjs(message === null || message === void 0 ? void 0 : message.sendTime), "days", true) >= 1;
|
|
62
|
-
const status = message.status;
|
|
63
|
-
const isDeliveredForUi = status !== MessageStatus.Sending && status !== MessageStatus.Failed;
|
|
64
|
-
return {
|
|
65
|
-
isReplyable: isDeliveredForUi,
|
|
66
|
-
isRevocable: isMyMessage && isDeliveredForUi && !isOlderThanOneDay,
|
|
67
|
-
isMine: isMyMessage,
|
|
68
|
-
};
|
|
69
|
-
}, [userID, message]);
|
|
61
|
+
const { isDeliveredForUi, isRevocable, isMine } = useMessageToolboxVisibility(message, userID);
|
|
70
62
|
const contextMenuItems = useMemo(() => {
|
|
71
63
|
if ((message === null || message === void 0 ? void 0 : message.contentType) === MessageType.RevokeMessage ||
|
|
72
64
|
isSystemLogMessageType(message === null || message === void 0 ? void 0 : message.contentType)) {
|
|
73
65
|
return [];
|
|
74
66
|
}
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
:
|
|
96
|
-
|
|
67
|
+
const closeToolbox = () => onContextMenuOpenChange === null || onContextMenuOpenChange === void 0 ? void 0 : onContextMenuOpenChange(false);
|
|
68
|
+
const actions = [];
|
|
69
|
+
if (isDeliveredForUi && onQuoteMessage) {
|
|
70
|
+
actions.push({
|
|
71
|
+
key: MessageToolboxActionKey.REPLY,
|
|
72
|
+
label: t("context_menu_reply"),
|
|
73
|
+
icon: "arrow-reply-o",
|
|
74
|
+
onClick: () => onQuoteMessage(message),
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
if (isDeliveredForUi) {
|
|
78
|
+
actions.push({
|
|
79
|
+
key: MessageToolboxActionKey.PIN,
|
|
80
|
+
label: t("context_menu_pin"),
|
|
81
|
+
icon: "thumbstack-o",
|
|
82
|
+
onClick: closeToolbox,
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
if (isDeliveredForUi && isCopyableMessageType(message === null || message === void 0 ? void 0 : message.contentType)) {
|
|
86
|
+
actions.push({
|
|
87
|
+
key: MessageToolboxActionKey.COPY_MESSAGE,
|
|
88
|
+
label: t("context_menu_copy_message"),
|
|
89
|
+
icon: "copy-o",
|
|
90
|
+
onClick: () => {
|
|
91
|
+
navigator.clipboard.writeText(getCopyableMessageText(message));
|
|
92
|
+
toastMessage.success(t("copy_message_success"));
|
|
93
|
+
closeToolbox();
|
|
94
|
+
},
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
if (isRevocable && onRevokeMessage) {
|
|
98
|
+
actions.push({
|
|
99
|
+
key: MessageToolboxActionKey.REVOKE,
|
|
100
|
+
label: t("context_menu_revoke"),
|
|
101
|
+
icon: "trash-alt-o-1",
|
|
102
|
+
danger: true,
|
|
103
|
+
onClick: () => onRevokeMessage((message === null || message === void 0 ? void 0 : message.clientMsgID) || ""),
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
return buildMessageToolboxMenuItems(actions);
|
|
97
107
|
}, [
|
|
98
|
-
|
|
108
|
+
isDeliveredForUi,
|
|
99
109
|
isRevocable,
|
|
100
110
|
t,
|
|
101
111
|
onRevokeMessage,
|
|
102
112
|
message,
|
|
103
113
|
onQuoteMessage,
|
|
114
|
+
onContextMenuOpenChange,
|
|
104
115
|
]);
|
|
116
|
+
const bubbleWrapperRef = useRef(null);
|
|
117
|
+
useLongPress(() => onContextMenuOpenChange === null || onContextMenuOpenChange === void 0 ? void 0 : onContextMenuOpenChange(true), enableLongPress ? bubbleWrapperRef : undefined, { delay: 500 });
|
|
105
118
|
const showSenderInfo = useMemo(() => {
|
|
106
119
|
var _a, _b, _c;
|
|
107
120
|
try {
|
|
@@ -147,13 +160,13 @@ const MessageItem = ({ message, allMessages, isGroupChat = false, forceHideTip =
|
|
|
147
160
|
timeBreakNode,
|
|
148
161
|
_jsx(SystemLogMessageItem, { message: message })));
|
|
149
162
|
}
|
|
150
|
-
const bubbleNode = (_jsx(MessageBubble, { isMine: isMine, isInternal: isInternalMessage, senderName: message === null || message === void 0 ? void 0 : message.senderNickname, showSenderName: showSenderName, showTip: showTip, id: `${MSG_ITEM_CONTENT_PREFIX}${message === null || message === void 0 ? void 0 : message.clientMsgID}`, content: (message === null || message === void 0 ? void 0 : message.contentType) === MessageType.MergeMessage ? (_jsxs(_Fragment, { children: [_jsx(MergeImageMessageItem, { message: message }), (message === null || message === void 0 ? void 0 : message.textElem) && _jsx(TextMessageItem, { message: message })] })) : (renderMessageByType(message)) }));
|
|
151
|
-
const wrappedBubble = hasContextMenu ? (_jsx(Dropdown, { menu: { items: contextMenuItems }, trigger: ["contextMenu"], open: contextMenuOpen, onOpenChange: onContextMenuOpenChange, children: _jsx("div", { className: "min-w-0", children: bubbleNode }) })) : (bubbleNode);
|
|
163
|
+
const bubbleNode = (_jsx(MessageBubble, { isMine: isMine, isInternal: isInternalMessage, senderName: message === null || message === void 0 ? void 0 : message.senderNickname, showSenderName: showSenderName, showTip: showTip, id: `${MSG_ITEM_CONTENT_PREFIX}${message === null || message === void 0 ? void 0 : message.clientMsgID}`, content: (message === null || message === void 0 ? void 0 : message.quoteElem) ? (_jsxs("div", { className: "flex flex-col gap-1", children: [_jsx(QuoteMessageItem, { message: message, onPressQuoteMessage: onPressQuoteMessage }), renderMessageByType(message)] })) : (message === null || message === void 0 ? void 0 : message.contentType) === MessageType.MergeMessage ? (_jsxs(_Fragment, { children: [_jsx(MergeImageMessageItem, { message: message }), (message === null || message === void 0 ? void 0 : message.textElem) && _jsx(TextMessageItem, { message: message })] })) : (renderMessageByType(message)) }));
|
|
164
|
+
const wrappedBubble = hasContextMenu ? (_jsx(Dropdown, { menu: { items: contextMenuItems }, trigger: ["contextMenu"], open: contextMenuOpen, onOpenChange: onContextMenuOpenChange, overlayClassName: MESSAGE_TOOLBOX_OVERLAY_CLASSNAME, children: _jsx("div", { ref: bubbleWrapperRef, className: "min-w-0", children: bubbleNode }) })) : (bubbleNode);
|
|
152
165
|
return (_createElement("div", Object.assign({}, messageContainerProps, { key: message === null || message === void 0 ? void 0 : message.clientMsgID }),
|
|
153
166
|
timeBreakNode,
|
|
154
167
|
_jsxs("div", { className: clsx("flex min-w-0 items-end gap-1", isMine ? "justify-end pl-12 pr-3" : "justify-start pl-3 pr-12"), children: [!isMine &&
|
|
155
168
|
showPeerInfo &&
|
|
156
|
-
(showAvatar ? (_jsx(MessageAvatar, { avatarUrl: message === null || message === void 0 ? void 0 : message.senderFaceUrl })) : (_jsx("div", { className: "h-6 w-6 shrink-0 self-end" }))), _jsxs("div", { className: clsx("flex min-w-0 max-w-[75%] flex-col gap-1", isMine ? "items-end" : "items-start"), children: [
|
|
169
|
+
(showAvatar ? (_jsx(MessageAvatar, { avatarUrl: message === null || message === void 0 ? void 0 : message.senderFaceUrl })) : (_jsx("div", { className: "h-6 w-6 shrink-0 self-end" }))), _jsxs("div", { className: clsx("flex min-w-0 max-w-[75%] flex-col gap-1", isMine ? "items-end" : "items-start"), children: [_jsxs("div", { className: "flex items-end gap-1.5", children: [isMine && (_jsx(MessageStatusIndicator, { message: message, isLatest: isLatestMine })), wrappedBubble] }), isMine && message.status === MessageStatus.Failed && (_jsx("span", { className: "mt-1 text-xs text-red-500", children: isMediaResendable(message) ? (_jsx(Trans, { i18nKey: "message_send_failed", components: {
|
|
157
170
|
bold: (_jsx("strong", { className: "cursor-pointer", onClick: () => resendMessage(message) })),
|
|
158
171
|
} })) : (t("message_send_failed_no_retry")) }))] })] })));
|
|
159
172
|
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ReplyPreviewBar.d.ts","sourceRoot":"","sources":["../../../../src/components/message/reply/ReplyPreviewBar.tsx"],"names":[],"mappings":"AAMA,eAAO,MAAM,eAAe,sDAuC3B,CAAC;AAEF,eAAe,eAAe,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useTranslation } from "react-i18next";
|
|
3
|
+
import { Icon } from "../../../components/icon";
|
|
4
|
+
import useAuthStore from "../../../store/auth";
|
|
5
|
+
import useConversationStore from "../../../store/conversation";
|
|
6
|
+
import { ReplyQuoteContent } from "./ReplyQuoteContent";
|
|
7
|
+
export const ReplyPreviewBar = () => {
|
|
8
|
+
const { t } = useTranslation();
|
|
9
|
+
const quotedMessage = useConversationStore((state) => state.quotedMessage);
|
|
10
|
+
const setQuotedMessage = useConversationStore((state) => state.setQuotedMessage);
|
|
11
|
+
const userID = useAuthStore((state) => state.userID);
|
|
12
|
+
const handleClearQuotedMessage = () => {
|
|
13
|
+
setQuotedMessage(null);
|
|
14
|
+
};
|
|
15
|
+
if (!quotedMessage)
|
|
16
|
+
return null;
|
|
17
|
+
const isMe = quotedMessage.sendID === userID;
|
|
18
|
+
const senderName = isMe
|
|
19
|
+
? t("your_self")
|
|
20
|
+
: quotedMessage.senderNickname || "";
|
|
21
|
+
return (_jsxs("div", { "data-testid": "reply-preview-bar", className: "flex h-[59px] w-full shrink-0 items-center bg-gray-200/10 px-2 py-1", children: [_jsx(ReplyQuoteContent, { message: quotedMessage, title: t("reply_to", { name: senderName }) }), _jsx("button", { type: "button", onClick: handleClearQuotedMessage, "aria-label": t("cancel"), "data-testid": "reply-preview-bar-close", className: "flex h-4 w-4 shrink-0 items-center justify-center", children: _jsx(Icon, { icon: "close-o", size: 16, className: "text-gray-600" }) })] }));
|
|
22
|
+
};
|
|
23
|
+
export default ReplyPreviewBar;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { MessageItem } from "@openim/wasm-client-sdk";
|
|
2
|
+
interface ReplyPreviewMediaProps {
|
|
3
|
+
message: MessageItem;
|
|
4
|
+
}
|
|
5
|
+
declare const ReplyPreviewMedia: ({ message }: ReplyPreviewMediaProps) => import("react/jsx-runtime").JSX.Element | null;
|
|
6
|
+
export default ReplyPreviewMedia;
|
|
7
|
+
//# sourceMappingURL=ReplyPreviewMedia.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ReplyPreviewMedia.d.ts","sourceRoot":"","sources":["../../../../src/components/message/reply/ReplyPreviewMedia.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAe,MAAM,yBAAyB,CAAC;AAKnE,UAAU,sBAAsB;IAC9B,OAAO,EAAE,WAAW,CAAC;CACtB;AAYD,QAAA,MAAM,iBAAiB,GAAI,aAAa,sBAAsB,mDAoD7D,CAAC;AAEF,eAAe,iBAAiB,CAAC"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { MessageType } from "@openim/wasm-client-sdk";
|
|
3
|
+
import { documentIcon } from "../../../assets/svg";
|
|
4
|
+
import { Icon } from "../../../components/icon";
|
|
5
|
+
const parseUrlMetadataImage = (ex) => {
|
|
6
|
+
var _a;
|
|
7
|
+
if (!ex)
|
|
8
|
+
return undefined;
|
|
9
|
+
try {
|
|
10
|
+
const extendMessageInfo = JSON.parse(ex);
|
|
11
|
+
return (_a = extendMessageInfo === null || extendMessageInfo === void 0 ? void 0 : extendMessageInfo.urlMetadata) === null || _a === void 0 ? void 0 : _a.image;
|
|
12
|
+
}
|
|
13
|
+
catch (_b) {
|
|
14
|
+
return undefined;
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
const ReplyPreviewMedia = ({ message }) => {
|
|
18
|
+
var _a, _b, _c, _d, _e;
|
|
19
|
+
if (message.contentType === MessageType.FileMessage) {
|
|
20
|
+
return (_jsx("div", { className: "flex h-6 w-6 shrink-0 items-center justify-center overflow-hidden [&>svg]:h-6 [&>svg]:w-6", children: documentIcon }));
|
|
21
|
+
}
|
|
22
|
+
if (message.contentType === MessageType.PictureMessage) {
|
|
23
|
+
const imageUrl = ((_b = (_a = message.pictureElem) === null || _a === void 0 ? void 0 : _a.sourcePicture) === null || _b === void 0 ? void 0 : _b.url) ||
|
|
24
|
+
((_d = (_c = message.pictureElem) === null || _c === void 0 ? void 0 : _c.snapshotPicture) === null || _d === void 0 ? void 0 : _d.url);
|
|
25
|
+
if (!imageUrl)
|
|
26
|
+
return null;
|
|
27
|
+
return (_jsx("img", { src: imageUrl, alt: "", className: "h-[42px] w-[42px] shrink-0 rounded-lg object-cover" }));
|
|
28
|
+
}
|
|
29
|
+
if (message.contentType === MessageType.VideoMessage) {
|
|
30
|
+
const posterUrl = (_e = message.videoElem) === null || _e === void 0 ? void 0 : _e.snapshotUrl;
|
|
31
|
+
return (_jsxs("div", { className: "relative h-[42px] w-[42px] shrink-0 overflow-hidden rounded-lg bg-gray-900", children: [posterUrl && (_jsx("img", { src: posterUrl, alt: "", className: "h-full w-full object-cover" })), _jsx("div", { className: "absolute inset-0 flex items-center justify-center", children: _jsx("div", { className: "flex h-5 w-5 items-center justify-center rounded-full bg-black/60", children: _jsx(Icon, { icon: "play-o", size: 12, className: "text-white" }) }) })] }));
|
|
32
|
+
}
|
|
33
|
+
if (message.contentType === MessageType.UrlTextMessage) {
|
|
34
|
+
const imageUrl = parseUrlMetadataImage(message.ex);
|
|
35
|
+
if (!imageUrl)
|
|
36
|
+
return null;
|
|
37
|
+
return (_jsx("img", { src: imageUrl, alt: "", className: "h-[42px] w-[42px] shrink-0 rounded-lg object-cover" }));
|
|
38
|
+
}
|
|
39
|
+
return null;
|
|
40
|
+
};
|
|
41
|
+
export default ReplyPreviewMedia;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { MessageItem, MessageType } from "@openim/wasm-client-sdk";
|
|
2
|
+
export declare const hasReplyMediaPreview: (contentType: MessageType) => boolean;
|
|
3
|
+
interface ReplyQuoteContentProps {
|
|
4
|
+
message: MessageItem;
|
|
5
|
+
title: string;
|
|
6
|
+
}
|
|
7
|
+
export declare const ReplyQuoteContent: ({ message, title }: ReplyQuoteContentProps) => import("react/jsx-runtime").JSX.Element;
|
|
8
|
+
export default ReplyQuoteContent;
|
|
9
|
+
//# sourceMappingURL=ReplyQuoteContent.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ReplyQuoteContent.d.ts","sourceRoot":"","sources":["../../../../src/components/message/reply/ReplyQuoteContent.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AASnE,eAAO,MAAM,oBAAoB,GAAI,aAAa,WAAW,YACb,CAAC;AAEjD,UAAU,sBAAsB;IAC9B,OAAO,EAAE,WAAW,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,eAAO,MAAM,iBAAiB,GAAI,oBAAoB,sBAAsB,4CAsB3E,CAAC;AAEF,eAAe,iBAAiB,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useTranslation } from "react-i18next";
|
|
3
|
+
import { MessageType } from "@openim/wasm-client-sdk";
|
|
4
|
+
import { generateContentBasedOnMessageType } from "../../../utils/common";
|
|
5
|
+
import ReplyPreviewMedia from "./ReplyPreviewMedia";
|
|
6
|
+
const TEXT_LIKE_MESSAGE_TYPES = [
|
|
7
|
+
MessageType.TextMessage,
|
|
8
|
+
MessageType.QuoteMessage,
|
|
9
|
+
];
|
|
10
|
+
export const hasReplyMediaPreview = (contentType) => !TEXT_LIKE_MESSAGE_TYPES.includes(contentType);
|
|
11
|
+
export const ReplyQuoteContent = ({ message, title }) => {
|
|
12
|
+
var _a, _b;
|
|
13
|
+
const { t } = useTranslation();
|
|
14
|
+
const hasMedia = hasReplyMediaPreview(message.contentType);
|
|
15
|
+
return (_jsxs("div", { className: "flex min-w-0 flex-1 items-center gap-0.5 pr-2 self-stretch", children: [_jsx("div", { className: "w-[3px] shrink-0 self-stretch rounded bg-gray-cool-200" }), hasMedia && _jsx(ReplyPreviewMedia, { message: message }), _jsxs("div", { className: "flex min-w-0 flex-1 flex-col justify-center py-1 pl-2", children: [_jsx("p", { className: "truncate text-[14px] font-medium leading-[160%] text-gray-900", children: title }), _jsx("p", { className: "truncate text-[13px] leading-[160%] text-gray-400", children: generateContentBasedOnMessageType(message.contentType, ((_a = message.textElem) === null || _a === void 0 ? void 0 : _a.content) || ((_b = message.quoteElem) === null || _b === void 0 ? void 0 : _b.text), t) })] })] }));
|
|
16
|
+
};
|
|
17
|
+
export default ReplyQuoteContent;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { MenuProps } from "antd";
|
|
2
|
+
import { MessageToolboxAction } from "./types";
|
|
3
|
+
export declare const MESSAGE_TOOLBOX_OVERLAY_CLASSNAME: string;
|
|
4
|
+
export declare const buildMessageToolboxMenuItems: (actions: MessageToolboxAction[]) => NonNullable<MenuProps["items"]>;
|
|
5
|
+
//# sourceMappingURL=MessageToolboxMenu.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MessageToolboxMenu.d.ts","sourceRoot":"","sources":["../../../../src/components/message/toolbox/MessageToolboxMenu.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,MAAM,CAAC;AAEtC,OAAO,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC;AAE/C,eAAO,MAAM,iCAAiC,QAS7C,CAAC;AA0BF,eAAO,MAAM,4BAA4B,GACvC,SAAS,oBAAoB,EAAE,KAC9B,WAAW,CAAC,SAAS,CAAC,OAAO,CAAC,CAO5B,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import clsx from "clsx";
|
|
3
|
+
import { Icon } from "../../../components/icon";
|
|
4
|
+
export const MESSAGE_TOOLBOX_OVERLAY_CLASSNAME = clsx("[&_.ant-dropdown-menu]:min-w-[200px]", "[&_.ant-dropdown-menu]:rounded-2xl", "[&_.ant-dropdown-menu]:p-0", "[&_.ant-dropdown-menu]:py-2", "[&_.ant-dropdown-menu]:shadow-message-toolbox", "[&_.ant-dropdown-menu-item]:rounded-none", "[&_.ant-dropdown-menu-item]:px-4", "[&_.ant-dropdown-menu-item]:py-1.5");
|
|
5
|
+
const ToolboxMenuRow = ({ icon, label, danger = false }) => (_jsxs("div", { className: "flex items-center gap-3", children: [_jsx(Icon, { icon: icon, size: 24, className: danger ? "text-danger-400" : "text-gray-900" }), _jsx("span", { className: clsx("text-base font-medium", danger ? "text-danger-400" : "text-gray-900"), children: label })] }));
|
|
6
|
+
export const buildMessageToolboxMenuItems = (actions) => actions.map((action) => ({
|
|
7
|
+
key: action.key,
|
|
8
|
+
label: (_jsx(ToolboxMenuRow, { icon: action.icon, label: action.label, danger: action.danger })),
|
|
9
|
+
onClick: action.onClick,
|
|
10
|
+
}));
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { MessageItem as MessageItemType, MessageType } from "@openim/wasm-client-sdk";
|
|
2
|
+
export declare const isCopyableMessageType: (contentType?: MessageType) => boolean;
|
|
3
|
+
export declare const getCopyableMessageText: (message: MessageItemType) => string;
|
|
4
|
+
//# sourceMappingURL=getCopyableMessageText.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"getCopyableMessageText.d.ts","sourceRoot":"","sources":["../../../../src/components/message/toolbox/getCopyableMessageText.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,IAAI,eAAe,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAUtF,eAAO,MAAM,qBAAqB,GAAI,cAAc,WAAW,KAAG,OACH,CAAC;AAEhE,eAAO,MAAM,sBAAsB,GAAI,SAAS,eAAe,KAAG,MAuBjE,CAAC"}
|