@droppii-org/chat-sdk 0.1.57 → 0.1.59

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/dist/components/conversation-detail/ConversationDetailHeader.js +3 -2
  2. package/dist/components/conversation-detail/ConversationDetailInput.d.ts.map +1 -1
  3. package/dist/components/conversation-detail/ConversationDetailInput.js +2 -1
  4. package/dist/components/conversation-detail/ConversationMessageList.d.ts.map +1 -1
  5. package/dist/components/conversation-detail/ConversationMessageList.js +18 -4
  6. package/dist/components/conversation-detail/ConversationMoreOptionItem.js +1 -1
  7. package/dist/components/conversation-detail/bot/BotInactiveNotice.d.ts +3 -0
  8. package/dist/components/conversation-detail/bot/BotInactiveNotice.d.ts.map +1 -0
  9. package/dist/components/conversation-detail/bot/BotInactiveNotice.js +10 -0
  10. package/dist/components/conversation-detail/bot/index.d.ts +1 -0
  11. package/dist/components/conversation-detail/bot/index.d.ts.map +1 -1
  12. package/dist/components/conversation-detail/bot/index.js +1 -0
  13. package/dist/components/conversation-inbox/ConversationInboxItem.js +3 -2
  14. package/dist/components/message/MessageList.d.ts.map +1 -1
  15. package/dist/components/message/MessageList.js +1 -23
  16. package/dist/components/message/footer/index.js +2 -2
  17. package/dist/components/message/item/QuoteMessage.d.ts +1 -2
  18. package/dist/components/message/item/QuoteMessage.d.ts.map +1 -1
  19. package/dist/components/message/item/QuoteMessage.js +13 -49
  20. package/dist/components/message/item/TextMessage.d.ts.map +1 -1
  21. package/dist/components/message/item/TextMessage.js +2 -2
  22. package/dist/components/message/item/index.d.ts.map +1 -1
  23. package/dist/components/message/item/index.js +12 -3
  24. package/dist/components/message/reply/ReplyPreviewBar.d.ts +3 -0
  25. package/dist/components/message/reply/ReplyPreviewBar.d.ts.map +1 -0
  26. package/dist/components/message/reply/ReplyPreviewBar.js +23 -0
  27. package/dist/components/message/reply/ReplyPreviewMedia.d.ts +7 -0
  28. package/dist/components/message/reply/ReplyPreviewMedia.d.ts.map +1 -0
  29. package/dist/components/message/reply/ReplyPreviewMedia.js +41 -0
  30. package/dist/components/message/reply/ReplyQuoteContent.d.ts +9 -0
  31. package/dist/components/message/reply/ReplyQuoteContent.d.ts.map +1 -0
  32. package/dist/components/message/reply/ReplyQuoteContent.js +17 -0
  33. package/dist/hooks/conversation/useBotConversationDetail.js +2 -2
  34. package/dist/hooks/conversation/useBotDetail.d.ts +3 -0
  35. package/dist/hooks/conversation/useBotDetail.d.ts.map +1 -0
  36. package/dist/hooks/conversation/useBotDetail.js +18 -0
  37. package/dist/hooks/conversation/useBotFlow.d.ts +1 -0
  38. package/dist/hooks/conversation/useBotFlow.d.ts.map +1 -1
  39. package/dist/hooks/conversation/useBotFlow.js +13 -3
  40. package/dist/hooks/conversation/useConversationAvatarUrl.d.ts +3 -0
  41. package/dist/hooks/conversation/useConversationAvatarUrl.d.ts.map +1 -0
  42. package/dist/hooks/conversation/useConversationAvatarUrl.js +11 -0
  43. package/dist/hooks/conversation/useCreateConversation.js +2 -2
  44. package/dist/hooks/message/useMessageListScroll.d.ts +1 -0
  45. package/dist/hooks/message/useMessageListScroll.d.ts.map +1 -1
  46. package/dist/hooks/message/useMessageListScroll.js +22 -0
  47. package/dist/locales/vi/common.json +5 -4
  48. package/dist/locales/vi/conversation-inbox.json +2 -1
  49. package/dist/screens/conversation-detail/index.d.ts.map +1 -1
  50. package/dist/screens/conversation-detail/index.js +4 -2
  51. package/dist/services/query.d.ts +3 -2
  52. package/dist/services/query.d.ts.map +1 -1
  53. package/dist/services/query.js +3 -2
  54. package/dist/services/routes.d.ts +3 -2
  55. package/dist/services/routes.d.ts.map +1 -1
  56. package/dist/services/routes.js +3 -2
  57. package/dist/styles/global.css +1 -1
  58. package/dist/tsconfig.tsbuildinfo +1 -1
  59. package/dist/types/conversation.d.ts +20 -0
  60. package/dist/types/conversation.d.ts.map +1 -1
  61. package/dist/types/conversation.js +5 -0
  62. package/dist/utils/common.js +2 -2
  63. package/dist/utils/conversation.d.ts +1 -0
  64. package/dist/utils/conversation.d.ts.map +1 -1
  65. package/dist/utils/conversation.js +11 -1
  66. package/package.json +1 -1
@@ -4,12 +4,13 @@ import { useTranslation } from "react-i18next";
4
4
  import { Icon } from "../../components/icon";
5
5
  import ConversationPeerAvatar from "../../components/conversation-inbox/ConversationPeerAvatar";
6
6
  import ConversationInboxTitle from "../../components/conversation-inbox/ConversationInboxTitle";
7
- import { resolveConversationAvatarUrl, resolveConversationDisplayName, resolvePeerBadgeLabel, } from "../../utils/conversation";
7
+ import { resolveConversationDisplayName, resolvePeerBadgeLabel, } from "../../utils/conversation";
8
+ import { useConversationAvatarUrl } from "../../hooks/conversation/useConversationAvatarUrl";
8
9
  const HeaderIconButton = ({ icon, onClick, testId, }) => (_jsx("button", { type: "button", onClick: onClick, "data-testid": testId, className: "flex shrink-0 cursor-pointer items-center justify-center p-2 text-primary-400", children: _jsx(Icon, { icon: icon, size: 24 }) }));
9
10
  const ConversationDetailHeader = ({ conversation, onBack, }) => {
10
11
  const { t } = useTranslation("conversation-inbox");
11
12
  const displayName = resolveConversationDisplayName(conversation, t);
12
- const avatarUrl = resolveConversationAvatarUrl(conversation);
13
+ const avatarUrl = useConversationAvatarUrl(conversation);
13
14
  const peerType = conversation.peerType;
14
15
  const badgeLabel = resolvePeerBadgeLabel(peerType, t);
15
16
  const subtitle = t("thread_detail.profile_hint");
@@ -1 +1 @@
1
- {"version":3,"file":"ConversationDetailInput.d.ts","sourceRoot":"","sources":["../../../src/components/conversation-detail/ConversationDetailInput.tsx"],"names":[],"mappings":"AA8BA,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,4CA2Y9B,CAAC;AAEF,eAAe,uBAAuB,CAAC"}
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,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,4CA2F5E,CAAC;AAEF,eAAe,uBAAuB,CAAC"}
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"}
@@ -19,24 +19,38 @@ const ConversationMessageList = ({ bottomSlot }) => {
19
19
  const authUserID = useAuthStore((state) => state.userID);
20
20
  const conversation = useConversationStore((state) => state.conversationData);
21
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);
22
25
  const conversationId = selectedConversationId || (conversation === null || conversation === void 0 ? void 0 : conversation.conversationID) || "";
23
26
  const isGroupChat = conversation ? resolveIsGroupChat(conversation) : false;
24
- const messageController = useMessage(conversationId);
25
- 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));
26
29
  const { loadState, moreOldLoading } = messageController;
27
30
  const isMessageLoading = !conversationId || loadState.initLoading;
28
31
  const [openToolboxMessageId, setOpenToolboxMessageId] = useState(null);
29
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]);
30
42
  useEffect(() => {
31
43
  emitter.on("CONVERSATION_CHAT_SCROLL_TO_BOTTOM_IF_AT_BOTTOM", scrollToBottomIfAtBottom);
44
+ emitter.on("CHAT_LIST_SCROLL_TO_MESSAGE", scrollToMessage);
32
45
  return () => {
33
46
  emitter.off("CONVERSATION_CHAT_SCROLL_TO_BOTTOM_IF_AT_BOTTOM", scrollToBottomIfAtBottom);
47
+ emitter.off("CHAT_LIST_SCROLL_TO_MESSAGE", scrollToMessage);
34
48
  };
35
- }, [scrollToBottomIfAtBottom]);
49
+ }, [scrollToBottomIfAtBottom, scrollToMessage]);
36
50
  useEventListener("scroll", closeToolbox, {
37
51
  target: scrollRef,
38
52
  enable: !!openToolboxMessageId,
39
53
  });
40
- 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: closeToolbox, onRevokeMessage: closeToolbox, enableLongPress: true }, message.clientMsgID)))] })) }));
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)))] })) }));
41
55
  };
42
56
  export default ConversationMessageList;
@@ -12,7 +12,7 @@ const ConversationMoreOptionItem = ({ option, onSelect }) => {
12
12
  return;
13
13
  onSelect(option);
14
14
  };
15
- return (_jsxs("button", { type: "button", onClick: handleClick, disabled: !option.enabled, "aria-label": label, "data-testid": `biz-more-option-${option.labelKey}`, className: clsx("flex flex-col items-center gap-1 rounded-xl px-1 transition-colors", option.enabled
15
+ return (_jsxs("button", { type: "button", onClick: handleClick, disabled: !option.enabled, "aria-label": label, "data-testid": `more-option-${option.labelKey}`, className: clsx("flex flex-col items-center gap-1 rounded-xl px-1 transition-colors", option.enabled
16
16
  ? "active:bg-chat-bubble-neutral/[0.08]"
17
17
  : "cursor-not-allowed opacity-40"), children: [_jsx("span", { className: "flex h-12 w-12 items-center justify-center rounded-full bg-gray-200/10", children: _jsx(Icon, { icon: option.icon, size: ICON_SIZE, className: "text-gray-900" }) }), _jsx("span", { className: "line-clamp-2 text-center text-[12px] leading-[1.4] text-gray-900", children: label })] }));
18
18
  };
@@ -0,0 +1,3 @@
1
+ declare const BotInactiveNotice: () => import("react/jsx-runtime").JSX.Element;
2
+ export default BotInactiveNotice;
3
+ //# sourceMappingURL=BotInactiveNotice.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BotInactiveNotice.d.ts","sourceRoot":"","sources":["../../../../src/components/conversation-detail/bot/BotInactiveNotice.tsx"],"names":[],"mappings":"AAOA,QAAA,MAAM,iBAAiB,+CActB,CAAC;AAEF,eAAe,iBAAiB,CAAC"}
@@ -0,0 +1,10 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { useTranslation } from "react-i18next";
4
+ import { Icon } from "../../../components/icon";
5
+ const ICON_SIZE = 16;
6
+ const BotInactiveNotice = () => {
7
+ const { t } = useTranslation("conversation-inbox");
8
+ return (_jsxs("div", { "data-testid": "conversation-bot-inactive-notice", className: "flex w-full items-center justify-center gap-1 bg-white px-4 py-1", children: [_jsx(Icon, { icon: "info-circle-o", size: ICON_SIZE, className: "shrink-0 text-gray-900" }), _jsx("span", { className: "text-[12px] font-normal leading-[1.6] text-gray-900", children: t("thread_detail.bot.inactive_notice") })] }));
9
+ };
10
+ export default BotInactiveNotice;
@@ -4,4 +4,5 @@ export { default as BotButtonMessage } from "./BotButtonMessage";
4
4
  export type { BotButtonMessageProps } from "./BotButtonMessage";
5
5
  export { default as BotSuggest } from "./BotSuggest";
6
6
  export type { BotSuggestProps } from "./BotSuggest";
7
+ export { default as BotInactiveNotice } from "./BotInactiveNotice";
7
8
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/conversation-detail/bot/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAC7D,YAAY,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAE5D,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACjE,YAAY,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAEhE,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,cAAc,CAAC;AACrD,YAAY,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/conversation-detail/bot/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAC7D,YAAY,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAE5D,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACjE,YAAY,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAEhE,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,cAAc,CAAC;AACrD,YAAY,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAEpD,OAAO,EAAE,OAAO,IAAI,iBAAiB,EAAE,MAAM,qBAAqB,CAAC"}
@@ -1,3 +1,4 @@
1
1
  export { default as BotStartButton } from "./BotStartButton";
2
2
  export { default as BotButtonMessage } from "./BotButtonMessage";
3
3
  export { default as BotSuggest } from "./BotSuggest";
4
+ export { default as BotInactiveNotice } from "./BotInactiveNotice";
@@ -4,7 +4,8 @@ import dayjs from "dayjs";
4
4
  import { useTranslation } from "react-i18next";
5
5
  import useAuthStore from "../../store/auth";
6
6
  import { formatTimestamp, parseLatestMessage } from "../../utils/common";
7
- import { isBotPeer, resolveConversationAvatarUrl, resolvePeerBadgeLabel, resolveConversationDisplayName, } from "../../utils/conversation";
7
+ import { isBotPeer, resolvePeerBadgeLabel, resolveConversationDisplayName, } from "../../utils/conversation";
8
+ import { useConversationAvatarUrl } from "../../hooks/conversation/useConversationAvatarUrl";
8
9
  import ThreadCard from "../../components/conversation/ThreadCard";
9
10
  import ConversationPeerAvatar from "./ConversationPeerAvatar";
10
11
  import ConversationInboxTitle from "./ConversationInboxTitle";
@@ -20,7 +21,7 @@ const ConversationInboxItem = ({ item, onClick }) => {
20
21
  const { t: tCommon } = useTranslation("common");
21
22
  const currentUserId = useAuthStore((state) => state.userID);
22
23
  const displayName = resolveConversationDisplayName(item, t);
23
- const avatarUrl = resolveConversationAvatarUrl(item);
24
+ const avatarUrl = useConversationAvatarUrl(item);
24
25
  const badgeLabel = resolvePeerBadgeLabel(item.peerType, t);
25
26
  const latestMessagePreview = parseLatestMessage(item.latestMsg, currentUserId, tCommon, isBotPeer(item));
26
27
  const latestMessageTime = formatLatestMessageTime(item.latestMsgSendTime || null);
@@ -1 +1 @@
1
- {"version":3,"file":"MessageList.d.ts","sourceRoot":"","sources":["../../../src/components/message/MessageList.tsx"],"names":[],"mappings":"AA0BA,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,4CAgQ3C,CAAC;AAEF,eAAe,WAAW,CAAC"}
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 { QuotedMessageFooter } from "./QuotedMessage";
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(QuotedMessageFooter, {}), 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 })] }));
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, isMine, onPressQuoteMessage, }: QuoteMessageItemProps) => import("react/jsx-runtime").JSX.Element;
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,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;AAKD,QAAA,MAAM,gBAAgB,GAAI,2CAIvB,qBAAqB,4CA0GvB,CAAC;AAEF,eAAe,gBAAgB,CAAC"}
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, jsxs as _jsxs } from "react/jsx-runtime";
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
- const capitalize = (text) => text ? text.charAt(0).toUpperCase() + text.slice(1) : "";
11
- const QuoteMessageItem = ({ message, isMine, onPressQuoteMessage, }) => {
12
- var _a, _b, _c, _d, _e, _f;
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 parseReplyText = useCallback(() => {
37
- var _a;
38
- const quoteMsg = (_a = message === null || message === void 0 ? void 0 : message.quoteElem) === null || _a === void 0 ? void 0 : _a.quoteMessage;
39
- if (!quoteMsg)
40
- return "";
41
- const senderID = message === null || message === void 0 ? void 0 : message.sendID;
42
- const targetID = quoteMsg === null || quoteMsg === void 0 ? void 0 : quoteMsg.sendID;
43
- const senderName = message === null || message === void 0 ? void 0 : message.senderNickname;
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;
@@ -1 +1 @@
1
- {"version":3,"file":"TextMessage.d.ts","sourceRoot":"","sources":["../../../../src/components/message/item/TextMessage.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAE,WAAW,EAAe,MAAM,yBAAyB,CAAC;AAQnE,UAAU,oBAAoB;IAC5B,OAAO,EAAE,WAAW,CAAC;CACtB;AAED,QAAA,MAAM,eAAe,GAAI,OAAO,oBAAoB,mDAiDnD,CAAC;AAEF,eAAe,eAAe,CAAC"}
1
+ {"version":3,"file":"TextMessage.d.ts","sourceRoot":"","sources":["../../../../src/components/message/item/TextMessage.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAE,WAAW,EAAe,MAAM,yBAAyB,CAAC;AAQnE,UAAU,oBAAoB;IAC5B,OAAO,EAAE,WAAW,CAAC;CACtB;AAED,QAAA,MAAM,eAAe,GAAI,OAAO,oBAAoB,mDAqDnD,CAAC;AAEF,eAAe,eAAe,CAAC"}
@@ -25,7 +25,7 @@ const TextMessageItem = (props) => {
25
25
  const richHtmlContent = ((_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) || "";
26
26
  if (richHtmlContent && htmlHasFormatting(richHtmlContent)) {
27
27
  const sanitizedContent = sanitizeHtml(richHtmlContent);
28
- return (_jsx("div", { className: clsx("break-normal whitespace-pre-line flex-1", MESSAGE_TEXT_CLASS), style: { overflowWrap: "anywhere" }, dangerouslySetInnerHTML: { __html: sanitizedContent } }));
28
+ return (_jsx("div", { className: clsx("min-w-0 flex-1 whitespace-pre-line [overflow-wrap:anywhere]", MESSAGE_TEXT_CLASS), dangerouslySetInnerHTML: { __html: sanitizedContent } }));
29
29
  }
30
30
  const text = ((_c = message === null || message === void 0 ? void 0 : message.textElem) === null || _c === void 0 ? void 0 : _c.content) ||
31
31
  ((_d = message === null || message === void 0 ? void 0 : message.quoteElem) === null || _d === void 0 ? void 0 : _d.text) ||
@@ -36,6 +36,6 @@ const TextMessageItem = (props) => {
36
36
  if (extractLinkUrls(text).length > 0) {
37
37
  return _jsx(LinkText, { text: text });
38
38
  }
39
- return (_jsx("p", { className: clsx("whitespace-pre-wrap break-words", MESSAGE_TEXT_CLASS), children: text }));
39
+ return (_jsx("p", { className: clsx("min-w-0 whitespace-pre-wrap [overflow-wrap:anywhere]", MESSAGE_TEXT_CLASS), children: text }));
40
40
  };
41
41
  export default TextMessageItem;
@@ -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;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
+ {"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,mDAoSlB,CAAC;AAEF,eAAe,WAAW,CAAC"}
@@ -1,5 +1,5 @@
1
1
  import { createElement as _createElement } from "react";
2
- import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
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
5
  import { Dropdown, message as toastMessage } from "antd";
@@ -160,13 +160,22 @@ const MessageItem = ({ message, allMessages, isGroupChat = false, forceHideTip =
160
160
  timeBreakNode,
161
161
  _jsx(SystemLogMessageItem, { message: message })));
162
162
  }
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.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)) }));
163
+ const renderBubbleContent = () => {
164
+ if (message === null || message === void 0 ? void 0 : message.quoteElem) {
165
+ return (_jsxs("div", { className: "flex flex-col gap-1", children: [_jsx(QuoteMessageItem, { message: message, onPressQuoteMessage: onPressQuoteMessage }), renderMessageByType(message)] }));
166
+ }
167
+ if ((message === null || message === void 0 ? void 0 : message.contentType) === MessageType.MergeMessage) {
168
+ return (_jsxs(_Fragment, { children: [_jsx(MergeImageMessageItem, { message: message }), (message === null || message === void 0 ? void 0 : message.textElem) && _jsx(TextMessageItem, { message: message })] }));
169
+ }
170
+ return renderMessageByType(message);
171
+ };
172
+ 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: renderBubbleContent() }));
164
173
  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);
165
174
  return (_createElement("div", Object.assign({}, messageContainerProps, { key: message === null || message === void 0 ? void 0 : message.clientMsgID }),
166
175
  timeBreakNode,
167
176
  _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 &&
168
177
  showPeerInfo &&
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: [(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 })), 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: {
178
+ (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: {
170
179
  bold: (_jsx("strong", { className: "cursor-pointer", onClick: () => resendMessage(message) })),
171
180
  } })) : (t("message_send_failed_no_retry")) }))] })] })));
172
181
  };
@@ -0,0 +1,3 @@
1
+ export declare const ReplyPreviewBar: () => import("react/jsx-runtime").JSX.Element | null;
2
+ export default ReplyPreviewBar;
3
+ //# sourceMappingURL=ReplyPreviewBar.d.ts.map
@@ -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,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,eAAO,MAAM,iBAAiB,GAAI,qBAG/B,sBAAsB,4CAsBxB,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;
@@ -5,9 +5,9 @@ import { ENDPOINTS } from "../../services/routes";
5
5
  import { QUERY_KEYS } from "../../services/query";
6
6
  export const useBotConversationDetail = (conversationId, enabled) => {
7
7
  return useQuery({
8
- queryKey: [QUERY_KEYS.GET_BIZ_CONVERSATION_DETAIL, conversationId],
8
+ queryKey: [QUERY_KEYS.GET_CONVERSATION_DETAIL, conversationId],
9
9
  queryFn: async () => {
10
- const res = await apiInstance.get(ENDPOINTS.chatService.getBizConversationDetail(conversationId));
10
+ const res = await apiInstance.get(ENDPOINTS.chatService.getConversationDetail(conversationId));
11
11
  return res.data.data;
12
12
  },
13
13
  enabled: enabled && !!conversationId,
@@ -0,0 +1,3 @@
1
+ import type { BotDetail } from "../../types/conversation";
2
+ export declare const useBotDetail: (botId: string, enabled: boolean) => import("@tanstack/react-query").UseQueryResult<BotDetail, Error>;
3
+ //# sourceMappingURL=useBotDetail.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useBotDetail.d.ts","sourceRoot":"","sources":["../../../src/hooks/conversation/useBotDetail.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAEtD,eAAO,MAAM,YAAY,GAAI,OAAO,MAAM,EAAE,SAAS,OAAO,qEAc3D,CAAC"}
@@ -0,0 +1,18 @@
1
+ "use client";
2
+ import { useQuery } from "@tanstack/react-query";
3
+ import { apiInstance } from "../../services/api";
4
+ import { ENDPOINTS } from "../../services/routes";
5
+ import { QUERY_KEYS } from "../../services/query";
6
+ export const useBotDetail = (botId, enabled) => {
7
+ return useQuery({
8
+ queryKey: [QUERY_KEYS.GET_BOT_DETAIL, botId],
9
+ queryFn: async () => {
10
+ const res = await apiInstance.get(ENDPOINTS.chatService.getBotDetail(botId));
11
+ return res.data.data;
12
+ },
13
+ enabled: enabled && !!botId,
14
+ staleTime: 0,
15
+ refetchOnWindowFocus: false,
16
+ refetchOnReconnect: false,
17
+ });
18
+ };
@@ -7,6 +7,7 @@ interface UseBotFlowParams {
7
7
  export declare const useBotFlow: ({ conversationId, isBotThread, }: UseBotFlowParams) => {
8
8
  status: BotFlowStatus;
9
9
  flowIsEnd: boolean;
10
+ isBotInactive: boolean;
10
11
  isProcessing: boolean;
11
12
  shouldShowButtons: boolean;
12
13
  currentButtonsBlock: BotInputButtonsBlock | null;
@@ -1 +1 @@
1
- {"version":3,"file":"useBotFlow.d.ts","sourceRoot":"","sources":["../../../src/hooks/conversation/useBotFlow.ts"],"names":[],"mappings":"AAKA,OAAO,EAIL,KAAK,oBAAoB,EAC1B,MAAM,sBAAsB,CAAC;AAU9B,MAAM,MAAM,aAAa,GAAG,SAAS,GAAG,aAAa,CAAC;AAEtD,UAAU,gBAAgB;IACxB,cAAc,EAAE,MAAM,CAAC;IACvB,WAAW,EAAE,OAAO,CAAC;CACtB;AAsBD,eAAO,MAAM,UAAU,GAAI,kCAGxB,gBAAgB;;;;;;;6BA0GqB,MAAM;;CAiD7C,CAAC"}
1
+ {"version":3,"file":"useBotFlow.d.ts","sourceRoot":"","sources":["../../../src/hooks/conversation/useBotFlow.ts"],"names":[],"mappings":"AAKA,OAAO,EAKL,KAAK,oBAAoB,EAC1B,MAAM,sBAAsB,CAAC;AAa9B,MAAM,MAAM,aAAa,GAAG,SAAS,GAAG,aAAa,CAAC;AAEtD,UAAU,gBAAgB;IACxB,cAAc,EAAE,MAAM,CAAC;IACvB,WAAW,EAAE,OAAO,CAAC;CACtB;AAsBD,eAAO,MAAM,UAAU,GAAI,kCAGxB,gBAAgB;;;;;;;;6BAmHqB,MAAM;;CAkD7C,CAAC"}