@droppii-org/chat-sdk 0.7.3 → 0.7.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (177) hide show
  1. package/dist/components/boot/BootProgressBar.d.ts +13 -0
  2. package/dist/components/boot/BootProgressBar.d.ts.map +1 -0
  3. package/dist/components/boot/BootProgressBar.js +18 -0
  4. package/dist/components/canned-response/CannedResponsePanel.d.ts.map +1 -1
  5. package/dist/components/canned-response/CannedResponsePanel.js +2 -2
  6. package/dist/components/common/BottomSheet.d.ts +18 -0
  7. package/dist/components/common/BottomSheet.d.ts.map +1 -0
  8. package/dist/components/common/BottomSheet.js +49 -0
  9. package/dist/components/common/DeskPanelDrawer.d.ts.map +1 -1
  10. package/dist/components/common/DeskPanelDrawer.js +29 -15
  11. package/dist/components/common/DeskSidePanel.d.ts.map +1 -1
  12. package/dist/components/common/DeskSidePanel.js +1 -1
  13. package/dist/components/compose/ComposeNewMessageModal.d.ts.map +1 -1
  14. package/dist/components/compose/ComposeNewMessageModal.js +3 -3
  15. package/dist/components/conversation/ConversationByGroupItem.d.ts.map +1 -1
  16. package/dist/components/conversation/ConversationByGroupItem.js +3 -8
  17. package/dist/components/conversation/ConversationBySessionItem.d.ts.map +1 -1
  18. package/dist/components/conversation/ConversationBySessionItem.js +3 -8
  19. package/dist/components/conversation/DeskConversationList.d.ts +4 -1
  20. package/dist/components/conversation/DeskConversationList.d.ts.map +1 -1
  21. package/dist/components/conversation/DeskConversationList.js +2 -2
  22. package/dist/components/conversation/DeskListHeader.d.ts +2 -0
  23. package/dist/components/conversation/DeskListHeader.d.ts.map +1 -1
  24. package/dist/components/conversation/DeskListHeader.js +3 -3
  25. package/dist/components/conversation-detail/ConversationMessageList.d.ts.map +1 -1
  26. package/dist/components/conversation-detail/ConversationMessageList.js +1 -1
  27. package/dist/components/conversation-inbox/ConversationInboxList.d.ts.map +1 -1
  28. package/dist/components/conversation-inbox/ConversationInboxList.js +12 -3
  29. package/dist/components/conversation-inbox/InboxBootStatus.d.ts +10 -0
  30. package/dist/components/conversation-inbox/InboxBootStatus.d.ts.map +1 -0
  31. package/dist/components/conversation-inbox/InboxBootStatus.js +34 -0
  32. package/dist/components/conversation-inbox/InboxListSkeleton.d.ts +6 -0
  33. package/dist/components/conversation-inbox/InboxListSkeleton.d.ts.map +1 -0
  34. package/dist/components/conversation-inbox/InboxListSkeleton.js +8 -0
  35. package/dist/components/group/GroupPanelHeader.js +1 -1
  36. package/dist/components/icon/strokeIconNodes.d.ts +6 -0
  37. package/dist/components/icon/strokeIconNodes.d.ts.map +1 -1
  38. package/dist/components/icon/strokeIconNodes.js +5 -0
  39. package/dist/components/message/MessageHeader.d.ts +3 -1
  40. package/dist/components/message/MessageHeader.d.ts.map +1 -1
  41. package/dist/components/message/MessageHeader.js +10 -6
  42. package/dist/components/message/MessageList.d.ts +2 -0
  43. package/dist/components/message/MessageList.d.ts.map +1 -1
  44. package/dist/components/message/MessageList.js +15 -4
  45. package/dist/components/message/SelectSession.js +1 -1
  46. package/dist/components/message/footer/ActionBar.d.ts.map +1 -1
  47. package/dist/components/message/footer/ActionBar.js +2 -2
  48. package/dist/components/message/footer/ComposerTabs.js +1 -1
  49. package/dist/components/message/footer/CrmComposerCard.js +1 -1
  50. package/dist/components/message/footer/EmojiPicker.d.ts +3 -1
  51. package/dist/components/message/footer/EmojiPicker.d.ts.map +1 -1
  52. package/dist/components/message/footer/EmojiPicker.js +3 -2
  53. package/dist/components/message/footer/EnterHandler.d.ts.map +1 -1
  54. package/dist/components/message/footer/EnterHandler.js +16 -2
  55. package/dist/components/message/footer/MediaActions.d.ts +2 -1
  56. package/dist/components/message/footer/MediaActions.d.ts.map +1 -1
  57. package/dist/components/message/footer/MediaActions.js +4 -4
  58. package/dist/components/message/footer/ToolbarPlugin.js +1 -1
  59. package/dist/components/message/footer/mention/MentionMenu.js +1 -1
  60. package/dist/components/message/headerIconButton.js +1 -1
  61. package/dist/components/message/item/MessageMoreButton.d.ts.map +1 -1
  62. package/dist/components/message/item/MessageMoreButton.js +18 -5
  63. package/dist/components/message/item/QuoteMessage.d.ts.map +1 -1
  64. package/dist/components/message/item/QuoteMessage.js +3 -50
  65. package/dist/components/message/reply/ReplyPreviewBar.d.ts.map +1 -1
  66. package/dist/components/message/reply/ReplyPreviewBar.js +4 -13
  67. package/dist/components/rich-text-editor/RichTextEditor.d.ts +3 -1
  68. package/dist/components/rich-text-editor/RichTextEditor.d.ts.map +1 -1
  69. package/dist/components/rich-text-editor/RichTextEditor.js +4 -2
  70. package/dist/components/search-conversation/item/SearchItemAsGroup.d.ts.map +1 -1
  71. package/dist/components/search-conversation/item/SearchItemAsGroup.js +3 -3
  72. package/dist/components/search-conversation/item/SearchItemAsMessage.d.ts.map +1 -1
  73. package/dist/components/search-conversation/item/SearchItemAsMessage.js +10 -0
  74. package/dist/components/search-conversation/item/SearchItemAsUser.d.ts.map +1 -1
  75. package/dist/components/search-conversation/item/SearchItemAsUser.js +6 -0
  76. package/dist/components/session/DeskAssignedSession.js +2 -2
  77. package/dist/components/session/FolderRow.js +1 -1
  78. package/dist/components/thread/ManualAssignPopover.d.ts.map +1 -1
  79. package/dist/components/thread/ManualAssignPopover.js +13 -6
  80. package/dist/components/thread/SessionDetailCard.js +1 -1
  81. package/dist/components/thread/SessionTagPicker.js +1 -1
  82. package/dist/components/thread/SupportSessionPanel.d.ts +1 -1
  83. package/dist/components/thread/SupportSessionPanel.d.ts.map +1 -1
  84. package/dist/components/thread/SupportSessionPanel.js +1 -1
  85. package/dist/components/thread/ThreadInfo.d.ts.map +1 -1
  86. package/dist/components/thread/ThreadInfo.js +3 -1
  87. package/dist/components/thread/ThreadInfoHeader.d.ts +1 -1
  88. package/dist/components/thread/ThreadInfoHeader.d.ts.map +1 -1
  89. package/dist/components/thread/ThreadInfoHeader.js +1 -1
  90. package/dist/components/thread/UserSection.js +2 -2
  91. package/dist/constants/layout.d.ts +10 -1
  92. package/dist/constants/layout.d.ts.map +1 -1
  93. package/dist/constants/layout.js +10 -1
  94. package/dist/hooks/common/useDeskShortcuts.d.ts.map +1 -1
  95. package/dist/hooks/common/useDeskShortcuts.js +3 -1
  96. package/dist/hooks/common/useIsDeskWorkspaceMounted.d.ts +3 -0
  97. package/dist/hooks/common/useIsDeskWorkspaceMounted.d.ts.map +1 -0
  98. package/dist/hooks/common/useIsDeskWorkspaceMounted.js +4 -0
  99. package/dist/hooks/common/useViewportTier.d.ts +4 -0
  100. package/dist/hooks/common/useViewportTier.d.ts.map +1 -0
  101. package/dist/hooks/common/useViewportTier.js +9 -0
  102. package/dist/hooks/common/useVisualViewportHeight.d.ts +10 -0
  103. package/dist/hooks/common/useVisualViewportHeight.d.ts.map +1 -0
  104. package/dist/hooks/common/useVisualViewportHeight.js +30 -0
  105. package/dist/hooks/conversation/useConversationList.d.ts.map +1 -1
  106. package/dist/hooks/conversation/useConversationList.js +31 -0
  107. package/dist/hooks/conversation/useDeskOfflineLock.d.ts +9 -0
  108. package/dist/hooks/conversation/useDeskOfflineLock.d.ts.map +1 -0
  109. package/dist/hooks/conversation/useDeskOfflineLock.js +46 -0
  110. package/dist/hooks/conversation/useDeskThreadNavigation.d.ts +19 -0
  111. package/dist/hooks/conversation/useDeskThreadNavigation.d.ts.map +1 -0
  112. package/dist/hooks/conversation/useDeskThreadNavigation.js +68 -0
  113. package/dist/hooks/global/useGlobalEvent.d.ts.map +1 -1
  114. package/dist/hooks/global/useGlobalEvent.js +22 -2
  115. package/dist/hooks/group/useCreateGroup.d.ts.map +1 -1
  116. package/dist/hooks/group/useCreateGroup.js +4 -4
  117. package/dist/hooks/init/useChatBootPhase.d.ts +30 -0
  118. package/dist/hooks/init/useChatBootPhase.d.ts.map +1 -0
  119. package/dist/hooks/init/useChatBootPhase.js +72 -0
  120. package/dist/hooks/message/usePinMessage.d.ts +0 -2
  121. package/dist/hooks/message/usePinMessage.d.ts.map +1 -1
  122. package/dist/hooks/message/usePinMessage.js +7 -11
  123. package/dist/hooks/message/useQuotedSenderName.d.ts +14 -0
  124. package/dist/hooks/message/useQuotedSenderName.d.ts.map +1 -0
  125. package/dist/hooks/message/useQuotedSenderName.js +41 -0
  126. package/dist/hooks/user/useAuth.d.ts.map +1 -1
  127. package/dist/hooks/user/useAuth.js +2 -0
  128. package/dist/index.d.ts +5 -1
  129. package/dist/index.d.ts.map +1 -1
  130. package/dist/index.js +5 -1
  131. package/dist/locales/i18n.d.ts.map +1 -1
  132. package/dist/locales/i18n.js +3 -2
  133. package/dist/locales/i18n.ts +3 -2
  134. package/dist/locales/vi/boot.json +28 -0
  135. package/dist/locales/vi/common.json +1 -1
  136. package/dist/screens/conversation-detail/index.d.ts.map +1 -1
  137. package/dist/screens/conversation-detail/index.js +8 -3
  138. package/dist/screens/desk-message/DeskBootCard.d.ts +7 -0
  139. package/dist/screens/desk-message/DeskBootCard.d.ts.map +1 -0
  140. package/dist/screens/desk-message/DeskBootCard.js +69 -0
  141. package/dist/screens/desk-message/DeskOfflineOverlay.d.ts +10 -0
  142. package/dist/screens/desk-message/DeskOfflineOverlay.d.ts.map +1 -0
  143. package/dist/screens/desk-message/DeskOfflineOverlay.js +11 -0
  144. package/dist/screens/desk-message/DeskWorkspace.d.ts +7 -1
  145. package/dist/screens/desk-message/DeskWorkspace.d.ts.map +1 -1
  146. package/dist/screens/desk-message/DeskWorkspace.js +82 -13
  147. package/dist/screens/desk-message/DeskWorkspaceSkeleton.d.ts +10 -0
  148. package/dist/screens/desk-message/DeskWorkspaceSkeleton.d.ts.map +1 -0
  149. package/dist/screens/desk-message/DeskWorkspaceSkeleton.js +18 -0
  150. package/dist/screens/desk-message/PhoneThreadFallbackHeader.d.ts +8 -0
  151. package/dist/screens/desk-message/PhoneThreadFallbackHeader.d.ts.map +1 -0
  152. package/dist/screens/desk-message/PhoneThreadFallbackHeader.js +11 -0
  153. package/dist/screens/desk-message/index.d.ts +2 -0
  154. package/dist/screens/desk-message/index.d.ts.map +1 -1
  155. package/dist/screens/desk-message/index.js +47 -3
  156. package/dist/store/boot.d.ts +29 -0
  157. package/dist/store/boot.d.ts.map +1 -0
  158. package/dist/store/boot.js +21 -0
  159. package/dist/store/conversation.d.ts +2 -0
  160. package/dist/store/conversation.d.ts.map +1 -1
  161. package/dist/store/conversation.js +13 -12
  162. package/dist/store/deskPanelHost.d.ts +2 -0
  163. package/dist/store/deskPanelHost.d.ts.map +1 -1
  164. package/dist/store/deskPanelHost.js +1 -0
  165. package/dist/store/type.d.ts +4 -1
  166. package/dist/store/type.d.ts.map +1 -1
  167. package/dist/store/workspaceLayout.d.ts +3 -0
  168. package/dist/store/workspaceLayout.d.ts.map +1 -1
  169. package/dist/store/workspaceLayout.js +2 -0
  170. package/dist/styles/global.css +1 -1
  171. package/dist/utils/conversation.d.ts +1 -0
  172. package/dist/utils/conversation.d.ts.map +1 -1
  173. package/dist/utils/conversation.js +1 -1
  174. package/package.json +1 -1
  175. package/dist/screens/desk-message/ViewportNotice.d.ts +0 -4
  176. package/dist/screens/desk-message/ViewportNotice.d.ts.map +0 -1
  177. package/dist/screens/desk-message/ViewportNotice.js +0 -9
@@ -1,30 +1,21 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useTranslation } from "react-i18next";
3
3
  import { AdaptiveIcon } from "../../../components/icon/AdaptiveIcon";
4
- import useAuthStore from "../../../store/auth";
5
4
  import useConversationStore from "../../../store/conversation";
6
- import { useUserUsername } from "../../../hooks/user/useUserUsername";
7
- import { isSupportSessionAgentView } from "../../../utils/conversation";
5
+ import { useQuotedSenderName } from "../../../hooks/message/useQuotedSenderName";
8
6
  import { ReplyQuoteContent } from "./ReplyQuoteContent";
9
7
  export const ReplyPreviewBar = () => {
10
8
  const { t } = useTranslation();
11
9
  const quotedMessage = useConversationStore((state) => state.quotedMessage);
12
10
  const setQuotedMessage = useConversationStore((state) => state.setQuotedMessage);
13
- const conversationData = useConversationStore((state) => state.conversationData);
14
- const userID = useAuthStore((state) => state.userID);
15
- const isCrm = useAuthStore((state) => state.isCrm);
16
- const isMe = (quotedMessage === null || quotedMessage === void 0 ? void 0 : quotedMessage.sendID) === userID;
17
- // Matches the sent quote's title, which shows agents outside CRM the username.
18
- const isAgentView = !isCrm && isSupportSessionAgentView(conversationData, userID);
19
- const quotedUsername = useUserUsername(isAgentView && !isMe ? quotedMessage === null || quotedMessage === void 0 ? void 0 : quotedMessage.sendID : undefined);
11
+ // Same name the sent quote will carry.
12
+ const { isMe, name } = useQuotedSenderName(quotedMessage);
20
13
  const handleClearQuotedMessage = () => {
21
14
  setQuotedMessage(null);
22
15
  };
23
16
  if (!quotedMessage)
24
17
  return null;
25
- const senderName = isMe
26
- ? t("your_self")
27
- : quotedUsername || quotedMessage.senderNickname || "";
18
+ const senderName = isMe ? t("your_self") : name;
28
19
  return (_jsxs("div", { "data-testid": "reply-preview-bar", "data-cp-name": "ReplyPreviewBar", 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(AdaptiveIcon, { stroke: "x", font: "close-o", size: 16, className: "text-gray-600" }) })] }));
29
20
  };
30
21
  export default ReplyPreviewBar;
@@ -6,7 +6,9 @@ interface RichTextEditorProps {
6
6
  onFilesChange?: (files: UploadFile[]) => void;
7
7
  minHeight?: string;
8
8
  showMediaUpload?: boolean;
9
+ /** CRM: hide the emoji button on phones (the system keyboard has emoji). */
10
+ hideEmojiOnPhone?: boolean;
9
11
  }
10
- export default function RichTextEditor({ initialHtml, placeholder, onChange, onFilesChange, minHeight, showMediaUpload, }: RichTextEditorProps): import("react/jsx-runtime").JSX.Element;
12
+ export default function RichTextEditor({ initialHtml, placeholder, onChange, onFilesChange, minHeight, showMediaUpload, hideEmojiOnPhone, }: RichTextEditorProps): import("react/jsx-runtime").JSX.Element;
11
13
  export {};
12
14
  //# sourceMappingURL=RichTextEditor.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"RichTextEditor.d.ts","sourceRoot":"","sources":["../../../src/components/rich-text-editor/RichTextEditor.tsx"],"names":[],"mappings":"AAYA,OAAO,EAAE,UAAU,EAAE,MAAM,MAAM,CAAC;AA0ClC,UAAU,mBAAmB;IAC3B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IACrD,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,EAAE,KAAK,IAAI,CAAC;IAC9C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED,MAAM,CAAC,OAAO,UAAU,cAAc,CAAC,EACrC,WAAW,EACX,WAAW,EACX,QAAQ,EACR,aAAa,EACb,SAAmB,EACnB,eAAsB,GACvB,EAAE,mBAAmB,2CA6DrB"}
1
+ {"version":3,"file":"RichTextEditor.d.ts","sourceRoot":"","sources":["../../../src/components/rich-text-editor/RichTextEditor.tsx"],"names":[],"mappings":"AAYA,OAAO,EAAE,UAAU,EAAE,MAAM,MAAM,CAAC;AA2ClC,UAAU,mBAAmB;IAC3B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IACrD,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,EAAE,KAAK,IAAI,CAAC;IAC9C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,4EAA4E;IAC5E,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B;AAED,MAAM,CAAC,OAAO,UAAU,cAAc,CAAC,EACrC,WAAW,EACX,WAAW,EACX,QAAQ,EACR,aAAa,EACb,SAAmB,EACnB,eAAsB,EACtB,gBAAwB,GACzB,EAAE,mBAAmB,2CAkErB"}
@@ -13,6 +13,7 @@ import { $getRoot } from "lexical";
13
13
  import { useLexicalComposerContext } from "@lexical/react/LexicalComposerContext";
14
14
  import { useEffect } from "react";
15
15
  import { ToolbarPlugin } from "../../components/message/footer/ToolbarPlugin";
16
+ import clsx from "clsx";
16
17
  import MediaActions from "../../components/message/footer/MediaActions";
17
18
  import { FilePreviewList } from "../../components/message/footer/FilePreview";
18
19
  import { editorTheme, editorNodes, editorOnError, } from "../../components/message/footer/editorConfig";
@@ -38,7 +39,7 @@ function HtmlPlugin({ initialHtml }) {
38
39
  }, [editor, initialHtml]);
39
40
  return null;
40
41
  }
41
- export default function RichTextEditor({ initialHtml, placeholder, onChange, onFilesChange, minHeight = "160px", showMediaUpload = true, }) {
42
+ export default function RichTextEditor({ initialHtml, placeholder, onChange, onFilesChange, minHeight = "160px", showMediaUpload = true, hideEmojiOnPhone = false, }) {
42
43
  const [listUploadFiles, setListUploadFiles] = useState([]);
43
44
  const handleChange = (editorState, editor, tags) => {
44
45
  if (tags.has("initial-html"))
@@ -58,5 +59,6 @@ export default function RichTextEditor({ initialHtml, placeholder, onChange, onF
58
59
  setListUploadFiles(files);
59
60
  onFilesChange === null || onFilesChange === void 0 ? void 0 : onFilesChange(files);
60
61
  };
61
- return (_jsxs(LexicalComposer, { initialConfig: EDITOR_CONFIG, children: [_jsxs("div", { className: "border border-gray-200 rounded-lg", children: [_jsx(FilePreviewList, { files: listUploadFiles, onRemove: handleRemoveFile }), _jsx("div", { className: "relative", children: _jsx(RichTextPlugin, { contentEditable: _jsx(ContentEditable, { className: "px-3 py-2 text-sm outline-none", style: { minHeight } }), ErrorBoundary: LexicalErrorBoundary, placeholder: placeholder ? (_jsx("div", { className: "absolute top-2 left-3 pointer-events-none", children: _jsx("p", { className: "text-gray-400 text-sm", children: placeholder }) })) : null }) }), _jsxs("div", { className: "flex items-center border-t border-gray-100 px-2 py-1", children: [_jsx(ToolbarPlugin, {}), _jsx(MediaActions, { listUploadFiles: listUploadFiles, onFilesChange: handleFilesChange, showMediaUpload: showMediaUpload })] })] }), _jsx(LinkPlugin, {}), _jsx(ListPlugin, {}), _jsx(OnChangePlugin, { onChange: handleChange, ignoreSelectionChange: true }), _jsx(HtmlPlugin, { initialHtml: initialHtml })] }));
62
+ return (_jsxs(LexicalComposer, { initialConfig: EDITOR_CONFIG, children: [_jsxs("div", { className: "border border-gray-200 rounded-lg", children: [_jsx(FilePreviewList, { files: listUploadFiles, onRemove: handleRemoveFile }), _jsx("div", { className: "relative", children: _jsx(RichTextPlugin, { contentEditable: _jsx(ContentEditable, { className: "px-3 py-2 text-sm outline-none", style: { minHeight } }), ErrorBoundary: LexicalErrorBoundary, placeholder: placeholder ? (_jsx("div", { className: "absolute top-2 left-3 pointer-events-none", children: _jsx("p", { className: "text-gray-400 text-sm", children: placeholder }) })) : null }) }), _jsxs("div", { className: clsx("flex items-center border-t border-gray-100 px-2 py-1", hideEmojiOnPhone &&
63
+ "flex-wrap max-sm:[&_[data-cp-name=ToolbarPlugin]]:!gap-1 max-sm:[&_[data-cp-name=ToolbarPlugin]]:!px-1"), children: [_jsx(ToolbarPlugin, {}), _jsx(MediaActions, { listUploadFiles: listUploadFiles, onFilesChange: handleFilesChange, showMediaUpload: showMediaUpload, hideEmojiOnPhone: hideEmojiOnPhone })] })] }), _jsx(LinkPlugin, {}), _jsx(ListPlugin, {}), _jsx(OnChangePlugin, { onChange: handleChange, ignoreSelectionChange: true }), _jsx(HtmlPlugin, { initialHtml: initialHtml })] }));
62
64
  }
@@ -1 +1 @@
1
- {"version":3,"file":"SearchItemAsGroup.d.ts","sourceRoot":"","sources":["../../../../src/components/search-conversation/item/SearchItemAsGroup.tsx"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,qCAAqC,CAAC;AAUxF,UAAU,sBAAsB;IAC9B,KAAK,EAAE,4BAA4B,CAAC;IACpC,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,QAAA,MAAM,iBAAiB,GAAI,OAAO,sBAAsB,4CA4FvD,CAAC;AAEF,eAAe,iBAAiB,CAAC"}
1
+ {"version":3,"file":"SearchItemAsGroup.d.ts","sourceRoot":"","sources":["../../../../src/components/search-conversation/item/SearchItemAsGroup.tsx"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,qCAAqC,CAAC;AAUxF,UAAU,sBAAsB;IAC9B,KAAK,EAAE,4BAA4B,CAAC;IACpC,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,QAAA,MAAM,iBAAiB,GAAI,OAAO,sBAAsB,4CA+FvD,CAAC;AAEF,eAAe,iBAAiB,CAAC"}
@@ -7,7 +7,7 @@ import { AdaptiveIcon } from "../../../components/icon/AdaptiveIcon";
7
7
  import { useTranslation } from "react-i18next";
8
8
  import { GroupVisibility } from "@droppii-org/wasm-client-sdk";
9
9
  import useConversationStore from "../../../store/conversation";
10
- import { useChatNavigate } from "../../../hooks/conversation/useChatNavigate";
10
+ import { useDeskThreadNavigation } from "../../../hooks/conversation/useDeskThreadNavigation";
11
11
  import { highlightSearch, sanitizeHtml } from "../../../utils/common";
12
12
  import GroupCompositeAvatar from "../../../components/group/GroupCompositeAvatar";
13
13
  import RowChip from "../../../components/conversation/RowChip";
@@ -18,7 +18,7 @@ const SearchItemAsGroup = (props) => {
18
18
  const { group, searchTerm = "" } = props;
19
19
  const { t } = useTranslation();
20
20
  const isCrm = useAuthStore((state) => state.isCrm);
21
- const onNavigate = useChatNavigate();
21
+ const { openThread } = useDeskThreadNavigation();
22
22
  const scope = useSearchScope();
23
23
  const openPdpResult = useOpenPdpSearchResult();
24
24
  const setConversationData = useConversationStore((state) => state.setConversationData);
@@ -39,7 +39,7 @@ const SearchItemAsGroup = (props) => {
39
39
  newSearchParams.delete("userId");
40
40
  newSearchParams.delete("groupId");
41
41
  newSearchParams.delete("botId");
42
- onNavigate(`${window.location.pathname}?${newSearchParams.toString()}`);
42
+ openThread({ threadId: conversation.conversationID }, `${window.location.pathname}?${newSearchParams.toString()}`);
43
43
  };
44
44
  return (_jsxs("div", Object.assign({ className: searchRowClass(isCrm) }, clickableProps(onPressItem), { "data-cp-name": "SearchItemAsGroup", children: [_jsx(GroupCompositeAvatar, { groupID: group.groupId, faceURL: conversation.faceURL, groupName: conversation.showName, size: isCrm ? 40 : 48 }), _jsxs("div", { className: "flex flex-col flex-1 min-w-0 gap-0.5", children: [_jsx("p", { className: isCrm
45
45
  ? "m-0 truncate text-sm font-medium text-gray-900"
@@ -1 +1 @@
1
- {"version":3,"file":"SearchItemAsMessage.d.ts","sourceRoot":"","sources":["../../../../src/components/search-conversation/item/SearchItemAsMessage.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAE,WAAW,EAA4B,MAAM,8BAA8B,CAAC;AA0BrF,UAAU,wBAAwB;IAChC,OAAO,EAAE,WAAW,GAAG;QAAE,SAAS,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC;IAC/C,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,2EAA2E;IAC3E,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB;AAED,QAAA,MAAM,mBAAmB,GAAI,OAAO,wBAAwB,4CAsJ3D,CAAC;AAEF,eAAe,mBAAmB,CAAC"}
1
+ {"version":3,"file":"SearchItemAsMessage.d.ts","sourceRoot":"","sources":["../../../../src/components/search-conversation/item/SearchItemAsMessage.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAE,WAAW,EAA4B,MAAM,8BAA8B,CAAC;AA2BrF,UAAU,wBAAwB;IAChC,OAAO,EAAE,WAAW,GAAG;QAAE,SAAS,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC;IAC/C,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,2EAA2E;IAC3E,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB;AAED,QAAA,MAAM,mBAAmB,GAAI,OAAO,wBAAwB,4CA+J3D,CAAC;AAEF,eAAe,mBAAmB,CAAC"}
@@ -16,6 +16,7 @@ import RowChip from "../../../components/conversation/RowChip";
16
16
  import useAuthStore from "../../../store/auth";
17
17
  import { getConversationIdFromMessage } from "../../../utils/conversation";
18
18
  import { useOpenPdpSearchResult } from "../../../hooks/search/useOpenPdpSearchResult";
19
+ import { useDeskThreadNavigation } from "../../../hooks/conversation/useDeskThreadNavigation";
19
20
  import { useSearchScope } from "../SearchScopeContext";
20
21
  // PDP labels the source by its inbox tab; BE's displayTag carries the CS team name.
21
22
  const PDP_TAG_LABEL_KEYS = {
@@ -31,6 +32,7 @@ const SearchItemAsMessage = (props) => {
31
32
  const scope = useSearchScope();
32
33
  const isPdpPortal = scope === "pdp-portal";
33
34
  const openPdpResult = useOpenPdpSearchResult();
35
+ const { openFromList } = useDeskThreadNavigation();
34
36
  const conversationData = useConversationStore((state) => state.conversationData);
35
37
  const useConversationDisplay = useMemo(() => {
36
38
  // PDP results span many threads, so show the sender like CRM does.
@@ -66,9 +68,17 @@ const SearchItemAsMessage = (props) => {
66
68
  .setConversationData(data, message.clientMsgID, {
67
69
  forceRevalidate: true,
68
70
  });
71
+ const previousId = useConversationStore.getState().selectedConversationId;
69
72
  useConversationStore
70
73
  .getState()
71
74
  .setSelectedConversationId(data.conversationID);
75
+ // CRM hits get a URL (and history entry) like list rows; hits inside the open thread don't.
76
+ if (isCrm && data.conversationID !== previousId) {
77
+ openFromList({
78
+ threadId: data.conversationID,
79
+ messageId: message.clientMsgID,
80
+ });
81
+ }
72
82
  onClick === null || onClick === void 0 ? void 0 : onClick();
73
83
  };
74
84
  let msgContent = "";
@@ -1 +1 @@
1
- {"version":3,"file":"SearchItemAsUser.d.ts","sourceRoot":"","sources":["../../../../src/components/search-conversation/item/SearchItemAsUser.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAIhD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yCAAyC,CAAC;AAclF,UAAU,qBAAqB;IAE7B,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,gBAAgB,EAAE,cAAc,CAAC,CAAC,CAAC;IAC9E,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,QAAA,MAAM,gBAAgB,GAAI,OAAO,qBAAqB,4CAsFrD,CAAC;AAEF,eAAe,gBAAgB,CAAC"}
1
+ {"version":3,"file":"SearchItemAsUser.d.ts","sourceRoot":"","sources":["../../../../src/components/search-conversation/item/SearchItemAsUser.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAIhD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yCAAyC,CAAC;AAelF,UAAU,qBAAqB;IAE7B,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,gBAAgB,EAAE,cAAc,CAAC,CAAC,CAAC;IAC9E,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,QAAA,MAAM,gBAAgB,GAAI,OAAO,qBAAqB,4CA2FrD,CAAC;AAEF,eAAe,gBAAgB,CAAC"}
@@ -7,6 +7,7 @@ import { highlightSearch, sanitizeHtml } from "../../../utils/common";
7
7
  import useConversationStore from "../../../store/conversation";
8
8
  import { useTranslation } from "react-i18next";
9
9
  import { useOpenPdpSearchResult } from "../../../hooks/search/useOpenPdpSearchResult";
10
+ import { useDeskThreadNavigation } from "../../../hooks/conversation/useDeskThreadNavigation";
10
11
  import { useSearchScope } from "../SearchScopeContext";
11
12
  import useAuthStore from "../../../store/auth";
12
13
  import { SessionStatus } from "../../../types/chat";
@@ -23,6 +24,7 @@ const SearchItemAsUser = (props) => {
23
24
  const { t } = useTranslation();
24
25
  const scope = useSearchScope();
25
26
  const openPdpResult = useOpenPdpSearchResult();
27
+ const { openFromList } = useDeskThreadNavigation();
26
28
  const isCrm = useAuthStore((state) => state.isCrm);
27
29
  const ownerName = `${(_a = session.owner) === null || _a === void 0 ? void 0 : _a.fullName}${((_b = session.owner) === null || _b === void 0 ? void 0 : _b.username) ? ` (${(_c = session.owner) === null || _c === void 0 ? void 0 : _c.username})` : ""}`;
28
30
  const onPressItem = async () => {
@@ -32,10 +34,14 @@ const SearchItemAsUser = (props) => {
32
34
  if (!(session === null || session === void 0 ? void 0 : session.conversation)) {
33
35
  return message.error(t("err_get_conversation"));
34
36
  }
37
+ const previousId = useConversationStore.getState().selectedConversationId;
35
38
  useConversationStore.getState().setConversationData(session.conversation);
36
39
  useConversationStore
37
40
  .getState()
38
41
  .setSelectedConversationId(session.conversationId);
42
+ if (isCrm && session.conversationId !== previousId) {
43
+ openFromList({ threadId: session.conversationId });
44
+ }
39
45
  };
40
46
  return (_jsxs("div", Object.assign({ className: searchRowClass(isCrm) }, clickableProps(onPressItem), { "data-cp-name": "SearchItemAsUser", children: [isCrm ? (_jsx(TintedAvatar, { name: ((_d = session.owner) === null || _d === void 0 ? void 0 : _d.fullName) || ((_e = session.owner) === null || _e === void 0 ? void 0 : _e.username) || "", src: (_f = session.owner) === null || _f === void 0 ? void 0 : _f.avatar, size: 40 })) : (_jsx(Avatar, { size: "large", src: (_g = session.owner) === null || _g === void 0 ? void 0 : _g.avatar, alt: (_h = session.owner) === null || _h === void 0 ? void 0 : _h.username, children: (_k = (_j = session.owner) === null || _j === void 0 ? void 0 : _j.fullName) === null || _k === void 0 ? void 0 : _k.charAt(0).toUpperCase() })), _jsxs("div", { className: "flex flex-col flex-1 min-w-0", children: [_jsx("p", { className: isCrm
41
47
  ? "m-0 truncate text-sm font-medium text-gray-900"
@@ -54,9 +54,9 @@ const DeskAssignedSession = ({ variant = "inline" }) => {
54
54
  };
55
55
  }, [refetch]);
56
56
  if (collapsed) {
57
- return (_jsx("div", { className: "flex flex-col items-center shrink-0 pt-3 rounded-xl bg-white shadow-sm", style: { width: LAYOUT_WIDTHS.folderCollapsed }, "data-cp-name": "DeskAssignedSession", children: _jsx(Tooltip, { title: t("folder_panel_expand"), placement: "right", children: _jsx(Button, { type: "text", className: "text-gray-600 w-8 h-8 p-0", "aria-label": t("folder_panel_expand"), onClick: () => setFolderCollapsedChoice(false), children: _jsx(StrokeIcon, { name: "chevrons-right", size: 20 }) }) }) }));
57
+ return (_jsx("div", { className: "flex flex-col items-center shrink-0 pt-3 rounded-xl bg-white shadow-sm", style: { width: LAYOUT_WIDTHS.folderCollapsed }, "data-cp-name": "DeskAssignedSession", children: _jsx(Tooltip, { title: t("folder_panel_expand"), placement: "right", children: _jsx(Button, { type: "text", className: "text-gray-600 w-8 h-8 p-0 touch:min-h-10 touch:min-w-10", "aria-label": t("folder_panel_expand"), onClick: () => setFolderCollapsedChoice(false), children: _jsx(StrokeIcon, { name: "chevrons-right", size: 20 }) }) }) }));
58
58
  }
59
- return (_jsxs("aside", { "aria-label": t("folder_panel_title"), className: `flex flex-col h-full shrink-0 overflow-hidden rounded-xl bg-white ${isOverlay ? "shadow-lg" : "shadow-sm"}`, style: { width: LAYOUT_WIDTHS.folder }, "data-cp-name": "DeskAssignedSession", children: [_jsxs("div", { className: "flex items-center justify-between h-14 pl-4 pr-2 border-b border-gray-25 shrink-0", children: [_jsx("span", { className: "text-base font-bold flex-1 truncate", children: t("desk_brand") }), _jsx(Tooltip, { title: t(isOverlay ? "folder_panel_close" : "folder_panel_collapse"), children: _jsx(Button, { type: "text", className: "text-gray-600 w-8 h-8 p-0", "aria-label": t(isOverlay ? "folder_panel_close" : "folder_panel_collapse"), onClick: () => isOverlay ? setFolderOverlayOpen(false) : setFolderCollapsedChoice(true), children: _jsx(StrokeIcon, { name: isOverlay ? "x" : "chevrons-left", size: 18 }) }) })] }), _jsxs("div", { className: "flex min-h-0 flex-1 flex-col gap-0.5 overflow-y-auto px-2 pb-2 pt-1", children: [_jsx("div", { className: "px-2 pb-1 pt-3 text-xs font-medium text-gray-600", children: t("my_messages") }), sessionSummary && (_jsx(SessionFolderList, { summary: sessionSummary, activeFolderId: activeFolderId, onFilterSelect: onFilterSelect, allGroups: {
59
+ return (_jsxs("aside", { "aria-label": t("folder_panel_title"), className: `flex flex-col h-full shrink-0 overflow-hidden rounded-xl bg-white ${isOverlay ? "shadow-lg" : "shadow-sm"}`, style: { width: LAYOUT_WIDTHS.folder }, "data-cp-name": "DeskAssignedSession", children: [_jsxs("div", { className: "flex items-center justify-between h-14 pl-4 pr-2 border-b border-gray-25 shrink-0", children: [_jsx("span", { className: "text-base font-bold flex-1 truncate", children: t("desk_brand") }), _jsx(Tooltip, { title: t(isOverlay ? "folder_panel_close" : "folder_panel_collapse"), children: _jsx(Button, { type: "text", className: "text-gray-600 w-8 h-8 p-0 touch:min-h-10 touch:min-w-10", "aria-label": t(isOverlay ? "folder_panel_close" : "folder_panel_collapse"), onClick: () => isOverlay ? setFolderOverlayOpen(false) : setFolderCollapsedChoice(true), children: _jsx(StrokeIcon, { name: isOverlay ? "x" : "chevrons-left", size: 18 }) }) })] }), _jsxs("div", { className: "flex min-h-0 flex-1 flex-col gap-0.5 overflow-y-auto px-2 pb-2 pt-1", children: [_jsx("div", { className: "px-2 pb-1 pt-3 text-xs font-medium text-gray-600", children: t("my_messages") }), sessionSummary && (_jsx(SessionFolderList, { summary: sessionSummary, activeFolderId: activeFolderId, onFilterSelect: onFilterSelect, allGroups: {
60
60
  active: viewMode === "allGroups",
61
61
  onSelect: onAllGroupsSelect,
62
62
  } })), _jsx(DeskTeamInbox, {})] })] }));
@@ -10,7 +10,7 @@ export const FolderCount = ({ count, highlighted, }) => {
10
10
  return highlighted ? (_jsx("span", { className: "inline-flex h-5 min-w-5 shrink-0 items-center justify-center rounded-full bg-danger-600 px-1.5 text-xs font-semibold tabular-nums text-white", children: formatCount(count) })) : (_jsx("span", { className: "shrink-0 text-xs tabular-nums text-gray-600", children: formatCount(count) }));
11
11
  };
12
12
  /** One selectable folder in the desk sidebar. */
13
- const FolderRow = ({ label, iconName, iconClassName, count = 0, highlighted, active = false, indentClassName = "pl-2", onClick, }) => (_jsxs("button", { type: "button", onClick: onClick, "aria-current": active ? "true" : undefined, "data-cp-name": "FolderRow", className: clsx("flex h-9 min-w-0 flex-1 items-center gap-2 rounded-lg pr-2 text-left text-sm transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary-400", indentClassName, active
13
+ const FolderRow = ({ label, iconName, iconClassName, count = 0, highlighted, active = false, indentClassName = "pl-2", onClick, }) => (_jsxs("button", { type: "button", onClick: onClick, "aria-current": active ? "true" : undefined, "data-cp-name": "FolderRow", className: clsx("flex h-9 touch:min-h-10 min-w-0 flex-1 items-center gap-2 rounded-lg pr-2 text-left text-sm transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary-400", indentClassName, active
14
14
  ? "bg-primary-25 font-semibold text-primary-500"
15
15
  : "text-gray-900 hover:bg-gray-5"), children: [_jsx(StrokeIcon, { name: iconName, size: 18, className: iconClassName }), _jsx("span", { className: "min-w-0 flex-1 truncate", children: label }), _jsx(FolderCount, { count: count, highlighted: highlighted })] }));
16
16
  export default FolderRow;
@@ -1 +1 @@
1
- {"version":3,"file":"ManualAssignPopover.d.ts","sourceRoot":"","sources":["../../../src/components/thread/ManualAssignPopover.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAY,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAIjD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,MAAM,CAAC;AAkBzC,UAAU,aAAa;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,EAAE,EAAE,MAAM,CAAC;CACZ;AAED,UAAU,wBAAwB;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,aAAa,GAAG,IAAI,CAAC;IACjC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,SAAS,CAAC,EAAE,YAAY,CAAC,WAAW,CAAC,CAAC;CACvC;AA0ED,QAAA,MAAM,mBAAmB,GAAI,wFAO1B,wBAAwB,4CA2O1B,CAAC;AAEF,eAAe,mBAAmB,CAAC"}
1
+ {"version":3,"file":"ManualAssignPopover.d.ts","sourceRoot":"","sources":["../../../src/components/thread/ManualAssignPopover.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAY,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAIjD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,MAAM,CAAC;AAsBzC,UAAU,aAAa;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,EAAE,EAAE,MAAM,CAAC;CACZ;AAED,UAAU,wBAAwB;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,aAAa,GAAG,IAAI,CAAC;IACjC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,SAAS,CAAC,EAAE,YAAY,CAAC,WAAW,CAAC,CAAC;CACvC;AA0ED,QAAA,MAAM,mBAAmB,GAAI,wFAO1B,wBAAwB,4CA+P1B,CAAC;AAEF,eAAe,mBAAmB,CAAC"}
@@ -13,12 +13,16 @@ import AssignConfirmModal from "./AssignConfirmModal";
13
13
  import { useDebounce } from "ahooks";
14
14
  import useAuthStore from "../../store/auth";
15
15
  import TintedAvatar from "../../components/common/TintedAvatar";
16
+ import BottomSheet from "../../components/common/BottomSheet";
17
+ import { useViewportTier } from "../../hooks/common/useViewportTier";
18
+ import { useMediaQuery } from "../../hooks/common/useMediaQuery";
19
+ import { LAYOUT_MEDIA } from "../../constants/layout";
16
20
  const SEARCH_DEBOUNCE_WAIT = 300;
17
21
  const SupporterItem = ({ supporter, onClick, isCurrentUser, }) => {
18
22
  var _a;
19
23
  const { t } = useTranslation();
20
24
  const isOnline = supporter.status === "ONLINE";
21
- return (_jsxs("div", { role: "option", "aria-selected": false, tabIndex: 0, className: "flex items-center gap-3 px-3 py-2 rounded-lg transition-colors cursor-pointer hover:bg-gray-5 focus-visible:outline focus-visible:outline-2 focus-visible:outline-primary-200", onClick: () => onClick(supporter), onKeyDown: (e) => {
25
+ return (_jsxs("div", { role: "option", "aria-selected": false, tabIndex: 0, className: "flex items-center gap-3 px-3 py-2 rounded-lg transition-colors cursor-pointer hover:bg-gray-5 touch:min-h-12 focus-visible:outline focus-visible:outline-2 focus-visible:outline-primary-200", onClick: () => onClick(supporter), onKeyDown: (e) => {
22
26
  if (e.key === "Enter" || e.key === " ") {
23
27
  e.preventDefault();
24
28
  onClick(supporter);
@@ -96,6 +100,8 @@ const ManualAssignPopover = ({ sessionId, supporter, teamId: propTeamId, childre
96
100
  const handleAfterClose = () => {
97
101
  setSelectedAgent(null);
98
102
  };
103
+ const isPhone = useViewportTier() === "phone";
104
+ const isTouch = useMediaQuery(LAYOUT_MEDIA.touch);
99
105
  const handleOpenChange = (newOpen) => {
100
106
  if (isSubmitting)
101
107
  return;
@@ -104,9 +110,9 @@ const ManualAssignPopover = ({ sessionId, supporter, teamId: propTeamId, childre
104
110
  setSearchText("");
105
111
  }
106
112
  };
107
- const popoverContent = (_jsxs("div", { className: "w-64", children: [_jsxs("button", { type: "button", className: clsx("flex w-full items-center gap-3 rounded-lg px-3 py-2 text-left text-sm transition-colors", isAutoAssignDisabled
113
+ const popoverContent = (_jsxs("div", { className: isPhone ? "w-full" : "w-64", children: [_jsxs("button", { type: "button", className: clsx("flex w-full items-center gap-3 rounded-lg px-3 py-2 text-left text-sm transition-colors", isAutoAssignDisabled
108
114
  ? "cursor-not-allowed text-gray-400"
109
- : "text-gray-900 hover:bg-gray-5"), onClick: handleAutoAssign, disabled: isAutoAssignDisabled, children: [isAutoAssigning ? (_jsx(Spin, { size: "small" })) : (_jsx("span", { className: "text-primary-400", children: _jsx(AdaptiveIcon, { stroke: "refresh-cw", font: "refresh-b", size: 20, strokeSize: 18 }) })), _jsx("span", { children: t("manual_assign_button_auto_reassign") })] }), _jsx(Divider, { className: "my-2" }), _jsx("div", { className: "mb-2", children: _jsx(Input, { autoFocus: true, placeholder: t("manual_assign_search_placeholder"), value: searchText, onChange: (e) => setSearchText(e.target.value), prefix: _jsx(AdaptiveIcon, { stroke: "search", font: "search-o", size: 16, className: "text-gray-400" }), className: "rounded-lg border-gray-300 focus-within:border-chat-focus focus-within:shadow-chat-focus-ring", allowClear: true }) }), _jsx("div", { className: "max-h-72 overflow-y-auto", role: "listbox", children: isLoading ? (_jsx("div", { className: "flex items-center justify-center py-8", children: _jsx(Spin, {}) })) : supporters && supporters.length > 0 ? (_jsx("div", { className: clsx("flex flex-col transition-opacity duration-200", isFetching && "opacity-50 pointer-events-none"), children: [...supporters]
115
+ : "text-gray-900 hover:bg-gray-5"), onClick: handleAutoAssign, disabled: isAutoAssignDisabled, children: [isAutoAssigning ? (_jsx(Spin, { size: "small" })) : (_jsx("span", { className: "text-primary-400", children: _jsx(AdaptiveIcon, { stroke: "refresh-cw", font: "refresh-b", size: 20, strokeSize: 18 }) })), _jsx("span", { children: t("manual_assign_button_auto_reassign") })] }), _jsx(Divider, { className: "my-2" }), _jsx("div", { className: "mb-2", children: _jsx(Input, { autoFocus: !isTouch, placeholder: t("manual_assign_search_placeholder"), value: searchText, onChange: (e) => setSearchText(e.target.value), prefix: _jsx(AdaptiveIcon, { stroke: "search", font: "search-o", size: 16, className: "text-gray-400" }), className: "rounded-lg border-gray-300 focus-within:border-chat-focus focus-within:shadow-chat-focus-ring", allowClear: true }) }), _jsx("div", { className: "max-h-72 overflow-y-auto", role: "listbox", children: isLoading ? (_jsx("div", { className: "flex items-center justify-center py-8", children: _jsx(Spin, {}) })) : supporters && supporters.length > 0 ? (_jsx("div", { className: clsx("flex flex-col transition-opacity duration-200", isFetching && "opacity-50 pointer-events-none"), children: [...supporters]
110
116
  .filter((item) => item.memberId !== (supporter === null || supporter === void 0 ? void 0 : supporter.id))
111
117
  .filter((item) => !excludeCurrentUser || item.memberId !== authUserID)
112
118
  .sort((supporterA, supporterB) => {
@@ -120,8 +126,9 @@ const ManualAssignPopover = ({ sessionId, supporter, teamId: propTeamId, childre
120
126
  });
121
127
  })
122
128
  .map((item) => (_jsx(SupporterItem, { supporter: item, onClick: handleSelectAgent, isCurrentUser: item.memberId === authUserID }, item.memberId))) })) : (_jsx("div", { className: "flex items-center justify-center py-8", children: _jsx("span", { className: "text-sm text-gray-400", children: t("manual_assign_no_results") }) })) })] }));
123
- return (_jsxs(_Fragment, { children: [_jsx(Popover, { content: popoverContent, trigger: "click", open: open, onOpenChange: handleOpenChange, placement: placement, arrow: false, children: children !== null && children !== void 0 ? children : (_jsxs("button", { type: "button", "aria-label": t("manual_assign_button_reassign"), className: clsx("flex items-center border border-gray-200 rounded-lg p-1 gap-1 bg-transparent transition-opacity focus-visible:outline focus-visible:outline-2 focus-visible:outline-primary-200", isSubmitting
124
- ? "opacity-50 pointer-events-none"
125
- : "cursor-pointer hover:opacity-80"), children: [_jsx(TintedAvatar, { name: (_a = supporter === null || supporter === void 0 ? void 0 : supporter.fullName) !== null && _a !== void 0 ? _a : "", src: supporter === null || supporter === void 0 ? void 0 : supporter.avatar, size: 28 }), _jsx("span", { className: "text-primary-400", children: _jsx(AdaptiveIcon, { stroke: "shuffle", font: "shuffle-b", size: 20, strokeSize: 18 }) })] })) }), _jsx(AssignConfirmModal, { open: confirmModalOpen, agent: selectedAgent, loading: isAssigning, onCancel: handleCancelConfirm, onConfirm: handleConfirmAssign, afterClose: handleAfterClose })] }));
129
+ const triggerNode = children !== null && children !== void 0 ? children : (_jsxs("button", { type: "button", "aria-label": t("manual_assign_button_reassign"), className: clsx("flex items-center border border-gray-200 rounded-lg p-1 gap-1 bg-transparent transition-opacity focus-visible:outline focus-visible:outline-2 focus-visible:outline-primary-200", isSubmitting
130
+ ? "opacity-50 pointer-events-none"
131
+ : "cursor-pointer hover:opacity-80"), children: [_jsx(TintedAvatar, { name: (_a = supporter === null || supporter === void 0 ? void 0 : supporter.fullName) !== null && _a !== void 0 ? _a : "", src: supporter === null || supporter === void 0 ? void 0 : supporter.avatar, size: 28 }), _jsx("span", { className: "text-primary-400", children: _jsx(AdaptiveIcon, { stroke: "shuffle", font: "shuffle-b", size: 20, strokeSize: 18 }) })] }));
132
+ return (_jsxs(_Fragment, { children: [isPhone ? (_jsxs(_Fragment, { children: [_jsx("span", { className: "contents", onClick: () => handleOpenChange(true), children: triggerNode }), _jsx(BottomSheet, { open: open, title: t("manual_assign_button_reassign"), onClose: () => handleOpenChange(false), children: popoverContent })] })) : (_jsx(Popover, { content: popoverContent, trigger: "click", open: open, onOpenChange: handleOpenChange, placement: placement, arrow: false, children: triggerNode })), _jsx(AssignConfirmModal, { open: confirmModalOpen, agent: selectedAgent, loading: isAssigning, onCancel: handleCancelConfirm, onConfirm: handleConfirmAssign, afterClose: handleAfterClose })] }));
126
133
  };
127
134
  export default ManualAssignPopover;
@@ -99,5 +99,5 @@ export const SessionDetailCard = ({ session, isActive, }) => {
99
99
  time: formatSessionTime(session.createdDate),
100
100
  })
101
101
  : formatSessionDate(session.closedDate || session.createdDate) }), _jsx("span", { className: "flex-1" }), isActive ? (_jsx("span", { className: "inline-flex h-[22px] items-center rounded-full bg-success-25 px-2 text-xs font-medium text-success-900", children: t("session_active") })) : (_jsx(TintedAvatar, { name: ((_a = session.supporter) === null || _a === void 0 ? void 0 : _a.fullName) || "A", src: (_b = session.supporter) === null || _b === void 0 ? void 0 : _b.avatar, size: 24 }))] }), _jsxs("div", { className: "flex flex-col gap-1", children: [_jsx("label", { htmlFor: `${ids}-tags`, className: fieldLabelClass, children: t("session_tags_label") }), _jsx(SessionTagPicker, { labelId: `${ids}-tags`, available: availableLabels !== null && availableLabels !== void 0 ? availableLabels : [], selectedIds: (_d = (_c = session.labels) === null || _c === void 0 ? void 0 : _c.map((label) => label.id)) !== null && _d !== void 0 ? _d : [], loading: isLoadingLabels, onChange: handleUpdateLabels })] }), _jsxs("div", { className: "flex flex-col gap-1", children: [_jsx("label", { htmlFor: `${ids}-issue`, className: fieldLabelClass, children: t("session_issue_detail_label") }), _jsx(TextArea, { id: `${ids}-issue`, value: issueDetail.value, onChange: (e) => issueDetail.setValue(e.target.value), placeholder: t("session_issue_detail_placeholder"), className: `${fieldClass} !min-h-9`, autoSize: { minRows: 1, maxRows: 3 } })] }), _jsxs("div", { className: "flex flex-col gap-1", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsx("label", { htmlFor: `${ids}-note`, className: fieldLabelClass, children: t("session_note_label") }), _jsx(SaveStatus, { status: saveStatus, onRetry: retrySave })] }), _jsx(TextArea, { id: `${ids}-note`, value: note.value, onChange: (e) => note.setValue(e.target.value), placeholder: t("session_note_placeholder"), className: fieldClass, autoSize: { minRows: 2, maxRows: 4 } })] }), isActive && (_jsxs(_Fragment, { children: [session.status !== SessionStatus.UNASSIGNED &&
102
- ((_e = session.supporter) === null || _e === void 0 ? void 0 : _e.id) && (_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(TintedAvatar, { name: session.supporter.fullName || "A", src: session.supporter.avatar, size: 28 }), _jsxs("span", { className: "flex min-w-0 flex-1 flex-col", children: [_jsx("span", { className: "text-xs text-gray-600", children: t("session_owner_label") }), _jsx("span", { className: "truncate text-[13px] font-medium text-gray-900", children: session.supporter.fullName })] }), _jsx(ManualAssignPopover, { sessionId: session.id, supporter: session.supporter, teamId: session.teamId, placement: "topRight", children: _jsx(Button, { icon: _jsx(StrokeIcon, { name: "shuffle", size: 18 }), className: "!h-8 !rounded-lg !px-3.5 !text-[13px] !font-medium", children: t("manual_assign_button_reassign") }) })] })), _jsx(Button, { block: true, icon: _jsx(StrokeIcon, { name: "check-circle", size: 18 }), onClick: () => setIsEndConfirmOpen(true), disabled: isEnding, children: isEnding ? t("end_session_ending") : t("session_close_button") }), _jsx(EndSessionConfirm, { open: isEndConfirmOpen, session: session, customerName: customerName, onConfirm: handleConfirmEnd, onCancel: () => setIsEndConfirmOpen(false) })] }))] }));
102
+ ((_e = session.supporter) === null || _e === void 0 ? void 0 : _e.id) && (_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(TintedAvatar, { name: session.supporter.fullName || "A", src: session.supporter.avatar, size: 28 }), _jsxs("span", { className: "flex min-w-0 flex-1 flex-col", children: [_jsx("span", { className: "text-xs text-gray-600", children: t("session_owner_label") }), _jsx("span", { className: "truncate text-[13px] font-medium text-gray-900", children: session.supporter.fullName })] }), _jsx(ManualAssignPopover, { sessionId: session.id, supporter: session.supporter, teamId: session.teamId, placement: "topRight", children: _jsx(Button, { icon: _jsx(StrokeIcon, { name: "shuffle", size: 18 }), className: "!h-8 touch:!h-10 !rounded-lg !px-3.5 !text-[13px] !font-medium", children: t("manual_assign_button_reassign") }) })] })), _jsx(Button, { block: true, icon: _jsx(StrokeIcon, { name: "check-circle", size: 18 }), onClick: () => setIsEndConfirmOpen(true), disabled: isEnding, children: isEnding ? t("end_session_ending") : t("session_close_button") }), _jsx(EndSessionConfirm, { open: isEndConfirmOpen, session: session, customerName: customerName, onConfirm: handleConfirmEnd, onCancel: () => setIsEndConfirmOpen(false) })] }))] }));
103
103
  };
@@ -19,7 +19,7 @@ const SessionTagPicker = ({ labelId, available, selectedIds, loading, onChange,
19
19
  event.stopPropagation();
20
20
  setOpen(false);
21
21
  }
22
- }, children: [_jsxs("div", { className: "flex min-h-9 flex-wrap items-center gap-1 rounded-lg border border-gray-50 px-1.5 py-1", children: [selected.map((label) => (_jsxs("span", { className: chipClass, children: [label.name, _jsx("button", { type: "button", "aria-label": t("session_remove_tag", { name: label.name }), className: "flex h-4 w-4 items-center justify-center rounded-full text-gray-600 hover:bg-gray-50", onClick: () => toggle(label.id), children: _jsx(StrokeIcon, { name: "x", size: 12 }) })] }, label.id))), _jsxs("button", { id: labelId, type: "button", "aria-label": t("session_add_tag"), "aria-expanded": open, "aria-controls": listId, className: "flex h-6 items-center gap-1 rounded px-1 text-[13px] text-gray-600 hover:text-gray-900", onClick: () => setOpen((value) => !value), children: [_jsx(StrokeIcon, { name: "plus", size: 14 }), t("session_add_tag")] })] }), open && (_jsxs("ul", { id: listId, role: "listbox", "aria-multiselectable": true, "aria-labelledby": labelId, className: "mt-1 max-h-40 overflow-y-auto rounded-lg border border-gray-50 p-1", children: [loading && (_jsx("li", { className: "flex justify-center py-2", children: _jsx(Spin, { size: "small" }) })), !loading && available.length === 0 && (_jsx("li", { className: "px-2 py-1.5 text-[13px] text-gray-600", children: t("session_no_tags") })), available.map((label) => {
22
+ }, children: [_jsxs("div", { className: "flex min-h-9 flex-wrap items-center gap-1 rounded-lg border border-gray-50 px-1.5 py-1", children: [selected.map((label) => (_jsxs("span", { className: chipClass, children: [label.name, _jsx("button", { type: "button", "aria-label": t("session_remove_tag", { name: label.name }), className: "flex h-4 w-4 items-center justify-center rounded-full text-gray-600 hover:bg-gray-50", onClick: () => toggle(label.id), children: _jsx(StrokeIcon, { name: "x", size: 12 }) })] }, label.id))), _jsxs("button", { id: labelId, type: "button", "aria-label": t("session_add_tag"), "aria-expanded": open, "aria-controls": listId, className: "flex h-6 touch:-my-2 touch:min-h-10 items-center gap-1 rounded px-1 text-[13px] text-gray-600 hover:text-gray-900", onClick: () => setOpen((value) => !value), children: [_jsx(StrokeIcon, { name: "plus", size: 14 }), t("session_add_tag")] })] }), open && (_jsxs("ul", { id: listId, role: "listbox", "aria-multiselectable": true, "aria-labelledby": labelId, className: "mt-1 max-h-40 overflow-y-auto rounded-lg border border-gray-50 p-1", children: [loading && (_jsx("li", { className: "flex justify-center py-2", children: _jsx(Spin, { size: "small" }) })), !loading && available.length === 0 && (_jsx("li", { className: "px-2 py-1.5 text-[13px] text-gray-600", children: t("session_no_tags") })), available.map((label) => {
23
23
  const isSelected = selectedIds.includes(label.id);
24
24
  return (_jsx("li", { role: "option", "aria-selected": isSelected, children: _jsxs("button", { type: "button", className: `flex h-8 w-full items-center justify-between rounded px-2 text-left text-[13px] text-gray-900 hover:bg-gray-5 ${isSelected ? "bg-primary-25" : ""}`, onClick: () => toggle(label.id), children: [label.name, isSelected && _jsx(StrokeIcon, { name: "check", size: 14 })] }) }, label.id));
25
25
  })] }))] }));
@@ -1,6 +1,6 @@
1
1
  interface SupportSessionPanelProps {
2
2
  conversationId: string;
3
- width: number;
3
+ width: number | string;
4
4
  /** Drawer variant only: "Thông tin" over this panel, opened from its ⓘ button. */
5
5
  isDetailsOpen?: boolean;
6
6
  onCloseDetails?: () => void;
@@ -1 +1 @@
1
- {"version":3,"file":"SupportSessionPanel.d.ts","sourceRoot":"","sources":["../../../src/components/thread/SupportSessionPanel.tsx"],"names":[],"mappings":"AAeA,UAAU,wBAAwB;IAChC,cAAc,EAAE,MAAM,CAAC;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,kFAAkF;IAClF,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,cAAc,CAAC,EAAE,MAAM,IAAI,CAAC;IAC5B,sFAAsF;IACtF,OAAO,EAAE,QAAQ,GAAG,QAAQ,CAAC;IAC7B,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,IAAI,CAAC;CAC5B;AAED;;;GAGG;AACH,QAAA,MAAM,mBAAmB,GAAI,4FAQ1B,wBAAwB,4CAgG1B,CAAC;AAEF,eAAe,mBAAmB,CAAC"}
1
+ {"version":3,"file":"SupportSessionPanel.d.ts","sourceRoot":"","sources":["../../../src/components/thread/SupportSessionPanel.tsx"],"names":[],"mappings":"AAeA,UAAU,wBAAwB;IAChC,cAAc,EAAE,MAAM,CAAC;IACvB,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC;IACvB,kFAAkF;IAClF,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,cAAc,CAAC,EAAE,MAAM,IAAI,CAAC;IAC5B,sFAAsF;IACtF,OAAO,EAAE,QAAQ,GAAG,QAAQ,CAAC;IAC7B,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,IAAI,CAAC;CAC5B;AAED;;;GAGG;AACH,QAAA,MAAM,mBAAmB,GAAI,4FAQ1B,wBAAwB,4CAgG1B,CAAC;AAEF,eAAe,mBAAmB,CAAC"}
@@ -41,6 +41,6 @@ const SupportSessionPanel = ({ conversationId, width, isDetailsOpen = false, onC
41
41
  (_a = detailsButtonRef.current) === null || _a === void 0 ? void 0 : _a.focus();
42
42
  wasDetailsOpen.current = isDetailsOpen;
43
43
  }, [isDetailsOpen]);
44
- return (_jsxs("div", { ref: setPanelEl, className: "relative flex h-full shrink-0 flex-col overflow-hidden rounded-xl bg-white shadow-sm", style: { width }, "data-cp-name": "SupportSessionPanel", "data-testid": "session-info-column", children: [variant === "drawer" ? (_jsx(ThreadInfoHeader, { title: t("support_session_panel_title"), onClose: onClose, actions: _jsx("button", { ref: detailsButtonRef, type: "button", "aria-label": t("thread_info_open"), title: t("thread_info_open"), "aria-expanded": isDetailsOpen, onClick: onOpenDetails, className: threadInfoIconButtonClass, children: _jsx(StrokeIcon, { name: "info", size: 18 }) }) })) : (_jsx("div", { className: "flex h-14 shrink-0 items-center border-b border-gray-25 px-4", children: _jsx("h2", { className: "m-0 truncate text-base font-bold text-gray-900", children: t("support_session_panel_title") }) })), _jsxs("div", { className: "min-h-0 flex-1 overflow-y-auto", children: [_jsx(UserSection, {}), _jsx(SessionSection, { sessions: closedSessions, isLoading: isLoading })] }), activeSession && (_jsx("div", { className: "max-h-[70%] shrink-0 overflow-y-auto border-t border-gray-25 bg-white p-4", "data-testid": "active-session-dock", children: _jsx(SessionDetailCard, { session: activeSession, isActive: true }, activeSession.id) })), variant === "drawer" && panelEl && (_jsx(Drawer, { open: isDetailsOpen, onClose: onCloseDetails, "aria-label": t("thread_info_title"), getContainer: panelEl, rootStyle: { position: "absolute" }, width: "100%", mask: false, closeIcon: false, destroyOnHidden: true, styles: { body: { padding: 0 }, wrapper: { boxShadow: "none" } }, children: _jsx("div", { className: "h-full", "data-testid": "thread-details-overlay", children: _jsx(SingleThreadInfo, { onClose: onCloseDetails }) }) }))] }));
44
+ return (_jsxs("div", { ref: setPanelEl, className: "relative flex h-full shrink-0 flex-col overflow-hidden rounded-xl bg-white shadow-sm phone:rounded-none phone:shadow-none", style: { width }, "data-cp-name": "SupportSessionPanel", "data-testid": "session-info-column", children: [variant === "drawer" ? (_jsx(ThreadInfoHeader, { title: t("support_session_panel_title"), onClose: onClose, actions: _jsx("button", { ref: detailsButtonRef, type: "button", "aria-label": t("thread_info_open"), title: t("thread_info_open"), "aria-expanded": isDetailsOpen, onClick: onOpenDetails, className: threadInfoIconButtonClass, children: _jsx(StrokeIcon, { name: "info", size: 18 }) }) })) : (_jsx("div", { className: "flex h-14 shrink-0 items-center border-b border-gray-25 px-4", children: _jsx("h2", { className: "m-0 truncate text-base font-bold text-gray-900", children: t("support_session_panel_title") }) })), _jsxs("div", { className: "min-h-0 flex-1 overflow-y-auto", children: [_jsx(UserSection, {}), _jsx(SessionSection, { sessions: closedSessions, isLoading: isLoading })] }), activeSession && (_jsx("div", { className: "max-h-[70%] shrink-0 overflow-y-auto border-t border-gray-25 bg-white p-4", "data-testid": "active-session-dock", children: _jsx(SessionDetailCard, { session: activeSession, isActive: true }, activeSession.id) })), variant === "drawer" && panelEl && (_jsx(Drawer, { open: isDetailsOpen, onClose: onCloseDetails, "aria-label": t("thread_info_title"), getContainer: panelEl, rootStyle: { position: "absolute" }, width: "100%", mask: false, closeIcon: false, destroyOnHidden: true, styles: { body: { padding: 0 }, wrapper: { boxShadow: "none" } }, children: _jsx("div", { className: "h-full", "data-testid": "thread-details-overlay", children: _jsx(SingleThreadInfo, { onClose: onCloseDetails }) }) }))] }));
45
45
  };
46
46
  export default SupportSessionPanel;
@@ -1 +1 @@
1
- {"version":3,"file":"ThreadInfo.d.ts","sourceRoot":"","sources":["../../../src/components/thread/ThreadInfo.tsx"],"names":[],"mappings":"AAGA,OAAwB,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AAU3E,MAAM,WAAW,eAAe;IAC9B,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,WAAW,CAAC,EAAE,qBAAqB,CAAC;IACpC,iGAAiG;IACjG,eAAe,CAAC,EAAE,WAAW,GAAG,IAAI,CAAC;IACrC;;;OAGG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAC;CAC9B;AAED,QAAA,MAAM,UAAU,GAAI,wEAMjB,eAAe,mDAuEjB,CAAC;AAEF,eAAe,UAAU,CAAC"}
1
+ {"version":3,"file":"ThreadInfo.d.ts","sourceRoot":"","sources":["../../../src/components/thread/ThreadInfo.tsx"],"names":[],"mappings":"AAGA,OAAwB,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AAW3E,MAAM,WAAW,eAAe;IAC9B,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,WAAW,CAAC,EAAE,qBAAqB,CAAC;IACpC,iGAAiG;IACjG,eAAe,CAAC,EAAE,WAAW,GAAG,IAAI,CAAC;IACrC;;;OAGG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAC;CAC9B;AAED,QAAA,MAAM,UAAU,GAAI,wEAMjB,eAAe,mDAwEjB,CAAC;AAEF,eAAe,UAAU,CAAC"}
@@ -11,12 +11,14 @@ import { isGroupConversation } from "../../utils/imCommon";
11
11
  import { LAYOUT_WIDTHS } from "../../constants/layout";
12
12
  import DeskSidePanel from "../../components/common/DeskSidePanel";
13
13
  import DeskPanelDrawer from "../../components/common/DeskPanelDrawer";
14
+ import useDeskPanelHostStore from "../../store/deskPanelHost";
14
15
  const ThreadInfo = ({ isOpen = true, onClose, groupConfig, drawerContainer, supportPanelInline = true, }) => {
15
16
  const { t } = useTranslation();
16
17
  const conversationData = useConversationStore((state) => state.conversationData);
17
18
  const conversationId = (conversationData === null || conversationData === void 0 ? void 0 : conversationData.conversationID) || "";
18
19
  const isGroup = isGroupConversation(conversationData !== null && conversationData !== void 0 ? conversationData : undefined);
19
20
  const isBot = (conversationData === null || conversationData === void 0 ? void 0 : conversationData.peerType) === PeerType.BOT;
21
+ const isFullScreen = useDeskPanelHostStore((state) => state.isFullScreen);
20
22
  // Narrow screens only: "Thông tin" over the "Phiên hỗ trợ" drawer, opened from inside it.
21
23
  const [isNarrowDetailsOpen, setIsNarrowDetailsOpen] = useState(false);
22
24
  useEffect(() => {
@@ -37,6 +39,6 @@ const ThreadInfo = ({ isOpen = true, onClose, groupConfig, drawerContainer, supp
37
39
  }
38
40
  return (_jsx(DeskPanelDrawer, { open: isOpen, label: t("support_session_panel_title"), onClose: () => onClose === null || onClose === void 0 ? void 0 : onClose(), container: drawerContainer,
39
41
  // Esc closes "Thông tin" first, then the drawer.
40
- keyboard: !isNarrowDetailsOpen, children: _jsx(SupportSessionPanel, { conversationId: conversationId, width: LAYOUT_WIDTHS.infoDrawer, isDetailsOpen: isNarrowDetailsOpen, onCloseDetails: () => setIsNarrowDetailsOpen(false), variant: "drawer", onClose: onClose, onOpenDetails: () => setIsNarrowDetailsOpen(true) }) }));
42
+ keyboard: !isNarrowDetailsOpen, children: _jsx(SupportSessionPanel, { conversationId: conversationId, width: isFullScreen ? "100%" : LAYOUT_WIDTHS.infoDrawer, isDetailsOpen: isNarrowDetailsOpen, onCloseDetails: () => setIsNarrowDetailsOpen(false), variant: "drawer", onClose: onClose, onOpenDetails: () => setIsNarrowDetailsOpen(true) }) }));
41
43
  };
42
44
  export default ThreadInfo;
@@ -6,7 +6,7 @@ interface ThreadInfoHeaderProps {
6
6
  /** Extra icon buttons placed before the close button. */
7
7
  actions?: ReactNode;
8
8
  }
9
- export declare const threadInfoIconButtonClass = "flex h-8 w-8 shrink-0 items-center justify-center rounded-lg text-gray-600 hover:bg-gray-5 focus-visible:outline focus-visible:outline-2 focus-visible:outline-primary-200";
9
+ export declare const threadInfoIconButtonClass = "flex h-8 w-8 touch:min-h-10 touch:min-w-10 shrink-0 items-center justify-center rounded-lg text-gray-600 hover:bg-gray-5 focus-visible:outline focus-visible:outline-2 focus-visible:outline-primary-200";
10
10
  /** 56px title bar shared by the right-hand panels, inline and in the drawer. */
11
11
  declare const ThreadInfoHeader: ({ title, onClose, actions }: ThreadInfoHeaderProps) => import("react/jsx-runtime").JSX.Element;
12
12
  export default ThreadInfoHeader;
@@ -1 +1 @@
1
- {"version":3,"file":"ThreadInfoHeader.d.ts","sourceRoot":"","sources":["../../../src/components/thread/ThreadInfoHeader.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAIlC,UAAU,qBAAqB;IAC7B,+BAA+B;IAC/B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,yDAAyD;IACzD,OAAO,CAAC,EAAE,SAAS,CAAC;CACrB;AAED,eAAO,MAAM,yBAAyB,+KACwI,CAAC;AAE/K,gFAAgF;AAChF,QAAA,MAAM,gBAAgB,GAAI,6BAA6B,qBAAqB,4CAmB3E,CAAC;AAEF,eAAe,gBAAgB,CAAC"}
1
+ {"version":3,"file":"ThreadInfoHeader.d.ts","sourceRoot":"","sources":["../../../src/components/thread/ThreadInfoHeader.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAIlC,UAAU,qBAAqB;IAC7B,+BAA+B;IAC/B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,yDAAyD;IACzD,OAAO,CAAC,EAAE,SAAS,CAAC;CACrB;AAED,eAAO,MAAM,yBAAyB,6MACsK,CAAC;AAE7M,gFAAgF;AAChF,QAAA,MAAM,gBAAgB,GAAI,6BAA6B,qBAAqB,4CAmB3E,CAAC;AAEF,eAAe,gBAAgB,CAAC"}
@@ -2,7 +2,7 @@
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { useTranslation } from "react-i18next";
4
4
  import { StrokeIcon } from "../../components/icon/StrokeIcon";
5
- export const threadInfoIconButtonClass = "flex h-8 w-8 shrink-0 items-center justify-center rounded-lg text-gray-600 hover:bg-gray-5 focus-visible:outline focus-visible:outline-2 focus-visible:outline-primary-200";
5
+ export const threadInfoIconButtonClass = "flex h-8 w-8 touch:min-h-10 touch:min-w-10 shrink-0 items-center justify-center rounded-lg text-gray-600 hover:bg-gray-5 focus-visible:outline focus-visible:outline-2 focus-visible:outline-primary-200";
6
6
  /** 56px title bar shared by the right-hand panels, inline and in the drawer. */
7
7
  const ThreadInfoHeader = ({ title, onClose, actions }) => {
8
8
  const { t } = useTranslation();
@@ -83,12 +83,12 @@ const UserSection = () => {
83
83
  message.success(t("copied_to_clipboard"));
84
84
  };
85
85
  const rowLabelClass = "text-gray-600";
86
- const copyButtonClass = "flex h-6 w-6 shrink-0 items-center justify-center rounded-lg text-gray-600 hover:bg-gray-5";
86
+ const copyButtonClass = "flex h-6 w-6 shrink-0 items-center justify-center rounded-lg text-gray-600 hover:bg-gray-5 touch:-m-2 touch:min-h-10 touch:min-w-10";
87
87
  const fullName = (data === null || data === void 0 ? void 0 : data.fullName) || "";
88
88
  return (_jsxs("div", { className: "flex flex-col gap-4 px-4 py-4", "data-cp-name": "UserSection", children: [_jsxs("div", { className: "flex items-center gap-3", children: [_jsx(TintedAvatar, { name: fullName, src: data === null || data === void 0 ? void 0 : data.avatar, size: 48 }), _jsx("div", { className: "flex min-w-0 flex-col gap-1", children: _jsx("p", { className: "m-0 truncate text-base font-semibold text-gray-900", children: fullName }) })] }), _jsxs("dl", { className: "m-0 grid grid-cols-[112px_minmax(0,1fr)] items-center gap-y-2 text-[13px]", children: [_jsx("dt", { className: rowLabelClass, children: t("user_username_label") }), _jsxs("dd", { className: "m-0 flex min-w-0 items-center gap-1 text-gray-900", children: [_jsx("span", { className: "truncate", children: (data === null || data === void 0 ? void 0 : data.username) || "" }), _jsx("button", { type: "button", className: copyButtonClass, "aria-label": t("user_copy_username"), title: t("user_copy_username"), onClick: () => copyValue((data === null || data === void 0 ? void 0 : data.username) || ""), children: _jsx(StrokeIcon, { name: "copy", size: 14 }) })] }), _jsx("dt", { className: rowLabelClass, children: t("user_id_label") }), _jsxs("dd", { className: "m-0 flex min-w-0 items-center gap-1 text-gray-900", children: [_jsx("span", { className: "truncate", title: (data === null || data === void 0 ? void 0 : data.id) || undefined, children: middleEllipsis((data === null || data === void 0 ? void 0 : data.id) || "") }), _jsx("button", { type: "button", className: copyButtonClass, "aria-label": t("user_copy_id"), title: t("user_copy_id"), onClick: () => copyValue((data === null || data === void 0 ? void 0 : data.id) || ""), children: _jsx(StrokeIcon, { name: "copy", size: 14 }) })] }), _jsx("dt", { className: `${rowLabelClass} self-start`, children: _jsx("label", { htmlFor: "customer-note", children: t("user_note_label") }) }), _jsx("dd", { className: "m-0", children: isEditingNote ? (_jsx("textarea", { id: "customer-note", autoFocus: true, rows: Math.min(Math.max(noteValue.split("\n").length, 2), 6), value: noteValue, placeholder: t("add_note"), className: "w-full resize-none rounded-lg border border-gray-50 px-2.5 py-1.5 text-[13px] text-gray-900 outline-none focus:border-primary-400", onChange: (e) => {
89
89
  const v = e.target.value;
90
90
  setNoteValue(v);
91
91
  scheduleSave(v);
92
- }, onBlur: () => setIsEditingNote(false) })) : (_jsx("button", { id: "customer-note", type: "button", onClick: () => setIsEditingNote(true), className: "m-0 w-full whitespace-pre-wrap break-words border-0 bg-transparent p-0 text-left text-[13px] font-medium leading-5 text-primary-500 hover:underline focus-visible:outline focus-visible:outline-2 focus-visible:outline-primary-200", children: noteValue ? (_jsx("span", { className: "font-normal text-gray-900", children: noteValue })) : (t("add_note")) })) })] })] }));
92
+ }, onBlur: () => setIsEditingNote(false) })) : (_jsx("button", { id: "customer-note", type: "button", onClick: () => setIsEditingNote(true), className: "m-0 w-full whitespace-pre-wrap break-words border-0 bg-transparent p-0 touch:-my-2.5 touch:min-h-10 text-left text-[13px] font-medium leading-5 text-primary-500 hover:underline focus-visible:outline focus-visible:outline-2 focus-visible:outline-primary-200", children: noteValue ? (_jsx("span", { className: "font-normal text-gray-900", children: noteValue })) : (t("add_note")) })) })] })] }));
93
93
  };
94
94
  export default UserSection;
@@ -1,6 +1,8 @@
1
1
  /** Viewport breakpoints (px) for the CRM desk workspace. */
2
2
  export declare const LAYOUT_BREAKPOINTS: {
3
- /** Below this the desk shows a "use a wider screen" notice. */
3
+ /** Phone/tablet boundary (see LAYOUT_MEDIA for the full phone rule). */
4
+ readonly tablet: 768;
5
+ /** From this width the desktop desk layout applies; below it the desk uses the tablet or phone layout. */
4
6
  readonly minWorkspace: 1024;
5
7
  /** From this width the folder panel stays inline; below it, it overlays the list. */
6
8
  readonly folderInline: 1600;
@@ -21,4 +23,11 @@ export declare const LAYOUT_WIDTHS: {
21
23
  readonly infoDrawer: 360;
22
24
  readonly chatMin: 480;
23
25
  };
26
+ /** Media queries behind the viewport tiers; keep in sync with the phone/touch variants in apps/web/tailwind.config.js. */
27
+ export declare const LAYOUT_MEDIA: {
28
+ readonly phone: `not all and (min-width: 768px), (pointer: coarse) and (max-height: 499px) and (max-width: ${number}px)`;
29
+ readonly belowDesktop: "not all and (min-width: 1024px)";
30
+ readonly touch: `(hover: none) and (pointer: coarse) and (max-width: ${number}px)`;
31
+ readonly touchAnyWidth: "(hover: none) and (pointer: coarse)";
32
+ };
24
33
  //# sourceMappingURL=layout.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"layout.d.ts","sourceRoot":"","sources":["../../src/constants/layout.ts"],"names":[],"mappings":"AAAA,4DAA4D;AAC5D,eAAO,MAAM,kBAAkB;IAC7B,+DAA+D;;IAE/D,qFAAqF;;IAErF,mGAAmG;;IAEnG,qFAAqF;;IAErF,kGAAkG;;CAE1F,CAAC;AAEX,+CAA+C;AAC/C,eAAO,MAAM,aAAa;;;;;;;;CAQhB,CAAC"}
1
+ {"version":3,"file":"layout.d.ts","sourceRoot":"","sources":["../../src/constants/layout.ts"],"names":[],"mappings":"AAAA,4DAA4D;AAC5D,eAAO,MAAM,kBAAkB;IAC7B,wEAAwE;;IAExE,0GAA0G;;IAE1G,qFAAqF;;IAErF,mGAAmG;;IAEnG,qFAAqF;;IAErF,kGAAkG;;CAE1F,CAAC;AAEX,+CAA+C;AAC/C,eAAO,MAAM,aAAa;;;;;;;;CAQhB,CAAC;AAEX,0HAA0H;AAC1H,eAAO,MAAM,YAAY;;;;;CAKf,CAAC"}
@@ -1,6 +1,8 @@
1
1
  /** Viewport breakpoints (px) for the CRM desk workspace. */
2
2
  export const LAYOUT_BREAKPOINTS = {
3
- /** Below this the desk shows a "use a wider screen" notice. */
3
+ /** Phone/tablet boundary (see LAYOUT_MEDIA for the full phone rule). */
4
+ tablet: 768,
5
+ /** From this width the desktop desk layout applies; below it the desk uses the tablet or phone layout. */
4
6
  minWorkspace: 1024,
5
7
  /** From this width the folder panel stays inline; below it, it overlays the list. */
6
8
  folderInline: 1600,
@@ -21,3 +23,10 @@ export const LAYOUT_WIDTHS = {
21
23
  infoDrawer: 360,
22
24
  chatMin: 480,
23
25
  };
26
+ /** Media queries behind the viewport tiers; keep in sync with the phone/touch variants in apps/web/tailwind.config.js. */
27
+ export const LAYOUT_MEDIA = {
28
+ phone: `not all and (min-width: ${LAYOUT_BREAKPOINTS.tablet}px), (pointer: coarse) and (max-height: 499px) and (max-width: ${LAYOUT_BREAKPOINTS.minWorkspace - 1}px)`,
29
+ belowDesktop: `not all and (min-width: ${LAYOUT_BREAKPOINTS.minWorkspace}px)`,
30
+ touch: `(hover: none) and (pointer: coarse) and (max-width: ${LAYOUT_BREAKPOINTS.minWorkspace - 1}px)`,
31
+ touchAnyWidth: "(hover: none) and (pointer: coarse)",
32
+ };
@@ -1 +1 @@
1
- {"version":3,"file":"useDeskShortcuts.d.ts","sourceRoot":"","sources":["../../../src/hooks/common/useDeskShortcuts.ts"],"names":[],"mappings":"AAOA,eAAO,MAAM,iBAAiB,2CAAyC,CAAC;AACxE,eAAO,MAAM,oBAAoB,uBAAuB,CAAC;AACzD,eAAO,MAAM,sBAAsB,sCAAoC,CAAC;AAExE,eAAO,MAAM,cAAc,GAAI,QAAQ,WAAW,GAAG,IAAI,YAQxD,CAAC;AA2CF,UAAU,uBAAuB;IAC/B,UAAU,EAAE,MAAM,IAAI,CAAC;CACxB;AAED,8EAA8E;AAC9E,eAAO,MAAM,gBAAgB,GAAI,gBAAgB,uBAAuB,SAsCvE,CAAC"}
1
+ {"version":3,"file":"useDeskShortcuts.d.ts","sourceRoot":"","sources":["../../../src/hooks/common/useDeskShortcuts.ts"],"names":[],"mappings":"AAOA,eAAO,MAAM,iBAAiB,2CAAyC,CAAC;AACxE,eAAO,MAAM,oBAAoB,uBAAuB,CAAC;AACzD,eAAO,MAAM,sBAAsB,sCAAoC,CAAC;AAExE,eAAO,MAAM,cAAc,GAAI,QAAQ,WAAW,GAAG,IAAI,YAQxD,CAAC;AA6CF,UAAU,uBAAuB;IAC/B,UAAU,EAAE,MAAM,IAAI,CAAC;CACxB;AAED,8EAA8E;AAC9E,eAAO,MAAM,gBAAgB,GAAI,gBAAgB,uBAAuB,SAsCvE,CAAC"}
@@ -15,7 +15,9 @@ export const isTypingTarget = (target) => {
15
15
  ["INPUT", "TEXTAREA", "SELECT"].includes(target.tagName) ||
16
16
  target.getAttribute("role") === "textbox");
17
17
  };
18
- const isModalOpen = () => Array.from(document.querySelectorAll(".ant-modal-wrap")).some((el) => el.style.display !== "none");
18
+ // Overlays that mark themselves with the attribute (nav drawer, bottom sheets, offline lock) pause shortcuts.
19
+ const isModalOpen = () => document.querySelector("[data-desk-shortcuts-off]") !== null ||
20
+ Array.from(document.querySelectorAll(".ant-modal-wrap")).some((el) => el.style.display !== "none");
19
21
  /** Moves to the next/previous row in the order the list is rendered (filtered and loaded). */
20
22
  const moveListSelection = (step) => {
21
23
  var _a, _b;
@@ -0,0 +1,3 @@
1
+ /** True while the CRM desk workspace is on screen; hosts use it to switch their own chrome. */
2
+ export declare const useIsDeskWorkspaceMounted: () => boolean;
3
+ //# sourceMappingURL=useIsDeskWorkspaceMounted.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useIsDeskWorkspaceMounted.d.ts","sourceRoot":"","sources":["../../../src/hooks/common/useIsDeskWorkspaceMounted.ts"],"names":[],"mappings":"AAGA,+FAA+F;AAC/F,eAAO,MAAM,yBAAyB,QAAO,OACe,CAAC"}
@@ -0,0 +1,4 @@
1
+ "use client";
2
+ import useDeskPanelHostStore from "../../store/deskPanelHost";
3
+ /** True while the CRM desk workspace is on screen; hosts use it to switch their own chrome. */
4
+ export const useIsDeskWorkspaceMounted = () => useDeskPanelHostStore((state) => state.workspace !== null);
@@ -0,0 +1,4 @@
1
+ export type ViewportTier = "phone" | "tablet" | "desktop";
2
+ /** Desk/shell tier; unmatched or unavailable queries read as desktop so ≥1024 never changes. */
3
+ export declare const useViewportTier: () => ViewportTier;
4
+ //# sourceMappingURL=useViewportTier.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useViewportTier.d.ts","sourceRoot":"","sources":["../../../src/hooks/common/useViewportTier.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,YAAY,GAAG,OAAO,GAAG,QAAQ,GAAG,SAAS,CAAC;AAE1D,gGAAgG;AAChG,eAAO,MAAM,eAAe,QAAO,YAIlC,CAAC"}
@@ -0,0 +1,9 @@
1
+ "use client";
2
+ import { LAYOUT_MEDIA } from "../../constants/layout";
3
+ import { useMediaQuery } from "./useMediaQuery";
4
+ /** Desk/shell tier; unmatched or unavailable queries read as desktop so ≥1024 never changes. */
5
+ export const useViewportTier = () => {
6
+ const isPhone = useMediaQuery(LAYOUT_MEDIA.phone);
7
+ const isBelowDesktop = useMediaQuery(LAYOUT_MEDIA.belowDesktop);
8
+ return isPhone ? "phone" : isBelowDesktop ? "tablet" : "desktop";
9
+ };
@@ -0,0 +1,10 @@
1
+ /** Visible (keyboard-aware) viewport height, set on the desk root. */
2
+ export declare const DESK_HEIGHT_VAR = "--dc-desk-height";
3
+ /** Same height on <html>, for portaled bottom sheets. */
4
+ export declare const VISUAL_HEIGHT_VAR = "--dc-visual-height";
5
+ /**
6
+ * Mirrors `visualViewport.height` into the height vars while `enabled` (resize only).
7
+ * WebKit ignores `interactive-widget`; zoom is cancelled out with `scale`.
8
+ */
9
+ export declare const useVisualViewportHeight: (el: HTMLElement | null, enabled: boolean) => void;
10
+ //# sourceMappingURL=useVisualViewportHeight.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useVisualViewportHeight.d.ts","sourceRoot":"","sources":["../../../src/hooks/common/useVisualViewportHeight.ts"],"names":[],"mappings":"AAGA,sEAAsE;AACtE,eAAO,MAAM,eAAe,qBAAqB,CAAC;AAClD,yDAAyD;AACzD,eAAO,MAAM,iBAAiB,uBAAuB,CAAC;AAEtD;;;GAGG;AACH,eAAO,MAAM,uBAAuB,GAClC,IAAI,WAAW,GAAG,IAAI,EACtB,SAAS,OAAO,SAoBjB,CAAC"}