@droppii-org/chat-sdk 0.1.74 → 0.1.75

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 (42) hide show
  1. package/dist/components/conversation-detail/ConversationDetailInput.d.ts +2 -1
  2. package/dist/components/conversation-detail/ConversationDetailInput.d.ts.map +1 -1
  3. package/dist/components/conversation-detail/ConversationDetailInput.js +2 -2
  4. package/dist/components/conversation-detail/bot/BotMenuSheet.d.ts +11 -0
  5. package/dist/components/conversation-detail/bot/BotMenuSheet.d.ts.map +1 -0
  6. package/dist/components/conversation-detail/bot/BotMenuSheet.js +24 -0
  7. package/dist/components/conversation-detail/bot/BotSuggest.d.ts +3 -1
  8. package/dist/components/conversation-detail/bot/BotSuggest.d.ts.map +1 -1
  9. package/dist/components/conversation-detail/bot/BotSuggest.js +3 -2
  10. package/dist/components/conversation-detail/bot/CsSessionConfirmModal.d.ts +9 -0
  11. package/dist/components/conversation-detail/bot/CsSessionConfirmModal.d.ts.map +1 -0
  12. package/dist/components/conversation-detail/bot/CsSessionConfirmModal.js +12 -0
  13. package/dist/components/conversation-detail/bot/index.d.ts +4 -0
  14. package/dist/components/conversation-detail/bot/index.d.ts.map +1 -1
  15. package/dist/components/conversation-detail/bot/index.js +2 -0
  16. package/dist/components/session/sessionMenuItems.d.ts.map +1 -1
  17. package/dist/components/session/sessionMenuItems.js +1 -0
  18. package/dist/hooks/conversation/useBotFlow.d.ts +7 -1
  19. package/dist/hooks/conversation/useBotFlow.d.ts.map +1 -1
  20. package/dist/hooks/conversation/useBotFlow.js +59 -3
  21. package/dist/hooks/conversation/useBotMainMenu.d.ts +1 -0
  22. package/dist/hooks/conversation/useBotMainMenu.d.ts.map +1 -1
  23. package/dist/hooks/conversation/useBotMainMenu.js +9 -0
  24. package/dist/hooks/conversation/useCloseBotSession.d.ts +2 -0
  25. package/dist/hooks/conversation/useCloseBotSession.d.ts.map +1 -0
  26. package/dist/hooks/conversation/useCloseBotSession.js +13 -0
  27. package/dist/locales/vi/conversation-inbox.json +13 -1
  28. package/dist/screens/conversation-detail/index.d.ts.map +1 -1
  29. package/dist/screens/conversation-detail/index.js +6 -3
  30. package/dist/services/query.d.ts +2 -0
  31. package/dist/services/query.d.ts.map +1 -1
  32. package/dist/services/query.js +2 -0
  33. package/dist/services/routes.d.ts +1 -0
  34. package/dist/services/routes.d.ts.map +1 -1
  35. package/dist/services/routes.js +1 -0
  36. package/dist/styles/global.css +1 -1
  37. package/dist/tsconfig.tsbuildinfo +1 -1
  38. package/dist/types/conversation.d.ts +1 -4
  39. package/dist/types/conversation.d.ts.map +1 -1
  40. package/dist/utils/botFlow.d.ts +6 -3
  41. package/dist/utils/botFlow.d.ts.map +1 -1
  42. package/package.json +1 -1
@@ -4,7 +4,8 @@ export interface ConversationDetailInputProps {
4
4
  onSendMessage?: (text: string) => void;
5
5
  onInputChange?: (value: string) => void;
6
6
  moreOptions?: MoreOptionConfig[];
7
+ onOpenBotMenu?: () => void;
7
8
  }
8
- declare const ConversationDetailInput: ({ placeholder, onSendMessage, onInputChange, moreOptions, }: ConversationDetailInputProps) => import("react/jsx-runtime").JSX.Element;
9
+ declare const ConversationDetailInput: ({ placeholder, onSendMessage, onInputChange, moreOptions, onOpenBotMenu, }: ConversationDetailInputProps) => import("react/jsx-runtime").JSX.Element;
9
10
  export default ConversationDetailInput;
10
11
  //# sourceMappingURL=ConversationDetailInput.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ConversationDetailInput.d.ts","sourceRoot":"","sources":["../../../src/components/conversation-detail/ConversationDetailInput.tsx"],"names":[],"mappings":"AA2BA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAM/D,MAAM,WAAW,4BAA4B;IAC3C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,WAAW,CAAC,EAAE,gBAAgB,EAAE,CAAC;CAClC;AAED,QAAA,MAAM,uBAAuB,GAAI,6DAK9B,4BAA4B,4CAoZ9B,CAAC;AAEF,eAAe,uBAAuB,CAAC"}
1
+ {"version":3,"file":"ConversationDetailInput.d.ts","sourceRoot":"","sources":["../../../src/components/conversation-detail/ConversationDetailInput.tsx"],"names":[],"mappings":"AA2BA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAM/D,MAAM,WAAW,4BAA4B;IAC3C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,WAAW,CAAC,EAAE,gBAAgB,EAAE,CAAC;IACjC,aAAa,CAAC,EAAE,MAAM,IAAI,CAAC;CAC5B;AAED,QAAA,MAAM,uBAAuB,GAAI,4EAM9B,4BAA4B,4CAma9B,CAAC;AAEF,eAAe,uBAAuB,CAAC"}
@@ -21,7 +21,7 @@ import ConversationMoreOptionPanel from "./ConversationMoreOptionPanel";
21
21
  const MAX_LINES = 5;
22
22
  const CONTAINER_MIN_HEIGHT = 48;
23
23
  const FALLBACK_LINE_HEIGHT = 25.6;
24
- const ConversationDetailInput = ({ placeholder, onSendMessage, onInputChange, moreOptions, }) => {
24
+ const ConversationDetailInput = ({ placeholder, onSendMessage, onInputChange, moreOptions, onOpenBotMenu, }) => {
25
25
  const { t } = useTranslation("conversation-inbox");
26
26
  const { t: tCommon } = useTranslation("common");
27
27
  const conversationData = useConversationStore((state) => state.conversationData);
@@ -258,6 +258,6 @@ const ConversationDetailInput = ({ placeholder, onSendMessage, onInputChange, mo
258
258
  };
259
259
  return (_jsxs("div", { ref: containerRef, "data-testid": "conversation-detail-input", className: "flex w-full shrink-0 flex-col bg-chat-bubble-neutral/[0.05]", children: [_jsx("input", { ref: mediaInputRef, type: "file", accept: "image/jpeg,image/png,image/jpg,video/*", multiple: true, className: "hidden", onChange: handleMediaInputChange }), _jsx("input", { ref: documentInputRef, type: "file", accept: ".pdf,.doc,.docx", multiple: true, className: "hidden", onChange: handleDocumentInputChange }), _jsx(ReplyPreviewBar, {}), listUploadFiles.length > 0 && (_jsx(FilePreviewList, { files: listUploadFiles, onRemove: (file) => handleRemoveFile(file.uid), onVideoReady: () => setIsVideoLoading(false) })), showLinkPreview && previewUrl && (_jsx(LinkInputPreview, { url: previewUrl, onRemove: () => setPreviewDismissed(true) })), _jsxs("div", { className: "flex items-end gap-3 px-3 py-2", children: [_jsx("div", { className: "flex shrink-0 items-center", children: _jsx("button", { type: "button", onClick: handleToggleMoreOption, "aria-label": t("thread_detail.more_option.toggle"), "aria-expanded": isMoreOptionOpen, "data-testid": "conversation-detail-more-option-toggle", className: "flex py-3 items-center justify-center rounded-full", children: isMoreOptionOpen ? (_jsx(Icon, { icon: "close-circle-b", size: 24, className: "text-primary-400" })) : (_jsx(Icon, { icon: "plus-circle-o", size: 24, className: "text-gray-900" })) }) }), _jsx("div", { className: clsx("flex min-w-0 flex-1 overflow-hidden rounded-xl border bg-white transition-shadow", isFocused
260
260
  ? "border-primary-200 shadow-primary-focus"
261
- : "border-gray-50"), style: { minHeight: CONTAINER_MIN_HEIGHT }, children: _jsx("div", { className: "flex min-w-0 flex-[1_0_0] items-center gap-2 self-stretch px-3 py-1", children: _jsx("textarea", { ref: textareaRef, value: value, rows: 1, onChange: (event) => handleChange(event.target.value), onFocus: handleFocus, onBlur: handleBlur, onKeyDown: handleKeyDown, placeholder: placeholder !== null && placeholder !== void 0 ? placeholder : t("thread_detail.input_placeholder"), "data-testid": "conversation-detail-message-input", className: "conversation-message-input-scrollbar min-h-0 min-w-0 flex-1 resize-none appearance-none border-0 bg-transparent p-0 text-[16px] leading-[1.6] tracking-[0.16px] text-black outline-none ring-0 placeholder:text-gray-400 focus:border-0 focus:outline-none focus:ring-0" }) }) }), _jsx("div", { className: "flex shrink-0 items-center pb-1", children: _jsx("button", { type: "button", onClick: () => void handleSend(), disabled: !canSend, "data-testid": "conversation-detail-send", className: clsx("flex h-10 w-10 items-center justify-center rounded-full", canSend ? "bg-chat-send" : "bg-chat-send opacity-25"), children: _jsx(Icon, { icon: "send-b", size: 20, className: "text-white" }) }) })] }), isMoreOptionOpen && (_jsx(ConversationMoreOptionPanel, { disabled: !isConversationReady, options: moreOptions, onTriggerMediaInput: () => { var _a; return (_a = mediaInputRef.current) === null || _a === void 0 ? void 0 : _a.click(); }, onTriggerDocumentInput: () => { var _a; return (_a = documentInputRef.current) === null || _a === void 0 ? void 0 : _a.click(); } }))] }));
261
+ : "border-gray-50"), style: { minHeight: CONTAINER_MIN_HEIGHT }, children: _jsxs("div", { className: "flex min-w-0 flex-[1_0_0] items-center gap-2 self-stretch px-3 py-1", children: [onOpenBotMenu && (_jsx("button", { type: "button", onClick: onOpenBotMenu, "aria-label": t("thread_detail.bot.menu.open_menu"), "data-testid": "conversation-detail-open-bot-menu", className: "flex shrink-0 items-center justify-center", children: _jsx(Icon, { icon: "chat-suggest-o", size: 24, className: "text-gray-600" }) })), _jsx("textarea", { ref: textareaRef, value: value, rows: 1, onChange: (event) => handleChange(event.target.value), onFocus: handleFocus, onBlur: handleBlur, onKeyDown: handleKeyDown, placeholder: placeholder !== null && placeholder !== void 0 ? placeholder : t("thread_detail.input_placeholder"), "data-testid": "conversation-detail-message-input", className: "conversation-message-input-scrollbar min-h-0 min-w-0 flex-1 resize-none appearance-none border-0 bg-transparent p-0 text-[16px] leading-[1.6] tracking-[0.16px] text-black outline-none ring-0 placeholder:text-gray-400 focus:border-0 focus:outline-none focus:ring-0" })] }) }), _jsx("div", { className: "flex shrink-0 items-center pb-1", children: _jsx("button", { type: "button", onClick: () => void handleSend(), disabled: !canSend, "data-testid": "conversation-detail-send", className: clsx("flex h-10 w-10 items-center justify-center rounded-full", canSend ? "bg-chat-send" : "bg-chat-send opacity-25"), children: _jsx(Icon, { icon: "send-b", size: 20, className: "text-white" }) }) })] }), isMoreOptionOpen && (_jsx(ConversationMoreOptionPanel, { disabled: !isConversationReady, options: moreOptions, onTriggerMediaInput: () => { var _a; return (_a = mediaInputRef.current) === null || _a === void 0 ? void 0 : _a.click(); }, onTriggerDocumentInput: () => { var _a; return (_a = documentInputRef.current) === null || _a === void 0 ? void 0 : _a.click(); } }))] }));
262
262
  };
263
263
  export default ConversationDetailInput;
@@ -0,0 +1,11 @@
1
+ import type { BotMainMenuItem } from "../../../types/conversation";
2
+ export interface BotMenuSheetProps {
3
+ open: boolean;
4
+ items: BotMainMenuItem[];
5
+ disabled?: boolean;
6
+ onClose: () => void;
7
+ onSelect: (item: BotMainMenuItem) => void;
8
+ }
9
+ declare const BotMenuSheet: ({ open, items, disabled, onClose, onSelect, }: BotMenuSheetProps) => import("react/jsx-runtime").JSX.Element;
10
+ export default BotMenuSheet;
11
+ //# sourceMappingURL=BotMenuSheet.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BotMenuSheet.d.ts","sourceRoot":"","sources":["../../../../src/components/conversation-detail/bot/BotMenuSheet.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAI5D,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,OAAO,CAAC;IACd,KAAK,EAAE,eAAe,EAAE,CAAC;IACzB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,QAAQ,EAAE,CAAC,IAAI,EAAE,eAAe,KAAK,IAAI,CAAC;CAC3C;AAED,QAAA,MAAM,YAAY,GAAI,+CAMnB,iBAAiB,4CAgEnB,CAAC;AAEF,eAAe,YAAY,CAAC"}
@@ -0,0 +1,24 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { Drawer, Button } from "antd";
4
+ import { useTranslation } from "react-i18next";
5
+ import { Icon } from "../../../components/icon";
6
+ import { BOT_DEFAULT_BUTTON_ID } from "../../../constants/botFlow";
7
+ const CHEVRON_SIZE = 20;
8
+ const BotMenuSheet = ({ open, items, disabled, onClose, onSelect, }) => {
9
+ const { t } = useTranslation("conversation-inbox");
10
+ const handleSelect = (item) => {
11
+ if (disabled)
12
+ return;
13
+ onSelect(item);
14
+ onClose();
15
+ };
16
+ return (_jsx(Drawer, { open: open, onClose: onClose, placement: "bottom", closeIcon: false, height: "auto", styles: {
17
+ body: { padding: "16px 16px 32px" },
18
+ mask: { backgroundColor: "rgba(0, 0, 0, 0.8)" },
19
+ content: { background: "transparent", boxShadow: "none" },
20
+ }, getContainer: false, children: _jsxs("div", { className: "flex flex-col overflow-hidden rounded-2xl bg-white", children: [_jsxs("div", { className: "flex items-center gap-4 border-b border-gray-25 px-3 py-4", children: [_jsx("span", { className: "flex-1 text-[18px] font-bold leading-[1.6] text-gray-900", children: t("thread_detail.bot.menu.title") }), _jsx(Button, { type: "text", shape: "default", className: "h-6 w-6 p-0 text-gray-900", onClick: onClose, "aria-label": t("thread_detail.bot.menu.title"), children: _jsx(Icon, { icon: "close-b", size: 24 }) })] }), _jsx("div", { className: "flex flex-col", children: items.map((item) => (_jsxs("button", { type: "button", disabled: disabled, onClick: () => handleSelect(item), className: "flex items-center gap-4 border-b border-gray-25 px-3 py-3 text-left transition-colors last:border-b-0 disabled:cursor-not-allowed disabled:opacity-60", children: [_jsx("span", { className: "flex-1 text-[16px] font-medium leading-[1.6] text-gray-900", children: item.id === BOT_DEFAULT_BUTTON_ID
21
+ ? t("thread_detail.bot.restart")
22
+ : item.label }), _jsx(Icon, { icon: "angle-right-o", size: CHEVRON_SIZE, className: "text-gray-900" })] }, item.id))) })] }) }));
23
+ };
24
+ export default BotMenuSheet;
@@ -1,7 +1,9 @@
1
1
  export interface BotSuggestProps {
2
2
  disabled?: boolean;
3
+ showMenuTrigger?: boolean;
3
4
  onRestart: () => void;
5
+ onOpenMenu: () => void;
4
6
  }
5
- declare const BotSuggest: ({ disabled, onRestart }: BotSuggestProps) => import("react/jsx-runtime").JSX.Element;
7
+ declare const BotSuggest: ({ disabled, showMenuTrigger, onRestart, onOpenMenu, }: BotSuggestProps) => import("react/jsx-runtime").JSX.Element;
6
8
  export default BotSuggest;
7
9
  //# sourceMappingURL=BotSuggest.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"BotSuggest.d.ts","sourceRoot":"","sources":["../../../../src/components/conversation-detail/bot/BotSuggest.tsx"],"names":[],"mappings":"AAQA,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,SAAS,EAAE,MAAM,IAAI,CAAC;CACvB;AAED,QAAA,MAAM,UAAU,GAAI,yBAAyB,eAAe,4CAyB3D,CAAC;AAEF,eAAe,UAAU,CAAC"}
1
+ {"version":3,"file":"BotSuggest.d.ts","sourceRoot":"","sources":["../../../../src/components/conversation-detail/bot/BotSuggest.tsx"],"names":[],"mappings":"AAiCA,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,SAAS,EAAE,MAAM,IAAI,CAAC;IACtB,UAAU,EAAE,MAAM,IAAI,CAAC;CACxB;AAED,QAAA,MAAM,UAAU,GAAI,uDAKjB,eAAe,4CAyBjB,CAAC;AAEF,eAAe,UAAU,CAAC"}
@@ -4,8 +4,9 @@ import clsx from "clsx";
4
4
  import { useTranslation } from "react-i18next";
5
5
  import { Icon } from "../../../components/icon";
6
6
  const CHIP_ICON_SIZE = 14;
7
- const BotSuggest = ({ disabled, onRestart }) => {
7
+ const SuggestChip = ({ disabled, icon, label, testId, onClick }) => (_jsxs("button", { type: "button", disabled: disabled, onClick: onClick, "data-testid": testId, className: clsx("flex h-7 shrink-0 items-center gap-1 rounded-lg bg-gray-25 px-3", "text-[12px] font-[510] leading-[1.6] tracking-[0.12px] text-gray-900 transition-colors", disabled && "cursor-not-allowed opacity-60"), children: [icon && _jsx(Icon, { icon: icon, size: CHIP_ICON_SIZE, className: "text-gray-900" }), _jsx("span", { className: "whitespace-nowrap", children: label })] }));
8
+ const BotSuggest = ({ disabled, showMenuTrigger = true, onRestart, onOpenMenu, }) => {
8
9
  const { t } = useTranslation("conversation-inbox");
9
- return (_jsx("div", { "data-testid": "conversation-bot-suggest", className: "flex w-full items-center gap-2 overflow-x-auto bg-chat-bubble-neutral/[0.05] px-2 pt-2", children: _jsxs("button", { type: "button", disabled: disabled, onClick: onRestart, className: clsx("flex h-7 shrink-0 items-center gap-1 rounded-lg bg-gray-25 px-3", "text-[12px] font-[510] leading-[1.6] tracking-[0.12px] text-gray-900 transition-colors", disabled && "cursor-not-allowed opacity-60"), children: [_jsx(Icon, { icon: "arrow-reload-o", size: CHIP_ICON_SIZE, className: "text-gray-900" }), _jsx("span", { className: "whitespace-nowrap", children: t("thread_detail.bot.restart") })] }) }));
10
+ return (_jsxs("div", { "data-testid": "conversation-bot-suggest", className: "flex w-full items-center gap-2 overflow-x-auto bg-chat-bubble-neutral/[0.05] px-2 pt-2", children: [_jsx(SuggestChip, { disabled: disabled, icon: "arrow-reload-o", label: t("thread_detail.bot.restart"), onClick: onRestart }), showMenuTrigger && (_jsx(SuggestChip, { disabled: disabled, label: t("thread_detail.bot.menu.trigger"), testId: "conversation-bot-suggest-menu-trigger", onClick: onOpenMenu }))] }));
10
11
  };
11
12
  export default BotSuggest;
@@ -0,0 +1,9 @@
1
+ export interface CsSessionConfirmModalProps {
2
+ open: boolean;
3
+ loading: boolean;
4
+ onCancel: () => void;
5
+ onConfirm: () => void;
6
+ }
7
+ declare const CsSessionConfirmModal: ({ open, loading, onCancel, onConfirm, }: CsSessionConfirmModalProps) => import("react/jsx-runtime").JSX.Element;
8
+ export default CsSessionConfirmModal;
9
+ //# sourceMappingURL=CsSessionConfirmModal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CsSessionConfirmModal.d.ts","sourceRoot":"","sources":["../../../../src/components/conversation-detail/bot/CsSessionConfirmModal.tsx"],"names":[],"mappings":"AAKA,MAAM,WAAW,0BAA0B;IACzC,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,SAAS,EAAE,MAAM,IAAI,CAAC;CACvB;AAED,QAAA,MAAM,qBAAqB,GAAI,yCAK5B,0BAA0B,4CA2D5B,CAAC;AAEF,eAAe,qBAAqB,CAAC"}
@@ -0,0 +1,12 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { Modal, Button } from "antd";
4
+ import { Trans, useTranslation } from "react-i18next";
5
+ const CsSessionConfirmModal = ({ open, loading, onCancel, onConfirm, }) => {
6
+ const { t } = useTranslation("conversation-inbox");
7
+ return (_jsx(Modal, { open: open, onCancel: onCancel, footer: null, closable: false, centered: true, forceRender: true, width: 400, maskClosable: !loading, keyboard: !loading, styles: {
8
+ content: { padding: 0, overflow: "hidden" },
9
+ body: { padding: 0 },
10
+ }, children: _jsxs("div", { role: "alertdialog", "aria-label": t("thread_detail.bot.cs_confirm.title"), className: "flex flex-col", children: [_jsx("div", { className: "border-b border-gray-25 p-4", children: _jsx("p", { className: "text-[18px] font-bold leading-[1.6] text-center text-gray-900", children: t("thread_detail.bot.cs_confirm.title") }) }), _jsx("p", { className: "p-4 text-[16px] leading-[1.6] text-gray-900", children: _jsx(Trans, { t: t, i18nKey: "thread_detail.bot.cs_confirm.body", components: { bold: _jsx("strong", { className: "font-bold" }) } }) }), _jsx("div", { className: "border-t border-gray-25" }), _jsxs("div", { className: "flex gap-2 p-4", children: [_jsx(Button, { className: "h-12 flex-1 !rounded-lg !border-gray-25 !bg-gray-25 !text-[16px] !font-medium !text-gray-900", onClick: onCancel, disabled: loading, children: t("thread_detail.bot.cs_confirm.cancel") }), _jsx(Button, { type: "primary", className: "h-12 flex-1 !rounded-lg !border-danger-400 !bg-danger-400 !text-[16px] !font-medium !text-white hover:!border-danger-300 hover:!bg-danger-300", onClick: onConfirm, loading: loading, children: t("thread_detail.bot.cs_confirm.confirm") })] })] }) }));
11
+ };
12
+ export default CsSessionConfirmModal;
@@ -5,4 +5,8 @@ export type { BotButtonMessageProps } from "./BotButtonMessage";
5
5
  export { default as BotSuggest } from "./BotSuggest";
6
6
  export type { BotSuggestProps } from "./BotSuggest";
7
7
  export { default as BotInactiveNotice } from "./BotInactiveNotice";
8
+ export { default as BotMenuSheet } from "./BotMenuSheet";
9
+ export type { BotMenuSheetProps } from "./BotMenuSheet";
10
+ export { default as CsSessionConfirmModal } from "./CsSessionConfirmModal";
11
+ export type { CsSessionConfirmModalProps } from "./CsSessionConfirmModal";
8
12
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/conversation-detail/bot/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAC7D,YAAY,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAE5D,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACjE,YAAY,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAEhE,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,cAAc,CAAC;AACrD,YAAY,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAEpD,OAAO,EAAE,OAAO,IAAI,iBAAiB,EAAE,MAAM,qBAAqB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/conversation-detail/bot/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAC7D,YAAY,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAE5D,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACjE,YAAY,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAEhE,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,cAAc,CAAC;AACrD,YAAY,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAEpD,OAAO,EAAE,OAAO,IAAI,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAEnE,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,gBAAgB,CAAC;AACzD,YAAY,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAExD,OAAO,EAAE,OAAO,IAAI,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAC3E,YAAY,EAAE,0BAA0B,EAAE,MAAM,yBAAyB,CAAC"}
@@ -2,3 +2,5 @@ export { default as BotStartButton } from "./BotStartButton";
2
2
  export { default as BotButtonMessage } from "./BotButtonMessage";
3
3
  export { default as BotSuggest } from "./BotSuggest";
4
4
  export { default as BotInactiveNotice } from "./BotInactiveNotice";
5
+ export { default as BotMenuSheet } from "./BotMenuSheet";
6
+ export { default as CsSessionConfirmModal } from "./CsSessionConfirmModal";
@@ -1 +1 @@
1
- {"version":3,"file":"sessionMenuItems.d.ts","sourceRoot":"","sources":["../../../src/components/session/sessionMenuItems.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,MAAM,CAAC;AACjC,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAGpC,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAC;AAEtD,KAAK,QAAQ,GAAG,QAAQ,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC;AAErD,UAAU,mBAAmB;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,cAAc,CAAC;IACvB,WAAW,EAAE,QAAQ,GAAG,KAAK,CAAC;IAC9B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,eAAO,MAAM,sBAAsB,EAAE,mBAAmB,EA0DvD,CAAC;AAEF,eAAO,MAAM,eAAe,GAAI,KAAK,MAAM,oCACQ,CAAC;AAEpD,UAAU,4BAA4B;IACpC,OAAO,EAAE,uBAAuB,CAAC;IACjC,CAAC,EAAE,SAAS,CAAC;IACb,cAAc,EAAE,CAAC,MAAM,EAAE,cAAc,KAAK,IAAI,CAAC;IACjD,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B;AA0BD,eAAO,MAAM,qBAAqB,GAAI,oDAKnC,4BAA4B,KAAG,QAAQ,EA4CzC,CAAC"}
1
+ {"version":3,"file":"sessionMenuItems.d.ts","sourceRoot":"","sources":["../../../src/components/session/sessionMenuItems.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,MAAM,CAAC;AACjC,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAGpC,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAC;AAEtD,KAAK,QAAQ,GAAG,QAAQ,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC;AAErD,UAAU,mBAAmB;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,cAAc,CAAC;IACvB,WAAW,EAAE,QAAQ,GAAG,KAAK,CAAC;IAC9B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,eAAO,MAAM,sBAAsB,EAAE,mBAAmB,EA2DvD,CAAC;AAEF,eAAO,MAAM,eAAe,GAAI,KAAK,MAAM,oCACQ,CAAC;AAEpD,UAAU,4BAA4B;IACpC,OAAO,EAAE,uBAAuB,CAAC;IACjC,CAAC,EAAE,SAAS,CAAC;IACb,cAAc,EAAE,CAAC,MAAM,EAAE,cAAc,KAAK,IAAI,CAAC;IACjD,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B;AA0BD,eAAO,MAAM,qBAAqB,GAAI,oDAKnC,4BAA4B,KAAG,QAAQ,EA4CzC,CAAC"}
@@ -10,6 +10,7 @@ export const SESSION_FILTER_CONFIGS = [
10
10
  filter: { status: SessionStatus.UNASSIGNED, tag: undefined },
11
11
  countSource: "status",
12
12
  teamOnly: true,
13
+ highlighted: true,
13
14
  },
14
15
  {
15
16
  key: SessionTag.SLOW_PROCESSING,
@@ -1,4 +1,4 @@
1
- import { type BotInputButtonsBlock } from "../../types/conversation";
1
+ import { type BotInputButtonsBlock, type BotMainMenuItem } from "../../types/conversation";
2
2
  export type BotFlowStatus = "running" | "not_started";
3
3
  interface UseBotFlowParams {
4
4
  conversationId: string;
@@ -11,9 +11,15 @@ export declare const useBotFlow: ({ conversationId, isBotThread, }: UseBotFlowPa
11
11
  isProcessing: boolean;
12
12
  shouldShowButtons: boolean;
13
13
  currentButtonsBlock: BotInputButtonsBlock | null;
14
+ menuItems: import("../../types/conversation").BotButtonOption[];
15
+ isInCsSession: boolean;
16
+ pendingMenuOption: import("../../types/conversation").BotButtonOption | null;
14
17
  start: () => Promise<void>;
15
18
  selectButton: (actionId: string) => Promise<void>;
16
19
  restart: () => Promise<void>;
20
+ selectMenuOption: (item: BotMainMenuItem) => Promise<void>;
21
+ confirmEndCsSession: () => Promise<void>;
22
+ cancelMenuOption: () => void;
17
23
  };
18
24
  export {};
19
25
  //# sourceMappingURL=useBotFlow.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"useBotFlow.d.ts","sourceRoot":"","sources":["../../../src/hooks/conversation/useBotFlow.ts"],"names":[],"mappings":"AAKA,OAAO,EAKL,KAAK,oBAAoB,EAC1B,MAAM,sBAAsB,CAAC;AAa9B,MAAM,MAAM,aAAa,GAAG,SAAS,GAAG,aAAa,CAAC;AAEtD,UAAU,gBAAgB;IACxB,cAAc,EAAE,MAAM,CAAC;IACvB,WAAW,EAAE,OAAO,CAAC;CACtB;AAsBD,eAAO,MAAM,UAAU,GAAI,kCAGxB,gBAAgB;;;;;;;;6BAmHqB,MAAM;;CAkD7C,CAAC"}
1
+ {"version":3,"file":"useBotFlow.d.ts","sourceRoot":"","sources":["../../../src/hooks/conversation/useBotFlow.ts"],"names":[],"mappings":"AAMA,OAAO,EAKL,KAAK,oBAAoB,EACzB,KAAK,eAAe,EACrB,MAAM,sBAAsB,CAAC;AAgB9B,MAAM,MAAM,aAAa,GAAG,SAAS,GAAG,aAAa,CAAC;AAEtD,UAAU,gBAAgB;IACxB,cAAc,EAAE,MAAM,CAAC;IACvB,WAAW,EAAE,OAAO,CAAC;CACtB;AAsBD,eAAO,MAAM,UAAU,GAAI,kCAGxB,gBAAgB;;;;;;;;;;;6BA+HqB,MAAM;;6BAkDN,eAAe;;;CA8CtD,CAAC"}
@@ -1,6 +1,7 @@
1
1
  "use client";
2
2
  import { useEffect, useRef, useState } from "react";
3
3
  import { useTranslation } from "react-i18next";
4
+ import { message as toastMessage } from "antd";
4
5
  import { BotBlockType, BotFlowNodeType, BotStatus, } from "../../types/conversation";
5
6
  import { BOT_DEFAULT_BUTTON_ID } from "../../constants/botFlow";
6
7
  import { useSendMessage } from "../../hooks/message/useSendMessage";
@@ -8,10 +9,13 @@ import useAuthStore from "../../store/auth";
8
9
  import useConversationStore from "../../store/conversation";
9
10
  import emitter from "../../utils/events";
10
11
  import { resolveConversationBotId } from "../../utils/conversation";
12
+ import { filterVisibleBotButtons, isInCsSession } from "../../utils/botFlow";
11
13
  import { useBotConversationDetail } from "./useBotConversationDetail";
12
14
  import { useBotDetail } from "./useBotDetail";
15
+ import { useBotMainMenu } from "./useBotMainMenu";
13
16
  import { useRunBotFlow } from "./useRunBotFlow";
14
17
  import { useResetBotFlow } from "./useResetBotFlow";
18
+ import { useCloseBotSession } from "./useCloseBotSession";
15
19
  const INITIAL_BOT_FLOW_STATE = {
16
20
  conversationId: "",
17
21
  flowCurrentStep: null,
@@ -27,7 +31,7 @@ const parseMessageFlowGroupId = (ex) => {
27
31
  }
28
32
  };
29
33
  export const useBotFlow = ({ conversationId, isBotThread, }) => {
30
- var _a, _b;
34
+ var _a, _b, _c;
31
35
  const [botFlowState, setBotFlowState] = useState(INITIAL_BOT_FLOW_STATE);
32
36
  const { conversationId: storedConversationId, flowCurrentStep } = botFlowState;
33
37
  const isActiveConversation = storedConversationId === conversationId;
@@ -45,9 +49,13 @@ export const useBotFlow = ({ conversationId, isBotThread, }) => {
45
49
  const isBotInactive = ((_a = botDetailQuery.data) === null || _a === void 0 ? void 0 : _a.status) === BotStatus.INACTIVE;
46
50
  const runMutation = useRunBotFlow();
47
51
  const resetMutation = useResetBotFlow();
52
+ const closeSessionMutation = useCloseBotSession();
48
53
  const { sendMergeMessage } = useSendMessage({
49
54
  scrollEvent: "CONVERSATION_CHAT_SCROLL_TO_BOTTOM_IF_AT_BOTTOM",
50
55
  });
56
+ const [pendingMenuOption, setPendingMenuOption] = useState(null);
57
+ const menuQuery = useBotMainMenu(conversationId, isBotThread);
58
+ const menuItems = filterVisibleBotButtons((_b = menuQuery.data) !== null && _b !== void 0 ? _b : []);
51
59
  useEffect(() => {
52
60
  if (!isBotThread) {
53
61
  setBotFlowState(INITIAL_BOT_FLOW_STATE);
@@ -81,8 +89,11 @@ export const useBotFlow = ({ conversationId, isBotThread, }) => {
81
89
  };
82
90
  }, [authUserID]);
83
91
  const activeStep = storedConversationId === conversationId ? flowCurrentStep : null;
84
- const currentButtonsBlock = (_b = activeStep === null || activeStep === void 0 ? void 0 : activeStep.data.children.find((child) => child.type === BotBlockType.InputButtons)) !== null && _b !== void 0 ? _b : null;
85
- const isProcessing = runMutation.isPending || resetMutation.isPending;
92
+ const currentButtonsBlock = (_c = activeStep === null || activeStep === void 0 ? void 0 : activeStep.data.children.find((child) => child.type === BotBlockType.InputButtons)) !== null && _c !== void 0 ? _c : null;
93
+ const isInActiveCsSession = isInCsSession({ flowCurrentStep: activeStep });
94
+ const isProcessing = runMutation.isPending ||
95
+ resetMutation.isPending ||
96
+ closeSessionMutation.isPending;
86
97
  const shouldShowButtons = !!currentButtonsBlock && !isProcessing && !pendingGroupId;
87
98
  const status = (activeStep === null || activeStep === void 0 ? void 0 : activeStep.type) === BotFlowNodeType.Start ? "not_started" : "running";
88
99
  const runStep = async (step, actionId = null) => {
@@ -146,6 +157,45 @@ export const useBotFlow = ({ conversationId, isBotThread, }) => {
146
157
  const resetDetail = await resetMutation.mutateAsync(conversationId);
147
158
  await runStep(resetDetail.flowCurrentStep);
148
159
  };
160
+ const runMenuOption = async (item) => {
161
+ if (!activeStep)
162
+ return;
163
+ await sendMergeMessage({
164
+ plainText: item.label,
165
+ richText: "",
166
+ isInternal: false,
167
+ flow: { groupId: activeStep.id, childId: null, actionId: item.id },
168
+ });
169
+ await runStep(activeStep, item.id);
170
+ };
171
+ const selectMenuOption = async (item) => {
172
+ if (item.id === BOT_DEFAULT_BUTTON_ID) {
173
+ await restart();
174
+ return;
175
+ }
176
+ if (isInActiveCsSession) {
177
+ setPendingMenuOption(item);
178
+ return;
179
+ }
180
+ await runMenuOption(item);
181
+ };
182
+ const confirmEndCsSession = async () => {
183
+ if (!pendingMenuOption)
184
+ return;
185
+ const option = pendingMenuOption;
186
+ try {
187
+ await closeSessionMutation.mutateAsync(conversationId);
188
+ setPendingMenuOption(null);
189
+ await runMenuOption(option);
190
+ }
191
+ catch (_a) {
192
+ toastMessage.error(t("thread_detail.bot.cs_confirm.close_failed"));
193
+ setPendingMenuOption(null);
194
+ }
195
+ };
196
+ const cancelMenuOption = () => {
197
+ setPendingMenuOption(null);
198
+ };
149
199
  return {
150
200
  status,
151
201
  flowIsEnd,
@@ -153,8 +203,14 @@ export const useBotFlow = ({ conversationId, isBotThread, }) => {
153
203
  isProcessing,
154
204
  shouldShowButtons,
155
205
  currentButtonsBlock,
206
+ menuItems,
207
+ isInCsSession: isInActiveCsSession,
208
+ pendingMenuOption,
156
209
  start,
157
210
  selectButton,
158
211
  restart,
212
+ selectMenuOption,
213
+ confirmEndCsSession,
214
+ cancelMenuOption,
159
215
  };
160
216
  };
@@ -1,3 +1,4 @@
1
1
  import type { BotMainMenuItem } from "../../types/conversation";
2
2
  export declare const fetchBotMainMenu: (conversationId: string) => Promise<BotMainMenuItem[]>;
3
+ export declare const useBotMainMenu: (conversationId: string, enabled: boolean) => import("@tanstack/react-query").UseQueryResult<import("../../types/conversation").BotButtonOption[], Error>;
3
4
  //# sourceMappingURL=useBotMainMenu.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"useBotMainMenu.d.ts","sourceRoot":"","sources":["../../../src/hooks/conversation/useBotMainMenu.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAE5D,eAAO,MAAM,gBAAgB,GAC3B,gBAAgB,MAAM,KACrB,OAAO,CAAC,eAAe,EAAE,CAK3B,CAAC"}
1
+ {"version":3,"file":"useBotMainMenu.d.ts","sourceRoot":"","sources":["../../../src/hooks/conversation/useBotMainMenu.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAE5D,eAAO,MAAM,gBAAgB,GAC3B,gBAAgB,MAAM,KACrB,OAAO,CAAC,eAAe,EAAE,CAK3B,CAAC;AAEF,eAAO,MAAM,cAAc,GAAI,gBAAgB,MAAM,EAAE,SAAS,OAAO,4GAMtE,CAAC"}
@@ -1,6 +1,15 @@
1
+ import { useQuery } from "@tanstack/react-query";
1
2
  import { apiInstance } from "../../services/api";
2
3
  import { ENDPOINTS } from "../../services/routes";
4
+ import { QUERY_KEYS } from "../../services/query";
3
5
  export const fetchBotMainMenu = async (conversationId) => {
4
6
  const res = await apiInstance.get(ENDPOINTS.chatService.getBotMainMenu(conversationId));
5
7
  return res.data.data || [];
6
8
  };
9
+ export const useBotMainMenu = (conversationId, enabled) => {
10
+ return useQuery({
11
+ queryKey: [QUERY_KEYS.GET_BOT_MAIN_MENU, conversationId],
12
+ queryFn: () => fetchBotMainMenu(conversationId),
13
+ enabled: enabled && !!conversationId,
14
+ });
15
+ };
@@ -0,0 +1,2 @@
1
+ export declare const useCloseBotSession: () => import("@tanstack/react-query").UseMutationResult<void, Error, string, unknown>;
2
+ //# sourceMappingURL=useCloseBotSession.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useCloseBotSession.d.ts","sourceRoot":"","sources":["../../../src/hooks/conversation/useCloseBotSession.ts"],"names":[],"mappings":"AAQA,eAAO,MAAM,kBAAkB,uFAS9B,CAAC"}
@@ -0,0 +1,13 @@
1
+ "use client";
2
+ import { useMutation } from "@tanstack/react-query";
3
+ import { apiInstance } from "../../services/api";
4
+ import { ENDPOINTS } from "../../services/routes";
5
+ import { QUERY_KEYS } from "../../services/query";
6
+ export const useCloseBotSession = () => {
7
+ return useMutation({
8
+ mutationKey: [QUERY_KEYS.CLOSE_BOT_SESSION],
9
+ mutationFn: async (conversationId) => {
10
+ await apiInstance.post(ENDPOINTS.chatService.closeBotSession(conversationId));
11
+ },
12
+ });
13
+ };
@@ -30,7 +30,19 @@
30
30
  "bot": {
31
31
  "start": "Bắt đầu",
32
32
  "restart": "Bắt đầu lại",
33
- "inactive_notice": "Người dùng này không còn khả dụng"
33
+ "inactive_notice": "Người dùng này không còn khả dụng",
34
+ "menu": {
35
+ "title": "Gợi ý",
36
+ "trigger": "Gợi ý khác",
37
+ "open_menu": "Xem gợi ý khác"
38
+ },
39
+ "cs_confirm": {
40
+ "title": "Kết thúc phiên hỗ trợ",
41
+ "body": "Bạn đang trong phiên hỗ trợ với hỗ trợ viên, bạn có muốn <bold>kết thúc phiên hỗ trợ</bold> ngay bây giờ?",
42
+ "confirm": "Kết thúc",
43
+ "cancel": "Tiếp tục",
44
+ "close_failed": "Không thể kết thúc phiên hỗ trợ. Vui lòng thử lại."
45
+ }
34
46
  }
35
47
  },
36
48
  "link_preview": {
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/screens/conversation-detail/index.tsx"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,kCAAkC,CAAC;AAQrF,OAAO,EAEL,KAAK,4BAA4B,EAClC,MAAM,6CAA6C,CAAC;AAGrD,MAAM,WAAW,4BACf,SAAQ,4BAA4B,EAClC,4BAA4B;IAC9B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;CACrB;AAED,QAAA,MAAM,uBAAuB,GAAI,wFAS9B,4BAA4B,mDA2G9B,CAAC;AAEF,eAAe,uBAAuB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/screens/conversation-detail/index.tsx"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,kCAAkC,CAAC;AAUrF,OAAO,EAEL,KAAK,4BAA4B,EAClC,MAAM,6CAA6C,CAAC;AAGrD,MAAM,WAAW,4BACf,SAAQ,4BAA4B,EAClC,4BAA4B;IAC9B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;CACrB;AAED,QAAA,MAAM,uBAAuB,GAAI,wFAS9B,4BAA4B,mDAwI9B,CAAC;AAEF,eAAe,uBAAuB,CAAC"}
@@ -13,11 +13,12 @@ var __rest = (this && this.__rest) || function (s, e) {
13
13
  import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
14
14
  import { usePathname, useRouter, useSearchParams } from "next/navigation";
15
15
  import { useTranslation } from "react-i18next";
16
+ import { useBoolean } from "ahooks";
16
17
  import clsx from "clsx";
17
18
  import { Empty, Spin } from "antd";
18
19
  import useConversationStore from "../../store/conversation";
19
20
  import { ConversationMessageList, ConversationDetailHeader, ConversationDetailInput, PinnedMessageBar, } from "../../components/conversation-detail";
20
- import { BotButtonMessage, BotInactiveNotice, BotStartButton, BotSuggest, } from "../../components/conversation-detail/bot";
21
+ import { BotButtonMessage, BotInactiveNotice, BotMenuSheet, BotStartButton, BotSuggest, CsSessionConfirmModal, } from "../../components/conversation-detail/bot";
21
22
  import { useBotFlow } from "../../hooks/conversation/useBotFlow";
22
23
  import { useResolveConversation, } from "../../hooks/conversation/useResolveConversation";
23
24
  import { isBotPeer } from "../../utils/conversation";
@@ -40,6 +41,8 @@ const DChatConversationDetail = (_a) => {
40
41
  conversationId: (_b = conversation === null || conversation === void 0 ? void 0 : conversation.conversationID) !== null && _b !== void 0 ? _b : "",
41
42
  isBotThread,
42
43
  });
44
+ const [isMenuOpen, { setTrue: openMenu, setFalse: closeMenu }] = useBoolean(false);
45
+ const hasMenuItems = botFlow.menuItems.length > 0;
43
46
  const handleBack = () => {
44
47
  const newSearchParams = new URLSearchParams(searchParams);
45
48
  newSearchParams.delete("threadId");
@@ -58,12 +61,12 @@ const DChatConversationDetail = (_a) => {
58
61
  }
59
62
  const isBotInactive = isBotThread && botFlow.isBotInactive;
60
63
  const isBotNotStarted = isBotThread && botFlow.status === "not_started";
61
- const footer = isBotInactive ? (_jsx(BotInactiveNotice, {})) : isBotNotStarted ? (_jsx("div", { className: "bg-white p-6", children: _jsx(BotStartButton, { label: t("thread_detail.bot.start"), onClick: botFlow.start, disabled: botFlow.isProcessing }) })) : (_jsxs(_Fragment, { children: [isBotThread && (_jsx(BotSuggest, { disabled: botFlow.isProcessing, onRestart: botFlow.restart })), _jsx(ConversationDetailInput, Object.assign({}, inputProps))] }));
64
+ const footer = isBotInactive ? (_jsx(BotInactiveNotice, {})) : isBotNotStarted ? (_jsx("div", { className: "bg-white p-6", children: _jsx(BotStartButton, { label: t("thread_detail.bot.start"), onClick: botFlow.start, disabled: botFlow.isProcessing }) })) : (_jsxs(_Fragment, { children: [isBotThread && (_jsx(BotSuggest, { disabled: botFlow.isProcessing, showMenuTrigger: hasMenuItems, onRestart: botFlow.restart, onOpenMenu: openMenu })), _jsx(ConversationDetailInput, Object.assign({}, inputProps, { onOpenBotMenu: isBotThread && hasMenuItems ? openMenu : undefined }))] }));
62
65
  const botButtonsSlot = isBotThread &&
63
66
  !isBotInactive &&
64
67
  !botFlow.flowIsEnd &&
65
68
  botFlow.shouldShowButtons &&
66
69
  botFlow.currentButtonsBlock ? (_jsx(BotButtonMessage, { buttons: botFlow.currentButtonsBlock.data.buttons, disabled: botFlow.isProcessing, onSelect: botFlow.selectButton, onRestart: botFlow.restart })) : null;
67
- return (_jsxs("div", { "data-testid": "conversation-detail-root", className: clsx("relative flex h-full w-full flex-col overflow-hidden bg-white", className), children: [_jsx(ConversationDetailHeader, { conversation: conversation, onBack: handleBack }), _jsx(PinnedMessageBar, {}), _jsx("div", { className: "flex min-h-0 flex-1 flex-col", children: children !== null && children !== void 0 ? children : _jsx(ConversationMessageList, { bottomSlot: botButtonsSlot }) }), footer] }));
70
+ return (_jsxs("div", { "data-testid": "conversation-detail-root", className: clsx("relative flex h-full w-full flex-col overflow-hidden bg-white", className), children: [_jsx(ConversationDetailHeader, { conversation: conversation, onBack: handleBack }), _jsx(PinnedMessageBar, {}), _jsx("div", { className: "flex min-h-0 flex-1 flex-col", children: children !== null && children !== void 0 ? children : _jsx(ConversationMessageList, { bottomSlot: botButtonsSlot }) }), footer, isBotThread && (_jsxs(_Fragment, { children: [_jsx(BotMenuSheet, { open: isMenuOpen, items: botFlow.menuItems, disabled: botFlow.isProcessing, onClose: closeMenu, onSelect: botFlow.selectMenuOption }), _jsx(CsSessionConfirmModal, { open: !!botFlow.pendingMenuOption, loading: botFlow.isProcessing, onCancel: botFlow.cancelMenuOption, onConfirm: botFlow.confirmEndCsSession })] }))] }));
68
71
  };
69
72
  export default DChatConversationDetail;
@@ -28,6 +28,8 @@ export declare const QUERY_KEYS: {
28
28
  GET_CONVERSATION_DETAIL: string;
29
29
  RUN_BOT_FLOW: string;
30
30
  RESET_BOT_FLOW: string;
31
+ CLOSE_BOT_SESSION: string;
32
+ GET_BOT_MAIN_MENU: string;
31
33
  GET_BOT_DETAIL: string;
32
34
  GET_CONVERSATION_BY_BOT_ID: string;
33
35
  LEAVE_CONVERSATION: string;
@@ -1 +1 @@
1
- {"version":3,"file":"query.d.ts","sourceRoot":"","sources":["../../src/services/query.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAoCtB,CAAC"}
1
+ {"version":3,"file":"query.d.ts","sourceRoot":"","sources":["../../src/services/query.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAsCtB,CAAC"}
@@ -28,6 +28,8 @@ export const QUERY_KEYS = {
28
28
  GET_CONVERSATION_DETAIL: "GET_CONVERSATION_DETAIL",
29
29
  RUN_BOT_FLOW: "RUN_BOT_FLOW",
30
30
  RESET_BOT_FLOW: "RESET_BOT_FLOW",
31
+ CLOSE_BOT_SESSION: "CLOSE_BOT_SESSION",
32
+ GET_BOT_MAIN_MENU: "GET_BOT_MAIN_MENU",
31
33
  GET_BOT_DETAIL: "GET_BOT_DETAIL",
32
34
  GET_CONVERSATION_BY_BOT_ID: "GET_CONVERSATION_BY_BOT_ID",
33
35
  LEAVE_CONVERSATION: "LEAVE_CONVERSATION",
@@ -31,6 +31,7 @@ export declare const ENDPOINTS: {
31
31
  getConversationDetail: (conversationId: string) => string;
32
32
  runBotFlow: (conversationId: string) => string;
33
33
  resetBotFlow: (conversationId: string) => string;
34
+ closeBotSession: (conversationId: string) => string;
34
35
  getBotMainMenu: (conversationId: string) => string;
35
36
  getBotDetail: (botId: string) => string;
36
37
  getConversationByBotId: (botId: string) => string;
@@ -1 +1 @@
1
- {"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../../src/services/routes.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,SAAS;;;;;;mCAMS,MAAM;;0CAGC,MAAM,UAAU,MAAM;6BAEnC,MAAM;;oDAEiB,MAAM;uCAEnB,MAAM;kCAEX,MAAM;;oCAGJ,MAAM;mCAEP,MAAM;uCAEF,MAAM;;;;;;;;iCASZ,MAAM;4CAEK,MAAM;;;;gDAKF,MAAM;qCAEjB,MAAM;uCAEJ,MAAM;yCAEJ,MAAM;8BAEjB,MAAM;wCACI,MAAM;;;;;;;;;CAUzC,CAAC"}
1
+ {"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../../src/services/routes.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,SAAS;;;;;;mCAMS,MAAM;;0CAGC,MAAM,UAAU,MAAM;6BAEnC,MAAM;;oDAEiB,MAAM;uCAEnB,MAAM;kCAEX,MAAM;;oCAGJ,MAAM;mCAEP,MAAM;uCAEF,MAAM;;;;;;;;iCASZ,MAAM;4CAEK,MAAM;;;;gDAKF,MAAM;qCAEjB,MAAM;uCAEJ,MAAM;0CAEH,MAAM;yCAEP,MAAM;8BAEjB,MAAM;wCACI,MAAM;;;;;;;;;CAUzC,CAAC"}
@@ -31,6 +31,7 @@ export const ENDPOINTS = {
31
31
  getConversationDetail: (conversationId) => `/chat-service/v1/app/conversations/${conversationId}`,
32
32
  runBotFlow: (conversationId) => `/chat-service/v1/app/conversations/${conversationId}/bot-flows/run`,
33
33
  resetBotFlow: (conversationId) => `/chat-service/v1/app/conversations/${conversationId}/bot-flows/reset`,
34
+ closeBotSession: (conversationId) => `/chat-service/v1/app/conversations/${conversationId}/session/close`,
34
35
  getBotMainMenu: (conversationId) => `/chat-service/v1/app/conversations/${conversationId}/bot-flows/main-menu`,
35
36
  getBotDetail: (botId) => `/chat-service/v1/app/bots/${botId}`,
36
37
  getConversationByBotId: (botId) => `/chat-service/v1/app/bots/${botId}/conversation`,