@droppii-org/chat-sdk 0.1.26 → 0.1.28

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 (119) hide show
  1. package/dist/assets/svg/canned-response.d.ts +7 -0
  2. package/dist/assets/svg/canned-response.d.ts.map +1 -0
  3. package/dist/assets/svg/canned-response.js +3 -0
  4. package/dist/assets/svg/canned-response.tsx +48 -0
  5. package/dist/assets/svg/index.d.ts +1 -1
  6. package/dist/assets/svg/index.d.ts.map +1 -1
  7. package/dist/assets/svg/index.js +1 -1
  8. package/dist/assets/svg/index.ts +1 -1
  9. package/dist/components/biz-thread-detail/BizMessageBubble.d.ts +10 -0
  10. package/dist/components/biz-thread-detail/BizMessageBubble.d.ts.map +1 -0
  11. package/dist/components/biz-thread-detail/BizMessageBubble.js +15 -0
  12. package/dist/components/biz-thread-detail/BizMessageList.d.ts +3 -0
  13. package/dist/components/biz-thread-detail/BizMessageList.d.ts.map +1 -0
  14. package/dist/components/biz-thread-detail/BizMessageList.js +28 -0
  15. package/dist/components/biz-thread-detail/BizThreadDetailHeader.d.ts +8 -0
  16. package/dist/components/biz-thread-detail/BizThreadDetailHeader.d.ts.map +1 -0
  17. package/dist/components/biz-thread-detail/BizThreadDetailHeader.js +18 -0
  18. package/dist/components/biz-thread-detail/BizThreadDetailInput.d.ts +8 -0
  19. package/dist/components/biz-thread-detail/BizThreadDetailInput.d.ts.map +1 -0
  20. package/dist/components/biz-thread-detail/BizThreadDetailInput.js +147 -0
  21. package/dist/components/biz-thread-detail/index.d.ts +8 -0
  22. package/dist/components/biz-thread-detail/index.d.ts.map +1 -0
  23. package/dist/components/biz-thread-detail/index.js +4 -0
  24. package/dist/components/biz-thread-detail/item/BizMessageItem.d.ts +8 -0
  25. package/dist/components/biz-thread-detail/item/BizMessageItem.d.ts.map +1 -0
  26. package/dist/components/biz-thread-detail/item/BizMessageItem.js +20 -0
  27. package/dist/components/canned-response/CannedResponseBody.d.ts +8 -0
  28. package/dist/components/canned-response/CannedResponseBody.d.ts.map +1 -0
  29. package/dist/components/canned-response/CannedResponseBody.js +109 -0
  30. package/dist/components/canned-response/CannedResponseFooter.d.ts +6 -0
  31. package/dist/components/canned-response/CannedResponseFooter.d.ts.map +1 -0
  32. package/dist/components/canned-response/CannedResponseFooter.js +8 -0
  33. package/dist/components/canned-response/CannedResponseHeader.d.ts +8 -0
  34. package/dist/components/canned-response/CannedResponseHeader.d.ts.map +1 -0
  35. package/dist/components/canned-response/CannedResponseHeader.js +11 -0
  36. package/dist/components/canned-response/index.d.ts +8 -0
  37. package/dist/components/canned-response/index.d.ts.map +1 -0
  38. package/dist/components/canned-response/index.js +34 -0
  39. package/dist/components/canned-response/team/TeamItem.d.ts +11 -0
  40. package/dist/components/canned-response/team/TeamItem.d.ts.map +1 -0
  41. package/dist/components/canned-response/team/TeamItem.js +31 -0
  42. package/dist/components/chat-bubble/ChatBubble.d.ts +6 -0
  43. package/dist/components/chat-bubble/ChatBubble.d.ts.map +1 -0
  44. package/dist/components/chat-bubble/ChatBubble.js +35 -0
  45. package/dist/components/conversation/DeskConversationList.js +1 -1
  46. package/dist/components/media-collection/FileCollection.d.ts +3 -0
  47. package/dist/components/media-collection/FileCollection.d.ts.map +1 -0
  48. package/dist/components/media-collection/FileCollection.js +53 -0
  49. package/dist/components/media-collection/ImageCollection.d.ts +3 -0
  50. package/dist/components/media-collection/ImageCollection.d.ts.map +1 -0
  51. package/dist/components/media-collection/ImageCollection.js +52 -0
  52. package/dist/components/media-collection/LinkCollection.d.ts +5 -0
  53. package/dist/components/media-collection/LinkCollection.d.ts.map +1 -0
  54. package/dist/components/media-collection/LinkCollection.js +92 -0
  55. package/dist/components/media-collection/VideoCollection.d.ts +3 -0
  56. package/dist/components/media-collection/VideoCollection.d.ts.map +1 -0
  57. package/dist/components/media-collection/VideoCollection.js +51 -0
  58. package/dist/components/media-collection/index.d.ts +9 -0
  59. package/dist/components/media-collection/index.d.ts.map +1 -0
  60. package/dist/components/media-collection/index.js +57 -0
  61. package/dist/components/message/MessageHeader.js +2 -2
  62. package/dist/components/message/footer/MediaActions.js +1 -1
  63. package/dist/components/message/footer/index.js +1 -1
  64. package/dist/components/rich-text-editor/RichTextEditor.d.ts +12 -0
  65. package/dist/components/rich-text-editor/RichTextEditor.d.ts.map +1 -0
  66. package/dist/components/rich-text-editor/RichTextEditor.js +62 -0
  67. package/dist/components/search-conversation/SearchAll.d.ts +8 -0
  68. package/dist/components/search-conversation/SearchAll.d.ts.map +1 -0
  69. package/dist/components/search-conversation/SearchAll.js +37 -0
  70. package/dist/components/search-conversation/SearchConversationAsMessages.d.ts +6 -0
  71. package/dist/components/search-conversation/SearchConversationAsMessages.d.ts.map +1 -0
  72. package/dist/components/search-conversation/SearchConversationAsMessages.js +23 -0
  73. package/dist/components/search-conversation/SearchConversationAsUsers.d.ts +6 -0
  74. package/dist/components/search-conversation/SearchConversationAsUsers.d.ts.map +1 -0
  75. package/dist/components/search-conversation/SearchConversationAsUsers.js +21 -0
  76. package/dist/components/search-conversation/SearchConversationMyInbox.d.ts +6 -0
  77. package/dist/components/search-conversation/SearchConversationMyInbox.d.ts.map +1 -0
  78. package/dist/components/search-conversation/SearchConversationMyInbox.js +24 -0
  79. package/dist/components/search-conversation/SearchDrawer.d.ts +3 -0
  80. package/dist/components/search-conversation/SearchDrawer.d.ts.map +1 -0
  81. package/dist/components/search-conversation/SearchDrawer.js +33 -0
  82. package/dist/components/search-conversation/SearchMessageOnCurrentConversation.d.ts +7 -0
  83. package/dist/components/search-conversation/SearchMessageOnCurrentConversation.d.ts.map +1 -0
  84. package/dist/components/search-conversation/SearchMessageOnCurrentConversation.js +28 -0
  85. package/dist/components/search-conversation/index.d.ts +12 -0
  86. package/dist/components/search-conversation/index.d.ts.map +1 -0
  87. package/dist/components/search-conversation/index.js +46 -0
  88. package/dist/components/search-conversation/item/SearchItemAsMessage.d.ts +12 -0
  89. package/dist/components/search-conversation/item/SearchItemAsMessage.d.ts.map +1 -0
  90. package/dist/components/search-conversation/item/SearchItemAsMessage.js +72 -0
  91. package/dist/components/search-conversation/item/SearchItemAsUser.d.ts +8 -0
  92. package/dist/components/search-conversation/item/SearchItemAsUser.d.ts.map +1 -0
  93. package/dist/components/search-conversation/item/SearchItemAsUser.js +25 -0
  94. package/dist/hooks/biz/useBizSendMessage.d.ts.map +1 -1
  95. package/dist/hooks/biz/useBizSendMessage.js +4 -0
  96. package/dist/hooks/canned-response/useFetchCannedCategories.d.ts +3 -0
  97. package/dist/hooks/canned-response/useFetchCannedCategories.d.ts.map +1 -0
  98. package/dist/hooks/canned-response/useFetchCannedCategories.js +13 -0
  99. package/dist/hooks/canned-response/useFetchCannedResponse.d.ts +219 -0
  100. package/dist/hooks/canned-response/useFetchCannedResponse.d.ts.map +1 -0
  101. package/dist/hooks/canned-response/useFetchCannedResponse.js +55 -0
  102. package/dist/index.d.ts +9 -9
  103. package/dist/index.d.ts.map +1 -1
  104. package/dist/index.js +6 -6
  105. package/dist/screens/biz-message/index.d.ts +9 -0
  106. package/dist/screens/biz-message/index.d.ts.map +1 -0
  107. package/dist/screens/biz-message/index.js +55 -0
  108. package/dist/screens/biz-thread-detail/index.d.ts +9 -0
  109. package/dist/screens/biz-thread-detail/index.d.ts.map +1 -0
  110. package/dist/screens/biz-thread-detail/index.js +36 -0
  111. package/dist/screens/chat-bubble/index.d.ts +7 -0
  112. package/dist/screens/chat-bubble/index.d.ts.map +1 -0
  113. package/dist/screens/chat-bubble/index.js +41 -0
  114. package/dist/screens/desk-message/index.d.ts +6 -0
  115. package/dist/screens/desk-message/index.d.ts.map +1 -0
  116. package/dist/screens/desk-message/index.js +17 -0
  117. package/dist/styles/global.css +1 -1
  118. package/dist/tsconfig.tsbuildinfo +1 -1
  119. package/package.json +1 -1
@@ -0,0 +1,7 @@
1
+ interface ISvgProps {
2
+ size?: number;
3
+ className?: string;
4
+ }
5
+ declare const CannedResponseIcon: (props: ISvgProps) => import("react/jsx-runtime").JSX.Element;
6
+ export default CannedResponseIcon;
7
+ //# sourceMappingURL=canned-response.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"canned-response.d.ts","sourceRoot":"","sources":["../../../src/assets/svg/canned-response.tsx"],"names":[],"mappings":"AAAA,UAAU,SAAS;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,QAAA,MAAM,kBAAkB,GAAI,OAAO,SAAS,4CAyC3C,CAAC;AACF,eAAe,kBAAkB,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ const CannedResponseIcon = (props) => (_jsxs("svg", { width: props.size || 18, height: props.size || 18, viewBox: `${0} ${0} ${props.size || 18} ${props.size || 18}`, fill: "none", xmlns: "http://www.w3.org/2000/svg", className: props === null || props === void 0 ? void 0 : props.className, children: [_jsxs("g", { clipPath: "url(#clip0_4070_70030)", children: [_jsx("path", { fillRule: "evenodd", clipRule: "evenodd", d: "M6.66732 0.833374C7.12755 0.833374 7.50065 1.20647 7.50065 1.66671L5.00065 18.3334C5.00065 18.7936 4.62755 19.1667 4.16732 19.1667C3.70708 19.1667 3.33398 18.7936 3.33398 18.3334L5.83398 1.66671C5.83398 1.20647 6.20708 0.833374 6.66732 0.833374Z", fill: "currentColor" }), _jsx("path", { fillRule: "evenodd", clipRule: "evenodd", d: "M14.9993 0.833374C15.4596 0.833374 15.8327 1.20647 15.8327 1.66671L13.3327 18.3334C13.3327 18.7936 12.9596 19.1667 12.4993 19.1667C12.0391 19.1667 11.666 18.7936 11.666 18.3334L14.166 1.66671C14.166 1.20647 14.5391 0.833374 14.9993 0.833374Z", fill: "currentColor" }), _jsx("path", { fillRule: "evenodd", clipRule: "evenodd", d: "M19.1673 5.83333C19.1673 6.29357 18.7942 6.66667 18.334 6.66667H1.66732C1.20708 6.66667 0.833984 6.29357 0.833984 5.83333C0.833984 5.37309 1.20708 5 1.66732 5H18.334C18.7942 5 19.1673 5.3731 19.1673 5.83333Z", fill: "currentColor" }), _jsx("path", { fillRule: "evenodd", clipRule: "evenodd", d: "M19.1673 14.1667C19.1673 14.627 18.7942 15 18.334 15H1.66732C1.20708 15 0.833984 14.627 0.833984 14.1667C0.833984 13.7065 1.20708 13.3334 1.66732 13.3334H18.334C18.7942 13.3334 19.1673 13.7065 19.1673 14.1667Z", fill: "currentColor" })] }), _jsx("defs", { children: _jsx("clipPath", { id: "clip0_4070_70030", children: _jsx("rect", { width: props.size || 18, height: props.size || 18, fill: "white" }) }) })] }));
3
+ export default CannedResponseIcon;
@@ -0,0 +1,48 @@
1
+ interface ISvgProps {
2
+ size?: number;
3
+ className?: string;
4
+ }
5
+
6
+ const CannedResponseIcon = (props: ISvgProps) => (
7
+ <svg
8
+ width={props.size || 18}
9
+ height={props.size || 18}
10
+ viewBox={`${0} ${0} ${props.size || 18} ${props.size || 18}`}
11
+ fill="none"
12
+ xmlns="http://www.w3.org/2000/svg"
13
+ className={props?.className}
14
+ >
15
+ <g clipPath="url(#clip0_4070_70030)">
16
+ <path
17
+ fillRule="evenodd"
18
+ clipRule="evenodd"
19
+ d="M6.66732 0.833374C7.12755 0.833374 7.50065 1.20647 7.50065 1.66671L5.00065 18.3334C5.00065 18.7936 4.62755 19.1667 4.16732 19.1667C3.70708 19.1667 3.33398 18.7936 3.33398 18.3334L5.83398 1.66671C5.83398 1.20647 6.20708 0.833374 6.66732 0.833374Z"
20
+ fill="currentColor"
21
+ />
22
+ <path
23
+ fillRule="evenodd"
24
+ clipRule="evenodd"
25
+ d="M14.9993 0.833374C15.4596 0.833374 15.8327 1.20647 15.8327 1.66671L13.3327 18.3334C13.3327 18.7936 12.9596 19.1667 12.4993 19.1667C12.0391 19.1667 11.666 18.7936 11.666 18.3334L14.166 1.66671C14.166 1.20647 14.5391 0.833374 14.9993 0.833374Z"
26
+ fill="currentColor"
27
+ />
28
+ <path
29
+ fillRule="evenodd"
30
+ clipRule="evenodd"
31
+ d="M19.1673 5.83333C19.1673 6.29357 18.7942 6.66667 18.334 6.66667H1.66732C1.20708 6.66667 0.833984 6.29357 0.833984 5.83333C0.833984 5.37309 1.20708 5 1.66732 5H18.334C18.7942 5 19.1673 5.3731 19.1673 5.83333Z"
32
+ fill="currentColor"
33
+ />
34
+ <path
35
+ fillRule="evenodd"
36
+ clipRule="evenodd"
37
+ d="M19.1673 14.1667C19.1673 14.627 18.7942 15 18.334 15H1.66732C1.20708 15 0.833984 14.627 0.833984 14.1667C0.833984 13.7065 1.20708 13.3334 1.66732 13.3334H18.334C18.7942 13.3334 19.1673 13.7065 19.1673 14.1667Z"
38
+ fill="currentColor"
39
+ />
40
+ </g>
41
+ <defs>
42
+ <clipPath id="clip0_4070_70030">
43
+ <rect width={props.size || 18} height={props.size || 18} fill="white" />
44
+ </clipPath>
45
+ </defs>
46
+ </svg>
47
+ );
48
+ export default CannedResponseIcon;
@@ -1,3 +1,3 @@
1
1
  export * from "./document";
2
- export * from "./cannedResponse";
2
+ export * from "./canned-response";
3
3
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/assets/svg/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,kBAAkB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/assets/svg/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,mBAAmB,CAAC"}
@@ -1,2 +1,2 @@
1
1
  export * from "./document";
2
- export * from "./cannedResponse";
2
+ export * from "./canned-response";
@@ -1,2 +1,2 @@
1
1
  export * from "./document";
2
- export * from "./cannedResponse";
2
+ export * from "./canned-response";
@@ -0,0 +1,10 @@
1
+ export interface BizMessageBubbleProps {
2
+ isMine: boolean;
3
+ content: string;
4
+ senderName?: string;
5
+ showSenderName?: boolean;
6
+ showTip?: boolean;
7
+ }
8
+ declare const BizMessageBubble: ({ isMine, content, senderName, showSenderName, showTip, }: BizMessageBubbleProps) => import("react/jsx-runtime").JSX.Element;
9
+ export default BizMessageBubble;
10
+ //# sourceMappingURL=BizMessageBubble.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BizMessageBubble.d.ts","sourceRoot":"","sources":["../../../src/components/biz-thread-detail/BizMessageBubble.tsx"],"names":[],"mappings":"AAIA,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AA6BD,QAAA,MAAM,gBAAgB,GAAI,2DAMvB,qBAAqB,4CAgCvB,CAAC;AAEF,eAAe,gBAAgB,CAAC"}
@@ -0,0 +1,15 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import clsx from "clsx";
4
+ const INCOMING_TAIL_PATH = "M1.3798 18H4V0C3.51762 4.5 3.34269 10.5 0.966518 14C-0.568384 16.2608 -0.159364 18 1.3798 18Z";
5
+ const OUTGOING_TAIL_PATH = "M2.6202 18H0V0C0.482375 4.5 0.657308 10.5 3.03348 14C4.56838 16.2608 4.15936 18 2.6202 18Z";
6
+ const BizMessageBubbleTail = ({ isMine }) => (_jsx("div", { className: "flex shrink-0 items-center justify-center", children: _jsx("div", { className: "flex-none", children: _jsx("svg", { xmlns: "http://www.w3.org/2000/svg", width: "4", height: "18", viewBox: "0 0 4 18", fill: "none", "aria-hidden": true, children: _jsx("path", { d: isMine ? OUTGOING_TAIL_PATH : INCOMING_TAIL_PATH, fill: isMine ? "#0051FF" : "#83899D", fillOpacity: "0.1" }) }) }) }));
7
+ const BizMessageBubble = ({ isMine, content, senderName, showSenderName, showTip = true, }) => {
8
+ const bubbleClass = clsx("relative max-w-full p-2", showTip
9
+ ? isMine
10
+ ? "rounded-[20px] rounded-br-none"
11
+ : "rounded-[20px] rounded-bl-none"
12
+ : "rounded-[20px]", isMine ? "bg-[rgba(0,81,255,0.1)]" : "bg-[rgba(131,137,157,0.1)]");
13
+ return (_jsxs("div", { className: "relative flex items-end", "data-testid": "biz-message-bubble", children: [!isMine && showTip && _jsx(BizMessageBubbleTail, { isMine: isMine }), _jsx("div", { className: bubbleClass, children: _jsxs("div", { className: "flex flex-col gap-1 px-1", children: [showSenderName && senderName && (_jsx("span", { className: "text-[12px] font-medium leading-[160%] tracking-[0.12px] text-[#747B7E]", children: senderName })), _jsx("p", { className: "whitespace-pre-wrap break-words text-[16px] leading-[160%] tracking-[0.16px] text-[#393E40]", children: content })] }) }), isMine && showTip && _jsx(BizMessageBubbleTail, { isMine: isMine })] }));
14
+ };
15
+ export default BizMessageBubble;
@@ -0,0 +1,3 @@
1
+ declare const BizMessageList: () => import("react/jsx-runtime").JSX.Element;
2
+ export default BizMessageList;
3
+ //# sourceMappingURL=BizMessageList.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BizMessageList.d.ts","sourceRoot":"","sources":["../../../src/components/biz-thread-detail/BizMessageList.tsx"],"names":[],"mappings":"AAaA,QAAA,MAAM,cAAc,+CA8DnB,CAAC;AAEF,eAAe,cAAc,CAAC"}
@@ -0,0 +1,28 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { useEffect } from "react";
4
+ import { Empty, Spin } from "antd";
5
+ import { useTranslation } from "react-i18next";
6
+ import { useChatContext } from "../../context/ChatContext";
7
+ import MessageInfiniteScroll from "../../components/message/MessageInfiniteScroll";
8
+ import { useMessage } from "../../hooks/message/useMessage";
9
+ import { useMessageListScroll } from "../../hooks/message/useMessageListScroll";
10
+ import useBizConversationStore from "../../store/bizConversation";
11
+ import emitter from "../../utils/events";
12
+ import BizMessageItem from "./item/BizMessageItem";
13
+ const BizMessageList = () => {
14
+ const { t } = useTranslation("biz-inbox");
15
+ const { user } = useChatContext();
16
+ const conversationId = useBizConversationStore((state) => { var _a; return (_a = state.conversationData) === null || _a === void 0 ? void 0 : _a.conversationId; });
17
+ const messageController = useMessage(conversationId, undefined, !!conversationId);
18
+ const { scrollRef, loadMoreOldMessage, handleInfiniteScroll, scrollToBottomIfAtBottom, } = useMessageListScroll(Object.assign({ conversationId, userId: user === null || user === void 0 ? void 0 : user.userID }, messageController));
19
+ const { loadState, moreNewLoading } = messageController;
20
+ useEffect(() => {
21
+ emitter.on("BIZ_CHAT_SCROLL_TO_BOTTOM_IF_AT_BOTTOM", scrollToBottomIfAtBottom);
22
+ return () => {
23
+ emitter.off("BIZ_CHAT_SCROLL_TO_BOTTOM_IF_AT_BOTTOM", scrollToBottomIfAtBottom);
24
+ };
25
+ }, [scrollToBottomIfAtBottom]);
26
+ return (_jsxs("div", { "data-testid": "biz-message-list", className: "relative flex min-h-0 min-w-0 flex-1 flex-col overflow-x-hidden bg-white", children: [_jsx(MessageInfiniteScroll, { scrollRef: scrollRef, scrollableTargetId: "scrollableBizMessagesDiv", loadState: loadState, 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: loadState.messageList.map((message, _, array) => (_jsx(BizMessageItem, { message: message, allMessages: array }, message.clientMsgID))) }), moreNewLoading && (_jsx("div", { className: "flex items-center justify-center py-2", children: _jsx(Spin, {}) }))] }));
27
+ };
28
+ export default BizMessageList;
@@ -0,0 +1,8 @@
1
+ import type { BizConversationItem } from "../../types/biz";
2
+ export interface BizThreadDetailHeaderProps {
3
+ conversation: BizConversationItem;
4
+ onBack?: () => void;
5
+ }
6
+ declare const BizThreadDetailHeader: ({ conversation, onBack, }: BizThreadDetailHeaderProps) => import("react/jsx-runtime").JSX.Element;
7
+ export default BizThreadDetailHeader;
8
+ //# sourceMappingURL=BizThreadDetailHeader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BizThreadDetailHeader.d.ts","sourceRoot":"","sources":["../../../src/components/biz-thread-detail/BizThreadDetailHeader.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAQvD,MAAM,WAAW,0BAA0B;IACzC,YAAY,EAAE,mBAAmB,CAAC;IAClC,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;CACrB;AAqBD,QAAA,MAAM,qBAAqB,GAAI,2BAG5B,0BAA0B,4CA8C5B,CAAC;AAEF,eAAe,qBAAqB,CAAC"}
@@ -0,0 +1,18 @@
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
+ import BizThreadAvatar from "../../components/biz-inbox/BizThreadAvatar";
6
+ import BizThreadTitle from "../../components/biz-inbox/BizThreadTitle";
7
+ import { isBizGroupChat, resolveBizAvatarUrl, resolveBizBadgeLabel, resolveBizDisplayName, } from "../../utils/bizConversation";
8
+ 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-[#1B3FE4]", children: _jsx(Icon, { icon: icon, size: 24 }) }));
9
+ const BizThreadDetailHeader = ({ conversation, onBack, }) => {
10
+ const { t } = useTranslation("biz-inbox");
11
+ const isGroup = isBizGroupChat(conversation);
12
+ const displayName = resolveBizDisplayName(conversation, t("thread_card.fallback_name"));
13
+ const avatarUrl = resolveBizAvatarUrl(conversation);
14
+ const badgeLabel = resolveBizBadgeLabel(conversation.chatCategory, t);
15
+ const subtitle = isGroup ? "" : t("thread_detail.profile_hint");
16
+ return (_jsxs("div", { "data-testid": "biz-thread-detail-header", className: "flex w-full cursor-default items-center border-b border-[#EFEFEF] bg-white p-2 shadow-[inset_0px_-1px_0px_0px_rgba(61,63,64,0.1)]", children: [_jsx(HeaderIconButton, { icon: "arrow-left-o", onClick: onBack, testId: "biz-thread-detail-back" }), _jsxs("div", { className: "flex min-w-0 flex-1 items-center gap-2 px-1", "data-testid": "biz-thread-detail-profile", children: [_jsx(BizThreadAvatar, { chatCategory: conversation.chatCategory, displayName: displayName, avatarUrl: avatarUrl, badgeLabel: badgeLabel }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsx(BizThreadTitle, { chatCategory: conversation.chatCategory, displayName: displayName }), _jsx("p", { className: "truncate text-[10px] font-normal leading-[160%] tracking-[0.1px] text-[#5C6366] [font-feature-settings:'liga'_off,'clig'_off]", children: subtitle })] })] })] }));
17
+ };
18
+ export default BizThreadDetailHeader;
@@ -0,0 +1,8 @@
1
+ export interface BizThreadDetailInputProps {
2
+ placeholder?: string;
3
+ onSendMessage?: (text: string) => void;
4
+ onInputChange?: (value: string) => void;
5
+ }
6
+ declare const BizThreadDetailInput: ({ placeholder, onSendMessage, onInputChange, }: BizThreadDetailInputProps) => import("react/jsx-runtime").JSX.Element;
7
+ export default BizThreadDetailInput;
8
+ //# sourceMappingURL=BizThreadDetailInput.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BizThreadDetailInput.d.ts","sourceRoot":"","sources":["../../../src/components/biz-thread-detail/BizThreadDetailInput.tsx"],"names":[],"mappings":"AAcA,MAAM,WAAW,yBAAyB;IACxC,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,oBAAoB,GAAI,gDAI3B,yBAAyB,4CAwM3B,CAAC;AAEF,eAAe,oBAAoB,CAAC"}
@@ -0,0 +1,147 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { useCallback, useEffect, useRef, useState } from "react";
4
+ import { useTranslation } from "react-i18next";
5
+ import clsx from "clsx";
6
+ import { Icon } from "../../components/icon";
7
+ import { useBizSendMessage } from "../../hooks/biz/useBizSendMessage";
8
+ import useBizConversationStore from "../../store/bizConversation";
9
+ import useBizMessageDraftStore from "../../store/bizMessageDraft";
10
+ import { emit } from "../../utils/events";
11
+ const MAX_LINES = 5;
12
+ const CONTAINER_MIN_HEIGHT = 48;
13
+ const BizThreadDetailInput = ({ placeholder, onSendMessage, onInputChange, }) => {
14
+ const { t } = useTranslation("biz-inbox");
15
+ const { sendTextMessage } = useBizSendMessage();
16
+ const conversationId = useBizConversationStore((state) => { var _a; return (_a = state.conversationData) === null || _a === void 0 ? void 0 : _a.conversationId; });
17
+ const setDraft = useBizMessageDraftStore((state) => state.setDraft);
18
+ const clearDraft = useBizMessageDraftStore((state) => state.clearDraft);
19
+ const containerRef = useRef(null);
20
+ const textareaRef = useRef(null);
21
+ const [value, setValue] = useState("");
22
+ const [isFocused, setIsFocused] = useState(false);
23
+ const [isSending, setIsSending] = useState(false);
24
+ const canSend = value.trim().length > 0 && !isSending;
25
+ const getTextareaHeights = useCallback(() => {
26
+ const textarea = textareaRef.current;
27
+ if (!textarea)
28
+ return null;
29
+ const lineHeight = parseFloat(window.getComputedStyle(textarea).lineHeight);
30
+ return {
31
+ lineHeight,
32
+ maxHeight: lineHeight * MAX_LINES,
33
+ };
34
+ }, []);
35
+ const adjustTextareaHeight = useCallback(() => {
36
+ const textarea = textareaRef.current;
37
+ const heights = getTextareaHeights();
38
+ if (!textarea || !heights)
39
+ return;
40
+ textarea.style.height = `${heights.lineHeight}px`;
41
+ const scrollHeight = textarea.scrollHeight;
42
+ const nextHeight = Math.min(Math.max(scrollHeight, heights.lineHeight), heights.maxHeight);
43
+ textarea.style.height = `${nextHeight}px`;
44
+ textarea.style.overflowY =
45
+ scrollHeight > heights.maxHeight ? "auto" : "hidden";
46
+ }, [getTextareaHeights]);
47
+ useEffect(() => {
48
+ var _a;
49
+ if (!conversationId) {
50
+ setValue("");
51
+ return;
52
+ }
53
+ const draft = (_a = useBizMessageDraftStore.getState().drafts[conversationId]) !== null && _a !== void 0 ? _a : "";
54
+ setValue(draft);
55
+ requestAnimationFrame(adjustTextareaHeight);
56
+ }, [conversationId, adjustTextareaHeight]);
57
+ useEffect(() => {
58
+ adjustTextareaHeight();
59
+ }, [value, adjustTextareaHeight]);
60
+ useEffect(() => {
61
+ if (!isFocused)
62
+ return;
63
+ const handlePointerDown = (event) => {
64
+ var _a, _b;
65
+ if ((_a = containerRef.current) === null || _a === void 0 ? void 0 : _a.contains(event.target))
66
+ return;
67
+ (_b = textareaRef.current) === null || _b === void 0 ? void 0 : _b.blur();
68
+ };
69
+ document.addEventListener("pointerdown", handlePointerDown);
70
+ return () => document.removeEventListener("pointerdown", handlePointerDown);
71
+ }, [isFocused]);
72
+ useEffect(() => {
73
+ const viewport = window.visualViewport;
74
+ if (!viewport)
75
+ return;
76
+ const handleViewportChange = () => {
77
+ if (document.activeElement === textareaRef.current) {
78
+ emit("BIZ_CHAT_SCROLL_TO_BOTTOM_IF_AT_BOTTOM");
79
+ }
80
+ };
81
+ viewport.addEventListener("resize", handleViewportChange);
82
+ return () => viewport.removeEventListener("resize", handleViewportChange);
83
+ }, []);
84
+ const handleChange = (nextValue) => {
85
+ setValue(nextValue);
86
+ if (conversationId) {
87
+ setDraft(conversationId, nextValue);
88
+ }
89
+ onInputChange === null || onInputChange === void 0 ? void 0 : onInputChange(nextValue);
90
+ };
91
+ const handleSend = async () => {
92
+ const text = value.trim();
93
+ if (!text || isSending)
94
+ return;
95
+ setIsSending(true);
96
+ try {
97
+ if (onSendMessage) {
98
+ onSendMessage(text);
99
+ }
100
+ else {
101
+ const sent = await sendTextMessage(text);
102
+ if (!sent)
103
+ return;
104
+ }
105
+ setValue("");
106
+ if (conversationId) {
107
+ clearDraft(conversationId);
108
+ }
109
+ requestAnimationFrame(adjustTextareaHeight);
110
+ }
111
+ finally {
112
+ setIsSending(false);
113
+ }
114
+ };
115
+ const handleFocus = () => {
116
+ setIsFocused(true);
117
+ emit("BIZ_CHAT_SCROLL_TO_BOTTOM_IF_AT_BOTTOM");
118
+ };
119
+ const handleBlur = () => {
120
+ setIsFocused(false);
121
+ };
122
+ const insertNewline = (textarea) => {
123
+ const { selectionStart, selectionEnd } = textarea;
124
+ const nextValue = value.slice(0, selectionStart) + "\n" + value.slice(selectionEnd);
125
+ handleChange(nextValue);
126
+ requestAnimationFrame(() => {
127
+ textarea.selectionStart = selectionStart + 1;
128
+ textarea.selectionEnd = selectionStart + 1;
129
+ adjustTextareaHeight();
130
+ });
131
+ };
132
+ const handleKeyDown = (event) => {
133
+ if (event.key !== "Enter")
134
+ return;
135
+ if (event.shiftKey) {
136
+ event.preventDefault();
137
+ insertNewline(event.currentTarget);
138
+ return;
139
+ }
140
+ event.preventDefault();
141
+ void handleSend();
142
+ };
143
+ return (_jsx("div", { ref: containerRef, "data-testid": "biz-thread-detail-input", className: "flex w-full shrink-0 flex-col bg-[rgba(131,137,157,0.05)]", children: _jsxs("div", { className: "flex items-end gap-3 px-3 py-2", children: [_jsx("div", { className: clsx("flex min-w-0 flex-1 overflow-hidden rounded-xl border bg-white transition-shadow", isFocused
144
+ ? "border-[#607CFB] shadow-[0px_0px_2px_rgba(27,63,228,0.5)]"
145
+ : "border-[#DDDEDF]"), 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": "biz-thread-detail-message-input", className: "biz-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-[#747B7E] 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": "biz-thread-detail-send", className: clsx("flex h-10 w-10 items-center justify-center rounded-full", canSend ? "bg-[#002BEB]" : "bg-[#002BEB] opacity-25"), children: _jsx(Icon, { icon: "send-b", size: 20, className: "text-white" }) }) })] }) }));
146
+ };
147
+ export default BizThreadDetailInput;
@@ -0,0 +1,8 @@
1
+ export { default as BizThreadDetailHeader } from "./BizThreadDetailHeader";
2
+ export type { BizThreadDetailHeaderProps } from "./BizThreadDetailHeader";
3
+ export { default as BizThreadDetailInput } from "./BizThreadDetailInput";
4
+ export type { BizThreadDetailInputProps } from "./BizThreadDetailInput";
5
+ export { default as BizMessageList } from "./BizMessageList";
6
+ export { default as BizMessageItem } from "./item/BizMessageItem";
7
+ export type { BizMessageItemProps } from "./item/BizMessageItem";
8
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/biz-thread-detail/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAC3E,YAAY,EAAE,0BAA0B,EAAE,MAAM,yBAAyB,CAAC;AAE1E,OAAO,EAAE,OAAO,IAAI,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AACzE,YAAY,EAAE,yBAAyB,EAAE,MAAM,wBAAwB,CAAC;AAExE,OAAO,EAAE,OAAO,IAAI,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAC7D,OAAO,EAAE,OAAO,IAAI,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAClE,YAAY,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC"}
@@ -0,0 +1,4 @@
1
+ export { default as BizThreadDetailHeader } from "./BizThreadDetailHeader";
2
+ export { default as BizThreadDetailInput } from "./BizThreadDetailInput";
3
+ export { default as BizMessageList } from "./BizMessageList";
4
+ export { default as BizMessageItem } from "./item/BizMessageItem";
@@ -0,0 +1,8 @@
1
+ import { MessageItem } from "@openim/wasm-client-sdk";
2
+ export interface BizMessageItemProps {
3
+ message: MessageItem;
4
+ allMessages: MessageItem[];
5
+ }
6
+ declare const BizMessageItem: ({ message, allMessages }: BizMessageItemProps) => import("react/jsx-runtime").JSX.Element | null;
7
+ export default BizMessageItem;
8
+ //# sourceMappingURL=BizMessageItem.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BizMessageItem.d.ts","sourceRoot":"","sources":["../../../../src/components/biz-thread-detail/item/BizMessageItem.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAOtD,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,WAAW,CAAC;IACrB,WAAW,EAAE,WAAW,EAAE,CAAC;CAC5B;AA4BD,QAAA,MAAM,cAAc,GAAI,0BAA0B,mBAAmB,mDA6CpE,CAAC;AAEF,eAAe,cAAc,CAAC"}
@@ -0,0 +1,20 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { Icon } from "../../../components/icon";
4
+ import useAuthStore from "../../../store/auth";
5
+ import { formatTimestamp } from "../../../utils/common";
6
+ import { getBizMessageDisplay } from "../../../utils/bizMessage";
7
+ import BizMessageBubble from "../BizMessageBubble";
8
+ const BizMessageAvatar = ({ avatarUrl }) => (_jsx("div", { className: "flex shrink-0 items-center pb-4", children: avatarUrl ? (_jsx("img", { src: avatarUrl, alt: "", className: "h-6 w-6 rounded-full object-cover" })) : (_jsx("div", { className: "flex h-6 w-6 items-center justify-center rounded-full bg-[#0C5CFF]", children: _jsx(Icon, { icon: "droppii-o-1", size: 14, className: "text-white" }) })) }));
9
+ const BizMessageTime = ({ sendTime }) => (_jsx("div", { className: "flex w-full items-center px-4 py-1", children: _jsx("div", { className: "flex min-w-0 flex-1 flex-col items-start", children: _jsx("p", { className: "w-full break-words text-center text-[12px] font-normal leading-[160%] tracking-normal text-[#747B7E]", children: formatTimestamp(sendTime, { hasTime: true }) }) }) }));
10
+ const BizMessageItem = ({ message, allMessages }) => {
11
+ const userID = useAuthStore((state) => state.userID);
12
+ if (!userID)
13
+ return null;
14
+ const display = getBizMessageDisplay(message, allMessages, userID);
15
+ if (!display.isMine) {
16
+ return (_jsxs("div", { className: "flex w-full flex-col pb-1", "data-testid": "biz-message-item", children: [display.showTimeBreak && _jsx(BizMessageTime, { sendTime: display.sendTime }), _jsxs("div", { className: "flex w-full items-end pl-3 pr-12", children: [display.showAvatar ? (_jsx(BizMessageAvatar, { avatarUrl: display.senderFaceUrl })) : (_jsx("div", { className: "w-6 shrink-0" })), _jsx("div", { className: "flex min-w-0 flex-1 flex-col gap-1", children: _jsx(BizMessageBubble, { isMine: display.isMine, content: display.content, senderName: display.senderName, showSenderName: display.showSenderName, showTip: display.showTip }) })] })] }));
17
+ }
18
+ return (_jsxs("div", { className: "flex w-full flex-col pb-1", "data-testid": "biz-message-item", children: [display.showTimeBreak && _jsx(BizMessageTime, { sendTime: display.sendTime }), _jsx("div", { className: "flex w-full justify-end pl-12 pr-3", children: _jsx("div", { className: "flex min-w-0 max-w-[calc(100%-48px)] flex-col items-end gap-1", children: _jsx(BizMessageBubble, { isMine: display.isMine, content: display.content, showTip: display.showTip }) }) })] }));
19
+ };
20
+ export default BizMessageItem;
@@ -0,0 +1,8 @@
1
+ interface ICannedResponseBodyProps {
2
+ search?: string;
3
+ onSelectCannedResponse?: (content: string) => void;
4
+ cannedQuery?: string;
5
+ }
6
+ declare const CannedResponseBody: (props: ICannedResponseBodyProps) => import("react/jsx-runtime").JSX.Element;
7
+ export default CannedResponseBody;
8
+ //# sourceMappingURL=CannedResponseBody.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CannedResponseBody.d.ts","sourceRoot":"","sources":["../../../src/components/canned-response/CannedResponseBody.tsx"],"names":[],"mappings":"AAiBA,UAAU,wBAAwB;IAChC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,sBAAsB,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACnD,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AASD,QAAA,MAAM,kBAAkB,GAAI,OAAO,wBAAwB,4CA8M1D,CAAC;AAEF,eAAe,kBAAkB,CAAC"}
@@ -0,0 +1,109 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Empty, Segmented, Spin } from "antd";
3
+ import { useFetchMyTeams } from "../../hooks/team/useFetchMyTeam";
4
+ import { useTranslation } from "react-i18next";
5
+ import { useCallback, useEffect, useMemo, useRef, useState } from "react";
6
+ import { CannedResponseVisibleScope } from "../../types/chat";
7
+ import TeamItem from "./team/TeamItem";
8
+ import { useFetchCannedResponse } from "../../hooks/canned-response/useFetchCannedResponse";
9
+ import InfiniteScroll from "react-infinite-scroll-component";
10
+ import { Icon } from "../../components/icon";
11
+ import { sanitizeHtml } from "../../utils/common";
12
+ import { useDebounce } from "ahooks";
13
+ import clsx from "clsx";
14
+ import emitter from "../../utils/events";
15
+ import { isArray } from "lodash";
16
+ import { useMessageFooterContext } from "../../components/message/footer";
17
+ const parseIndex = (index, length) => {
18
+ if (index === null)
19
+ return null;
20
+ if (index < 0)
21
+ return 0;
22
+ if (index >= length)
23
+ return length - 1;
24
+ return index;
25
+ };
26
+ const CannedResponseBody = (props) => {
27
+ var _a, _b;
28
+ const { search, onSelectCannedResponse, cannedQuery } = props;
29
+ const { activeCannedIndex, setActiveCannedIndex, setMaxActiveCannedIndex } = useMessageFooterContext();
30
+ const itemRefs = useRef([]);
31
+ const { t } = useTranslation();
32
+ const { data: myTeams, isLoading: isLoadingTeams } = useFetchMyTeams();
33
+ const [scope, setScope] = useState(CannedResponseVisibleScope.TEAM);
34
+ const [selectedTeamId, setSelectedTeamId] = useState(undefined);
35
+ const [selectedCategoryId, setSelectedCategoryId] = useState(undefined);
36
+ const cannedQueryDebounced = useDebounce(cannedQuery, { wait: 300 });
37
+ const { dataFlatten: cannedResponses, fetchNextPage, hasNextPage, } = useFetchCannedResponse({
38
+ visibilityScope: scope,
39
+ teamId: selectedTeamId,
40
+ categoryId: selectedCategoryId,
41
+ shortcut: search || cannedQueryDebounced || "",
42
+ });
43
+ const validActiveCannedIndex = useMemo(() => {
44
+ return parseIndex(activeCannedIndex, (cannedResponses === null || cannedResponses === void 0 ? void 0 : cannedResponses.length) || 0);
45
+ }, [activeCannedIndex, cannedResponses === null || cannedResponses === void 0 ? void 0 : cannedResponses.length]);
46
+ const options = useMemo(() => {
47
+ return [
48
+ { label: t("team"), value: CannedResponseVisibleScope.TEAM },
49
+ { label: t("personal"), value: CannedResponseVisibleScope.PRIVATE },
50
+ ];
51
+ }, [t]);
52
+ const onSelectCategory = useCallback((teamId, categoryId) => {
53
+ setSelectedTeamId(teamId);
54
+ setSelectedCategoryId(categoryId);
55
+ }, []);
56
+ const renderTeamItem = useCallback((team, index) => {
57
+ return (_jsx(TeamItem, { team: team, onSelectCategory: onSelectCategory, selectedTeamId: selectedTeamId, selectedCategoryId: selectedCategoryId, defaultOpen: index === 0 }, team === null || team === void 0 ? void 0 : team.teamId));
58
+ }, [onSelectCategory, selectedTeamId, selectedCategoryId]);
59
+ useEffect(() => {
60
+ if (!isLoadingTeams && myTeams && myTeams.length > 0) {
61
+ setSelectedTeamId(myTeams[0].teamId);
62
+ }
63
+ }, [isLoadingTeams, myTeams]);
64
+ useEffect(() => {
65
+ const handler = (index) => {
66
+ var _a;
67
+ const validIndex = parseIndex(index, cannedResponses === null || cannedResponses === void 0 ? void 0 : cannedResponses.length);
68
+ if (validIndex !== null && !!(cannedResponses === null || cannedResponses === void 0 ? void 0 : cannedResponses[validIndex])) {
69
+ const htmlContent = ((_a = cannedResponses === null || cannedResponses === void 0 ? void 0 : cannedResponses[validIndex]) === null || _a === void 0 ? void 0 : _a.content) || "";
70
+ // 🔒 Sanitize HTML to prevent XSS attacks
71
+ const sanitizedContent = sanitizeHtml(htmlContent);
72
+ onSelectCannedResponse === null || onSelectCannedResponse === void 0 ? void 0 : onSelectCannedResponse(sanitizedContent);
73
+ }
74
+ };
75
+ emitter.on("CANNED_RESPONSE_SELECT", handler);
76
+ return () => {
77
+ emitter.off("CANNED_RESPONSE_SELECT", handler);
78
+ };
79
+ }, [cannedResponses, onSelectCannedResponse]);
80
+ useEffect(() => {
81
+ setActiveCannedIndex(0);
82
+ }, [search, cannedQueryDebounced, setActiveCannedIndex]);
83
+ useEffect(() => {
84
+ var _a, _b;
85
+ if (activeCannedIndex !== null) {
86
+ (_b = (_a = itemRefs.current) === null || _a === void 0 ? void 0 : _a[activeCannedIndex]) === null || _b === void 0 ? void 0 : _b.scrollIntoView({
87
+ block: "nearest",
88
+ });
89
+ }
90
+ }, [activeCannedIndex]);
91
+ useEffect(() => {
92
+ setMaxActiveCannedIndex((cannedResponses === null || cannedResponses === void 0 ? void 0 : cannedResponses.length) - 1 > 0 ? (cannedResponses === null || cannedResponses === void 0 ? void 0 : cannedResponses.length) - 1 : 0);
93
+ }, [cannedResponses, setMaxActiveCannedIndex]);
94
+ return (_jsxs("div", { className: "flex flex-1 flex-row h-[400px]", children: [_jsxs("div", { className: "w-[170px] p-2 border-r border-gray-200", children: [_jsx(Segmented, { options: options, block: true, size: "small", value: scope, onChange: setScope }), _jsx("div", { className: "overflow-y-auto h-full", children: scope === CannedResponseVisibleScope.TEAM && (_jsx("div", { className: "mt-1 flex flex-col", children: (_a = myTeams === null || myTeams === void 0 ? void 0 : myTeams.map) === null || _a === void 0 ? void 0 : _a.call(myTeams, (team, index) => renderTeamItem(team, index)) })) })] }), _jsxs("div", { id: "scrollableCannedDiv", className: "flex flex-col flex-1 h-full overflow-y-auto", children: [!!cannedQuery && !search && (_jsx("div", { className: "px-3 py-2 border-b border-gray-200", children: _jsxs("span", { className: "text-sm text-gray-500", children: [t("canned_response_quick_search_placeholder"), _jsx("span", { className: "text-blue-600", children: ` #${cannedQuery}` })] }) })), _jsx(InfiniteScroll, { dataLength: (cannedResponses === null || cannedResponses === void 0 ? void 0 : cannedResponses.length) || 0, next: fetchNextPage, hasMore: hasNextPage, loader: _jsx("div", { className: "flex items-center justify-center py-2", children: _jsx(Spin, {}) }), scrollableTarget: "scrollableCannedDiv", children: !isArray(cannedResponses) || (cannedResponses === null || cannedResponses === void 0 ? void 0 : cannedResponses.length) === 0 ? (_jsx("div", { className: "flex items-center justify-center py-12", children: _jsx(Empty, { image: _jsx(Icon, { icon: "chat-square-b", size: 80, className: "text-gray-300" }), description: t("no_canned_response") }) })) : ((_b = cannedResponses === null || cannedResponses === void 0 ? void 0 : cannedResponses.map) === null || _b === void 0 ? void 0 : _b.call(cannedResponses, (canned, index) => {
95
+ var _a, _b;
96
+ const isActive = index === validActiveCannedIndex;
97
+ const htmlContent = (canned === null || canned === void 0 ? void 0 : canned.content) || "";
98
+ // 🔒 Sanitize HTML to prevent XSS attacks
99
+ const sanitizedContent = sanitizeHtml(htmlContent);
100
+ return (_jsxs("div", { ref: (el) => {
101
+ itemRefs.current[index] = el;
102
+ }, className: clsx("flex flex-col flex-1 px-3 py-2 cursor-pointer hover:bg-blue-100 w-full border-b border-gray-200", isActive && "bg-blue-100"), onClick: () => onSelectCannedResponse === null || onSelectCannedResponse === void 0 ? void 0 : onSelectCannedResponse(sanitizedContent), children: [_jsxs("span", { className: "text-xs truncate text-gray-500", children: [`${((_a = canned === null || canned === void 0 ? void 0 : canned.category) === null || _a === void 0 ? void 0 : _a.name)
103
+ ? `${(_b = canned === null || canned === void 0 ? void 0 : canned.category) === null || _b === void 0 ? void 0 : _b.name} / `
104
+ : ""}`, _jsx("span", { className: "text-black", children: `${(canned === null || canned === void 0 ? void 0 : canned.name) || ""} ` }), _jsx("span", { children: "/" }), _jsx("span", { className: "text-blue-500", children: ` #${(canned === null || canned === void 0 ? void 0 : canned.shortcut) || ""}` })] }), _jsx("div", { dangerouslySetInnerHTML: {
105
+ __html: sanitizedContent,
106
+ }, className: "text-sm mt-1" })] }, canned === null || canned === void 0 ? void 0 : canned.id));
107
+ })) })] })] }));
108
+ };
109
+ export default CannedResponseBody;
@@ -0,0 +1,6 @@
1
+ interface ICannedResponseFooterProps {
2
+ openCreateCannedModal?: () => void;
3
+ }
4
+ declare const CannedResponseFooter: ({ openCreateCannedModal, }: ICannedResponseFooterProps) => import("react/jsx-runtime").JSX.Element;
5
+ export default CannedResponseFooter;
6
+ //# sourceMappingURL=CannedResponseFooter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CannedResponseFooter.d.ts","sourceRoot":"","sources":["../../../src/components/canned-response/CannedResponseFooter.tsx"],"names":[],"mappings":"AAGA,UAAU,0BAA0B;IAClC,qBAAqB,CAAC,EAAE,MAAM,IAAI,CAAC;CACpC;AAED,QAAA,MAAM,oBAAoB,GAAI,4BAE3B,0BAA0B,4CAgB5B,CAAC;AAEF,eAAe,oBAAoB,CAAC"}
@@ -0,0 +1,8 @@
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
+ const CannedResponseFooter = ({ openCreateCannedModal, }) => {
5
+ const { t } = useTranslation();
6
+ return (_jsx("div", { className: "flex items-center justify-end border-t border-gray-200 p-2", children: _jsxs("div", { className: "flex cursor-pointer items-center gap-1", onClick: openCreateCannedModal, children: [_jsx(Icon, { icon: "plus-circle-o", size: 16, className: "text-blue-500" }), _jsx("span", { className: "text-sm text-blue-500", children: t("add_canned_response") })] }) }));
7
+ };
8
+ export default CannedResponseFooter;
@@ -0,0 +1,8 @@
1
+ interface ICannedResponseHeaderProps {
2
+ onClose?: () => void;
3
+ search?: string;
4
+ setSearch?: (search: string) => void;
5
+ }
6
+ declare const CannedResponseHeader: (props: ICannedResponseHeaderProps) => import("react/jsx-runtime").JSX.Element;
7
+ export default CannedResponseHeader;
8
+ //# sourceMappingURL=CannedResponseHeader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CannedResponseHeader.d.ts","sourceRoot":"","sources":["../../../src/components/canned-response/CannedResponseHeader.tsx"],"names":[],"mappings":"AAKA,UAAU,0BAA0B;IAClC,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;CACtC;AAED,QAAA,MAAM,oBAAoB,GAAI,OAAO,0BAA0B,4CA+B9D,CAAC;AAEF,eAAe,oBAAoB,CAAC"}
@@ -0,0 +1,11 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useTranslation } from "react-i18next";
3
+ import CannedResponseIcon from "../../assets/svg/canned-response";
4
+ import { Button, Input } from "antd";
5
+ import { Icon } from "../../components/icon";
6
+ const CannedResponseHeader = (props) => {
7
+ const { onClose, search, setSearch } = props;
8
+ const { t } = useTranslation();
9
+ return (_jsxs("div", { className: "px-3 py-2 flex flex-row items-center gap-2 border-b border-gray-200", children: [_jsxs("div", { className: "flex flex-row items-center gap-2", children: [_jsx(CannedResponseIcon, { size: 20, className: "text-blue-500" }), _jsx("span", { className: "text-base font-medium", children: t("canned_responses") })] }), _jsxs("div", { className: "flex flex-1 flex-row items-center justify-end gap-2", children: [_jsx(Input, { size: "large", placeholder: t("search"), prefix: _jsx(Icon, { icon: "search-o", size: 20, className: "text-gray-500" }), style: { width: 260 }, className: "text-sm", value: search, onChange: (e) => setSearch === null || setSearch === void 0 ? void 0 : setSearch(e.target.value) }), _jsx(Button, { type: "text", shape: "default", className: "text-gray-500 w-8 h-8 p-0", onClick: onClose, children: _jsx(Icon, { icon: "close-o", size: 16 }) })] })] }));
10
+ };
11
+ export default CannedResponseHeader;
@@ -0,0 +1,8 @@
1
+ interface ICannedResponseProps {
2
+ onClose?: () => void;
3
+ openCreateCannedModal?: () => void;
4
+ cannedQuery?: string;
5
+ }
6
+ declare const CannedResponse: ({ onClose, openCreateCannedModal, cannedQuery, }: ICannedResponseProps) => import("react/jsx-runtime").JSX.Element;
7
+ export default CannedResponse;
8
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/canned-response/index.tsx"],"names":[],"mappings":"AASA,UAAU,oBAAoB;IAC5B,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,qBAAqB,CAAC,EAAE,MAAM,IAAI,CAAC;IACnC,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,QAAA,MAAM,cAAc,GAAI,kDAIrB,oBAAoB,4CAgDtB,CAAC;AAEF,eAAe,cAAc,CAAC"}