@cmnd-ai/chatbot-react 1.7.0 → 1.8.0

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 (39) hide show
  1. package/Readme.md +239 -15
  2. package/dist/ChatProvider/index.d.ts +1 -1
  3. package/dist/ChatProvider/index.js +13 -16
  4. package/dist/ChatProvider/processStream/index.js +58 -51
  5. package/dist/CmndChatBot/index.d.ts +15 -4
  6. package/dist/CmndChatBot/index.js +4 -4
  7. package/dist/components/Chatbubble.d.ts +13 -3
  8. package/dist/components/Chatbubble.js +18 -17
  9. package/dist/components/Conversation.d.ts +7 -3
  10. package/dist/components/Conversation.js +3 -2
  11. package/dist/components/ConversationCard.d.ts +18 -0
  12. package/dist/components/ConversationCard.js +83 -0
  13. package/dist/components/ConversationsPanel/index.d.ts +33 -0
  14. package/dist/components/ConversationsPanel/index.js +333 -0
  15. package/dist/components/LoadingBubble.d.ts +14 -2
  16. package/dist/components/LoadingBubble.js +8 -7
  17. package/dist/components/ScrollToBottomButton.d.ts +10 -0
  18. package/dist/components/ScrollToBottomButton.js +57 -0
  19. package/dist/constants/endpoints.d.ts +5 -0
  20. package/dist/constants/endpoints.js +6 -0
  21. package/dist/hooks/use-fetch-data.d.ts +9 -0
  22. package/dist/hooks/use-fetch-data.js +32 -0
  23. package/dist/hooks/use-messages-scroll.d.ts +15 -0
  24. package/dist/hooks/use-messages-scroll.js +80 -0
  25. package/dist/index.d.ts +2 -1
  26. package/dist/index.js +1 -0
  27. package/dist/services/getChatBotConversationsList/index.d.ts +7 -0
  28. package/dist/services/getChatBotConversationsList/index.js +11 -0
  29. package/dist/styles/index.css +110 -0
  30. package/dist/type.d.ts +32 -0
  31. package/dist/utils/format_date/index.d.ts +2 -0
  32. package/dist/utils/format_date/index.js +32 -0
  33. package/dist/utils/getConversationLocalStorageKey/index.d.ts +5 -0
  34. package/dist/utils/getConversationLocalStorageKey/index.js +2 -0
  35. package/dist/utils/getUTCDateTime/index.d.ts +2 -0
  36. package/dist/utils/getUTCDateTime/index.js +11 -0
  37. package/dist/utils/saveConversationIdToLocalStorage/index.d.ts +6 -0
  38. package/dist/utils/saveConversationIdToLocalStorage/index.js +19 -0
  39. package/package.json +1 -1
@@ -11,6 +11,7 @@ import SyntaxHighlighter from "react-syntax-highlighter";
11
11
  //@ts-ignore
12
12
  import oneDark from "react-syntax-highlighter/dist/cjs/styles/prism/one-dark.js";
13
13
  import { overrideStyle } from "../utils.js";
14
+ import saveConversationIdToLocalStorage from "../utils/saveConversationIdToLocalStorage/index.js";
14
15
  const patchLastMessageToolInfo = (messages, toolInfo) => {
15
16
  console.log("patchLastMessageToolInfo", messages, toolInfo);
16
17
  const lastMessage = messages[messages.length - 1];
@@ -26,25 +27,25 @@ const patchLastMessageToolInfo = (messages, toolInfo) => {
26
27
  const newMessages = [...shallowCopyOfMessagesWithoutLast, copyOfLastMessage];
27
28
  return newMessages;
28
29
  };
29
- const confirmToolRun = async ({ messages, setMessages, postSessionMessage, setIsChatLoading, setCanSendMessage, setChatbotConversationId, scrollToBottom, }) => {
30
+ const confirmToolRun = async ({ messages, setMessages, postSessionMessage, setIsChatLoading, setCanSendMessage, setChatbotConversationId, chatbotId, organizationId, }) => {
30
31
  const newMessages = patchLastMessageToolInfo(messages, {
31
32
  confirmed: true,
32
33
  });
33
34
  setIsChatLoading(true);
34
35
  setCanSendMessage(false);
35
36
  setMessages(newMessages);
36
- await postSessionMessage(newMessages, (data) => {
37
+ await postSessionMessage(newMessages, async (data) => {
37
38
  if (data.finalResponseWithUsageData) {
38
39
  setCanSendMessage(true);
39
40
  setIsChatLoading(false);
40
41
  const { messages, chatbotConversationId } = data;
41
42
  if (chatbotConversationId) {
42
43
  setChatbotConversationId(chatbotConversationId);
43
- // saveConversationIdToLocalStorage(
44
- // chatbotConversationId.toString(),
45
- // config.chatbot_id!,
46
- // config.organization_id!
47
- // );
44
+ await saveConversationIdToLocalStorage({
45
+ chatbotConversationId,
46
+ chatbotId,
47
+ organizationId,
48
+ });
48
49
  }
49
50
  messages && setMessages(messages);
50
51
  }
@@ -58,23 +59,23 @@ const confirmToolRun = async ({ messages, setMessages, postSessionMessage, setIs
58
59
  };
59
60
  newAssistantMessage.message = data.message;
60
61
  setMessages([...newMessages, newAssistantMessage]);
61
- scrollToBottom();
62
62
  }
63
63
  });
64
64
  };
65
- const getChatAvatar = (role) => {
65
+ const getChatAvatar = (role, theme = "light", Components) => {
66
+ const iconColor = theme === "dark" ? "#ffffff" : "#000000";
66
67
  switch (role) {
67
68
  case MessageRole.USER:
68
- return _jsx(FaUserCircle, {});
69
+ return Components?.UserAvatar ? (_jsx(Components.UserAvatar, {})) : (_jsx(FaUserCircle, { color: iconColor }));
69
70
  case MessageRole.FUNCTION:
70
- return _jsx(BsTools, {});
71
+ return Components?.ToolAvatar ? (_jsx(Components.ToolAvatar, {})) : (_jsx(BsTools, { color: iconColor }));
71
72
  case MessageRole.ASSISTANT:
72
- return _jsx(BsRobot, {});
73
+ return Components?.BotAvatar ? (_jsx(Components.BotAvatar, {})) : (_jsx(BsRobot, { color: iconColor }));
73
74
  default:
74
- return _jsx(BsRobot, {});
75
+ return _jsx(BsRobot, { color: iconColor });
75
76
  }
76
77
  };
77
- const Chatbubble = ({ message, role, toolCallDetails, tools, postSessionMessage, setMessages, messages, hide, setChatbotConversationId, setCanSendMessage, setIsChatLoading, scrollToBottom, isLoadingBubble, UITools, customStyles, }) => {
78
+ const Chatbubble = ({ message, role, toolCallDetails, tools, postSessionMessage, setMessages, messages, hide, setChatbotConversationId, setCanSendMessage, setIsChatLoading, isLoadingBubble, UITools, customStyles, chatbotId, organizationId, theme, Components, }) => {
78
79
  const toolData = tools?.find((t) => t.name === toolCallDetails?.name);
79
80
  const hasConfirmedToolRun = useRef(false);
80
81
  const isPostingMessage = useRef(false);
@@ -92,7 +93,8 @@ const Chatbubble = ({ message, role, toolCallDetails, tools, postSessionMessage,
92
93
  setIsChatLoading,
93
94
  setCanSendMessage,
94
95
  setChatbotConversationId,
95
- scrollToBottom,
96
+ chatbotId,
97
+ organizationId,
96
98
  });
97
99
  }
98
100
  }, []);
@@ -120,7 +122,7 @@ const Chatbubble = ({ message, role, toolCallDetails, tools, postSessionMessage,
120
122
  return (_jsxs("div", { style: defaultStyle, className: `cmnd-chatbot-chat-bubble ${role}`, children: [_jsx("span", { style: overrideStyle({
121
123
  fontSize: "30px",
122
124
  color: "black",
123
- }, customStyles?.chatAvatarStyle), children: getChatAvatar(role) }), _jsxs("span", { style: chatBubbleCustomStyle, children: [role === MessageRole.USER || isLoadingBubble ? (_jsx("span", { children: message })) : (_jsx(ReactMarkdown, { className: "markdown", remarkPlugins: [remarkGfm], children: message?.toString() ?? "", remarkRehypeOptions: { passThrough: ["link"] }, components: {
125
+ }, customStyles?.chatAvatarStyle), children: getChatAvatar(role, theme, Components) }), _jsxs("span", { style: chatBubbleCustomStyle, children: [role === MessageRole.USER || isLoadingBubble ? (_jsx("span", { children: message })) : (_jsx(ReactMarkdown, { className: "markdown", remarkPlugins: [remarkGfm], children: message?.toString() ?? "", remarkRehypeOptions: { passThrough: ["link"] }, components: {
124
126
  // eslint-disable-next-line @typescript-eslint/ban-ts-comment
125
127
  // @ts-ignore
126
128
  code({ inline, className, children, ...props }) {
@@ -165,7 +167,6 @@ const Chatbubble = ({ message, role, toolCallDetails, tools, postSessionMessage,
165
167
  message: data.message,
166
168
  };
167
169
  setMessages([...newMessages, newAssistantMessage]);
168
- scrollToBottom();
169
170
  }
170
171
  };
171
172
  try {
@@ -14,9 +14,9 @@ export interface ConversationProps {
14
14
  setIsChatLoading: Dispatch<SetStateAction<boolean>>;
15
15
  setCanSendMessage: Dispatch<SetStateAction<boolean>>;
16
16
  canSendMessage: boolean;
17
- scrollToBottom: () => void;
18
17
  enabledTools: any[];
19
- postSessionMessage: (message: string, onData: any) => void;
18
+ postSessionMessage: (newMessages: any, onData: any) => Promise<any>;
19
+ theme?: "light" | "dark";
20
20
  Components?: {
21
21
  InputField?: (params: InputFieldProps) => JSX.Element;
22
22
  SendButton?: (params: SendButtonProps) => JSX.Element;
@@ -25,6 +25,10 @@ export interface ConversationProps {
25
25
  UITools?: CMNDChatbotUITool[];
26
26
  customStyles?: CustomStyles;
27
27
  setCurrentConversationMemory: (memory: CMNDChatMemory) => Promise<any>;
28
+ chatbotId: number;
29
+ organizationId: number;
30
+ isMessagesScrolledToBottom?: boolean;
31
+ resetMessagesScroll?: () => void;
28
32
  }
29
- declare const Conversation: ({ messages, handleSendClick, isChatLoading, error, messagesRef, enabledTools, postSessionMessage, setMessages, setChatbotConversationId, setIsChatLoading, setCanSendMessage, scrollToBottom, canSendMessage, setInput, input, Components, UITools, customStyles, }: ConversationProps) => JSX.Element;
33
+ declare const Conversation: ({ messages, handleSendClick, isChatLoading, error, messagesRef, enabledTools, postSessionMessage, setMessages, setChatbotConversationId, setIsChatLoading, setCanSendMessage, canSendMessage, setInput, input, theme, Components, UITools, customStyles, chatbotId, organizationId, isMessagesScrolledToBottom, resetMessagesScroll, }: ConversationProps) => JSX.Element;
30
34
  export default Conversation;
@@ -1,9 +1,10 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import Chatbubble from "./Chatbubble.js";
3
3
  import LoadingBubble from "./LoadingBubble.js";
4
+ import ScrollToBottomButton from "./ScrollToBottomButton.js";
4
5
  import ChatInputBox from "./ChatInputBox.js";
5
- const Conversation = ({ messages, handleSendClick, isChatLoading, error, messagesRef, enabledTools, postSessionMessage, setMessages, setChatbotConversationId, setIsChatLoading, setCanSendMessage, scrollToBottom, canSendMessage, setInput, input, Components, UITools, customStyles, }) => {
6
- return (_jsxs("div", { className: "cmnd-conversations", children: [_jsxs("div", { ref: messagesRef, id: "messages", className: "cmnd-conversations-messages", children: [error, messages.map((m, i) => (_jsx(Chatbubble, { customStyles: customStyles, hide: m.hiddenFromUser, message: m.message, role: m.role, toolCallDetails: m.tool, tools: enabledTools, postSessionMessage: postSessionMessage, messages: messages, setMessages: setMessages, id: m.id, setChatbotConversationId: setChatbotConversationId, setIsChatLoading: setIsChatLoading, setCanSendMessage: setCanSendMessage, scrollToBottom: scrollToBottom, UITools: UITools }, i))), isChatLoading ? _jsx(LoadingBubble, { customStyles: customStyles }) : null] }), _jsxs("div", { id: "cmnd-input-div", className: "cmnd-input-div", children: [Components?.InputField ? (_jsx(Components.InputField, { ...{ input, setInput, canSendMessage, handleSendClick } })) : (_jsx(ChatInputBox, { input: input, setInput: setInput, handleSendClick: handleSendClick })), Components?.SendButton ? (_jsx(Components.SendButton, { ...{
6
+ const Conversation = ({ messages, handleSendClick, isChatLoading, error, messagesRef, enabledTools, postSessionMessage, setMessages, setChatbotConversationId, setIsChatLoading, setCanSendMessage, canSendMessage, setInput, input, theme, Components, UITools, customStyles, chatbotId, organizationId, isMessagesScrolledToBottom = true, resetMessagesScroll, }) => {
7
+ return (_jsxs("div", { className: "cmnd-conversations", children: [_jsxs("div", { ref: messagesRef, id: "messages", className: "cmnd-conversations-messages", children: [error, messages.map((m, i) => (_jsx(Chatbubble, { chatbotId: chatbotId, organizationId: organizationId, customStyles: customStyles, hide: m.hiddenFromUser, message: m.message, role: m.role, toolCallDetails: m.tool, tools: enabledTools, postSessionMessage: postSessionMessage, messages: messages, setMessages: setMessages, id: m.id, setChatbotConversationId: setChatbotConversationId, setIsChatLoading: setIsChatLoading, setCanSendMessage: setCanSendMessage, UITools: UITools, theme: theme, Components: Components }, i))), isChatLoading ? (_jsx(LoadingBubble, { customStyles: customStyles, chatbotId: chatbotId, organizationId: organizationId, theme: theme, Components: Components })) : null] }), _jsx(ScrollToBottomButton, { onClick: resetMessagesScroll || (() => { }), isVisible: !isMessagesScrolledToBottom && messages.length > 0, theme: theme, customStyles: customStyles }), _jsxs("div", { id: "cmnd-input-div", className: "cmnd-input-div", children: [Components?.InputField ? (_jsx(Components.InputField, { ...{ input, setInput, canSendMessage, handleSendClick } })) : (_jsx(ChatInputBox, { input: input, setInput: setInput, handleSendClick: handleSendClick })), Components?.SendButton ? (_jsx(Components.SendButton, { ...{
7
8
  canSendMessage,
8
9
  handleSendClick,
9
10
  } })) : (_jsx("button", { className: "cmnd-send-button", onClick: handleSendClick, children: "Send" }))] })] }));
@@ -0,0 +1,18 @@
1
+ import React from "react";
2
+ import { ChatbotConversation } from "../type.js";
3
+ interface ConversationCardProps {
4
+ conversation: ChatbotConversation;
5
+ isActive: boolean;
6
+ onClick: () => void;
7
+ onDelete?: () => void;
8
+ theme?: "light" | "dark";
9
+ customStyles?: {
10
+ conversationCardStyle?: React.CSSProperties;
11
+ activeConversationCardStyle?: React.CSSProperties;
12
+ titleStyle?: React.CSSProperties;
13
+ dateStyle?: React.CSSProperties;
14
+ deleteButtonStyle?: React.CSSProperties;
15
+ };
16
+ }
17
+ declare const ConversationCard: React.FC<ConversationCardProps>;
18
+ export default ConversationCard;
@@ -0,0 +1,83 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import formatDate from "../utils/format_date/index.js";
3
+ const ConversationCard = ({ conversation, isActive, onClick, onDelete, theme = "light", customStyles, }) => {
4
+ const themeColors = {
5
+ light: {
6
+ card: "#ffffff",
7
+ activeCard: "#f0f2f5",
8
+ border: "#e0e0e0",
9
+ activeBorder: "#373E4E",
10
+ text: "#212121",
11
+ secondaryText: "#757575",
12
+ deleteHover: "#ff6b6b",
13
+ deleteHoverBg: "#ffebee",
14
+ },
15
+ dark: {
16
+ card: "#2a2f3a",
17
+ activeCard: "#3d4354",
18
+ border: "#3d4354",
19
+ activeBorder: "#5a67d8",
20
+ text: "#ffffff",
21
+ secondaryText: "#848d97",
22
+ deleteHover: "#ff6b6b",
23
+ deleteHoverBg: "#ff6b6b20",
24
+ },
25
+ };
26
+ const colors = themeColors[theme];
27
+ const truncateTitle = (title, maxLength = 50) => {
28
+ return title.length > maxLength
29
+ ? `${title.substring(0, maxLength)}...`
30
+ : title;
31
+ };
32
+ return (_jsx("div", { className: `cmnd-conversation-card ${isActive ? "cmnd-conversation-card-active" : ""}`, style: {
33
+ padding: "12px 16px",
34
+ margin: "8px 0",
35
+ borderRadius: "12px",
36
+ cursor: "pointer",
37
+ transition: "all 0.2s ease",
38
+ border: `1px solid ${isActive ? colors.activeBorder : colors.border}`,
39
+ backgroundColor: isActive ? colors.activeCard : colors.card,
40
+ position: "relative",
41
+ ...customStyles?.conversationCardStyle,
42
+ ...(isActive && customStyles?.activeConversationCardStyle),
43
+ }, onClick: onClick, children: _jsxs("div", { style: {
44
+ display: "flex",
45
+ justifyContent: "space-between",
46
+ alignItems: "flex-start",
47
+ }, children: [_jsxs("div", { style: { flex: 1, minWidth: 0 }, children: [_jsx("h4", { className: "cmnd-conversation-title", style: {
48
+ margin: "0 0 4px 0",
49
+ fontSize: "14px",
50
+ fontWeight: "600",
51
+ color: colors.text,
52
+ lineHeight: "1.3",
53
+ whiteSpace: "nowrap",
54
+ overflow: "hidden",
55
+ textOverflow: "ellipsis",
56
+ ...customStyles?.titleStyle,
57
+ }, children: conversation.chatbotConversationTitle }), _jsx("p", { className: "cmnd-conversation-date", style: {
58
+ margin: "0",
59
+ fontSize: "12px",
60
+ color: colors.secondaryText,
61
+ ...customStyles?.dateStyle,
62
+ }, children: formatDate(conversation.updatedAt) })] }), onDelete && (_jsx("button", { className: "cmnd-conversation-delete", onClick: (e) => {
63
+ e.stopPropagation();
64
+ onDelete();
65
+ }, style: {
66
+ background: "none",
67
+ border: "none",
68
+ color: colors.secondaryText,
69
+ cursor: "pointer",
70
+ padding: "4px",
71
+ borderRadius: "4px",
72
+ fontSize: "14px",
73
+ transition: "all 0.2s ease",
74
+ ...customStyles?.deleteButtonStyle,
75
+ }, onMouseEnter: (e) => {
76
+ e.currentTarget.style.color = colors.deleteHover;
77
+ e.currentTarget.style.backgroundColor = colors.deleteHoverBg;
78
+ }, onMouseLeave: (e) => {
79
+ e.currentTarget.style.color = colors.secondaryText;
80
+ e.currentTarget.style.backgroundColor = "transparent";
81
+ }, children: "\u00D7" }))] }) }));
82
+ };
83
+ export default ConversationCard;
@@ -0,0 +1,33 @@
1
+ import React, { Dispatch, SetStateAction } from "react";
2
+ import { InputFieldProps, SendButtonProps } from "../../type.js";
3
+ interface ConversationsPanelProps {
4
+ organizationId: number;
5
+ chatbotId: number;
6
+ baseUrl: string;
7
+ theme?: "light" | "dark";
8
+ enabledTools?: any[];
9
+ setChatbotConversationId: Dispatch<SetStateAction<number | undefined>>;
10
+ chatbotConversationId: number | undefined;
11
+ postSessionMessage: (newMessages: any, onData: any) => Promise<any>;
12
+ Components?: {
13
+ InputField?: (params: InputFieldProps) => JSX.Element;
14
+ SendButton?: (params: SendButtonProps) => JSX.Element;
15
+ error?: any;
16
+ };
17
+ UITools?: any[];
18
+ customStyles?: {
19
+ panelStyle?: React.CSSProperties;
20
+ sidebarStyle?: React.CSSProperties;
21
+ conversationListStyle?: React.CSSProperties;
22
+ headerStyle?: React.CSSProperties;
23
+ newChatButtonStyle?: React.CSSProperties;
24
+ refreshButtonStyle?: React.CSSProperties;
25
+ conversationCardStyle?: React.CSSProperties;
26
+ activeConversationCardStyle?: React.CSSProperties;
27
+ titleStyle?: React.CSSProperties;
28
+ dateStyle?: React.CSSProperties;
29
+ deleteButtonStyle?: React.CSSProperties;
30
+ };
31
+ }
32
+ export declare const ConversationsPanel: React.FC<ConversationsPanelProps>;
33
+ export {};
@@ -0,0 +1,333 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import React, { useState, useEffect, } from "react";
3
+ import useFetchData from "../../hooks/use-fetch-data.js";
4
+ import getChatBotConversationsList from "../../services/getChatBotConversationsList/index.js";
5
+ import Conversation from "../Conversation.js";
6
+ import ConversationCard from "../ConversationCard.js";
7
+ import { RiAddLine } from "react-icons/ri";
8
+ import { FiSidebar } from "react-icons/fi";
9
+ import getConversationLocalStorageKey from "../../utils/getConversationLocalStorageKey/index.js";
10
+ import saveConversationIdToLocalStorage from "../../utils/saveConversationIdToLocalStorage/index.js";
11
+ import getUTCDateTime from "../../utils/getUTCDateTime/index.js";
12
+ import useMessagesScroll from "../../hooks/use-messages-scroll.js";
13
+ export const ConversationsPanel = ({ organizationId, chatbotId, baseUrl, theme = "light", enabledTools = [], setChatbotConversationId, chatbotConversationId, postSessionMessage, Components, UITools, customStyles, }) => {
14
+ const [selectedConversation, setSelectedConversation] = useState(null);
15
+ const [messages, setMessages] = useState([]);
16
+ const [input, setInput] = useState("");
17
+ const [isChatLoading, setIsChatLoading] = useState(false);
18
+ const [canSendMessage, setCanSendMessage] = useState(true);
19
+ const [conversationIds, setConversationIds] = useState([]);
20
+ const [isSidebarCollapsed, setIsSidebarCollapsed] = useState(false);
21
+ const { messagesRef, resetMessagesScroll, isMessagesScrolledToBottom } = useMessagesScroll(messages);
22
+ const themeColors = {
23
+ light: {
24
+ background: "#ffffff",
25
+ sidebar: "#f8f9fa",
26
+ card: "#ffffff",
27
+ activeCard: "#f0f2f5",
28
+ border: "#e0e0e0",
29
+ text: "#212121",
30
+ secondaryText: "#757575",
31
+ button: "#373E4E",
32
+ buttonHover: "#2a2f3a",
33
+ deleteHover: "#ff6b6b",
34
+ deleteHoverBg: "#ffebee",
35
+ },
36
+ dark: {
37
+ background: "#1a1d24",
38
+ sidebar: "#20232c",
39
+ card: "#2a2f3a",
40
+ activeCard: "#3d4354",
41
+ border: "#3d4354",
42
+ text: "#ffffff",
43
+ secondaryText: "#848d97",
44
+ button: "#3d4354",
45
+ buttonHover: "#4a5568",
46
+ deleteHover: "#ff6b6b",
47
+ deleteHoverBg: "#ff6b6b20",
48
+ },
49
+ };
50
+ const colors = themeColors[theme];
51
+ const localStorageKey = getConversationLocalStorageKey({
52
+ organizationId,
53
+ chatbotId,
54
+ });
55
+ useEffect(() => {
56
+ try {
57
+ const conversationsFromLocalStorage = JSON.parse(localStorage.getItem(localStorageKey) || "[]") ?? [];
58
+ setConversationIds(conversationsFromLocalStorage);
59
+ }
60
+ catch (error) {
61
+ console.error("Error parsing conversations from localStorage:", error);
62
+ setConversationIds([]);
63
+ }
64
+ }, [organizationId, chatbotId, localStorageKey]);
65
+ const refetchConversationIds = () => {
66
+ try {
67
+ const conversationsFromLocalStorage = JSON.parse(localStorage.getItem(localStorageKey) || "[]") ?? [];
68
+ setConversationIds(conversationsFromLocalStorage);
69
+ }
70
+ catch (error) {
71
+ console.error("Error parsing conversations from localStorage:", error);
72
+ setConversationIds([]);
73
+ }
74
+ };
75
+ const { data, loading, error, refetch } = useFetchData(() => {
76
+ // Only fetch if we have conversation IDs
77
+ if (conversationIds.length === 0) {
78
+ return Promise.resolve({
79
+ data: { chatbotConversations: [] },
80
+ status: 200,
81
+ statusText: "OK",
82
+ headers: {},
83
+ config: {},
84
+ });
85
+ }
86
+ return getChatBotConversationsList({
87
+ organizationId,
88
+ chatbotId,
89
+ conversationIds,
90
+ baseUrl,
91
+ });
92
+ }, [organizationId, chatbotId, conversationIds, baseUrl]);
93
+ const handleSendClick = () => {
94
+ if (!input.trim() || !canSendMessage)
95
+ return;
96
+ const userMessage = {
97
+ role: "user",
98
+ message: input,
99
+ id: Date.now().toString(),
100
+ unuseful: false,
101
+ hiddenFromUser: false,
102
+ };
103
+ const newMessages = [...messages, userMessage];
104
+ setMessages(newMessages);
105
+ setInput("");
106
+ setIsChatLoading(true);
107
+ setCanSendMessage(false);
108
+ const onData = async (data) => {
109
+ if (data.finalResponseWithUsageData) {
110
+ setIsChatLoading(false);
111
+ setCanSendMessage(true);
112
+ const { chatbotConversationId: newConversationId, messages: updatedMessages, } = data;
113
+ if (newConversationId) {
114
+ setChatbotConversationId(newConversationId);
115
+ await saveConversationIdToLocalStorage({
116
+ chatbotConversationId: newConversationId,
117
+ chatbotId,
118
+ organizationId,
119
+ });
120
+ refetchConversationIds();
121
+ if (selectedConversation &&
122
+ selectedConversation.chatbotConversationTitle === "New Conversation") {
123
+ setSelectedConversation({
124
+ ...selectedConversation,
125
+ chatbotConversationId: newConversationId,
126
+ chatbotConversationTitle: input.substring(0, 50) + (input.length > 50 ? "..." : ""),
127
+ messages: updatedMessages || newMessages,
128
+ });
129
+ }
130
+ }
131
+ if (updatedMessages) {
132
+ setMessages(updatedMessages);
133
+ }
134
+ }
135
+ if (data.message) {
136
+ setIsChatLoading(false);
137
+ setCanSendMessage(true);
138
+ const assistantMessage = {
139
+ role: "assistant",
140
+ message: data.message,
141
+ id: Date.now().toString(),
142
+ unuseful: false,
143
+ hiddenFromUser: false,
144
+ };
145
+ setMessages([...newMessages, assistantMessage]);
146
+ }
147
+ };
148
+ postSessionMessage(newMessages, onData).catch((error) => {
149
+ console.error(error);
150
+ setIsChatLoading(false);
151
+ setCanSendMessage(true);
152
+ });
153
+ };
154
+ const handleConversationSelect = (conversation) => {
155
+ setSelectedConversation(conversation);
156
+ setChatbotConversationId(conversation.chatbotConversationId);
157
+ const formattedMessages = conversation.messages.map((msg) => ({
158
+ ...msg,
159
+ id: msg.id || Date.now().toString(),
160
+ }));
161
+ setMessages(formattedMessages);
162
+ };
163
+ const handleNewChat = () => {
164
+ setSelectedConversation(null);
165
+ setChatbotConversationId(undefined);
166
+ setMessages([]);
167
+ setInput("");
168
+ const dateString = getUTCDateTime();
169
+ const newConversation = {
170
+ chatbotConversationId: Date.now(),
171
+ messages: [],
172
+ chatbotId: chatbotId,
173
+ chatbotConversationTitle: "New Conversation",
174
+ createdAt: dateString,
175
+ updatedAt: dateString,
176
+ totalCostSoFar: 0,
177
+ totalTokensSoFar: 0,
178
+ };
179
+ setSelectedConversation(newConversation);
180
+ };
181
+ const handleDeleteConversation = async (conversationId) => {
182
+ try {
183
+ const currentConversations = JSON.parse(localStorage.getItem(localStorageKey) || "[]") ?? [];
184
+ const updatedConversations = currentConversations.filter((id) => id !== conversationId);
185
+ localStorage.setItem(localStorageKey, JSON.stringify(updatedConversations));
186
+ if (selectedConversation?.chatbotConversationId === conversationId) {
187
+ setSelectedConversation(null);
188
+ setMessages([]);
189
+ setChatbotConversationId(undefined);
190
+ }
191
+ refetchConversationIds();
192
+ }
193
+ catch (error) {
194
+ console.error("Error deleting conversation:", error);
195
+ }
196
+ };
197
+ const setCurrentConversationMemory = async (memory) => {
198
+ console.log("Set conversation memory:", memory);
199
+ };
200
+ const allConversations = React.useMemo(() => {
201
+ const existingConversations = data?.chatbotConversations || [];
202
+ const newConversation = selectedConversation &&
203
+ selectedConversation.chatbotConversationTitle === "New Conversation"
204
+ ? selectedConversation
205
+ : null;
206
+ let conversations = [...existingConversations];
207
+ if (newConversation) {
208
+ conversations.push(newConversation);
209
+ }
210
+ return conversations.sort((a, b) => {
211
+ const dateA = new Date(a.updatedAt);
212
+ const dateB = new Date(b.updatedAt);
213
+ return dateB.getTime() - dateA.getTime();
214
+ });
215
+ }, [data?.chatbotConversations, selectedConversation]);
216
+ return (_jsxs("div", { className: "cmnd-conversations-panel", style: {
217
+ display: "flex",
218
+ height: "100%",
219
+ backgroundColor: colors.background,
220
+ color: colors.text,
221
+ ...customStyles?.panelStyle,
222
+ }, children: [_jsxs("div", { className: "cmnd-conversations-sidebar", style: {
223
+ width: isSidebarCollapsed ? "50px" : "300px",
224
+ borderRight: `1px solid ${colors.border}`,
225
+ display: "flex",
226
+ flexDirection: "column",
227
+ backgroundColor: colors.sidebar,
228
+ transition: "width 0.3s ease",
229
+ ...customStyles?.sidebarStyle,
230
+ }, children: [_jsxs("div", { className: "cmnd-conversations-header", style: {
231
+ padding: isSidebarCollapsed ? "12px 8px" : "16px",
232
+ borderBottom: `1px solid ${colors.border}`,
233
+ display: "flex",
234
+ justifyContent: isSidebarCollapsed ? "center" : "space-between",
235
+ alignItems: "center",
236
+ flexDirection: isSidebarCollapsed ? "column" : "row",
237
+ gap: isSidebarCollapsed ? "8px" : "0",
238
+ ...customStyles?.headerStyle,
239
+ }, children: [!isSidebarCollapsed && (_jsx("h3", { style: {
240
+ margin: 0,
241
+ fontSize: "16px",
242
+ fontWeight: "600",
243
+ color: colors.text,
244
+ }, children: "Conversations" })), _jsxs("div", { style: {
245
+ display: "flex",
246
+ gap: "8px",
247
+ flexDirection: isSidebarCollapsed ? "column" : "row",
248
+ }, children: [_jsx("button", { className: "cmnd-toggle-sidebar-button", onClick: () => setIsSidebarCollapsed(!isSidebarCollapsed), title: isSidebarCollapsed ? "Expand Sidebar" : "Collapse Sidebar", style: {
249
+ background: colors.button,
250
+ border: "none",
251
+ color: theme === "light" ? "#ffffff" : colors.text,
252
+ padding: "8px",
253
+ borderRadius: "6px",
254
+ cursor: "pointer",
255
+ display: "flex",
256
+ alignItems: "center",
257
+ justifyContent: "center",
258
+ transition: "all 0.2s ease",
259
+ ...customStyles?.newChatButtonStyle,
260
+ }, onMouseEnter: (e) => {
261
+ e.currentTarget.style.backgroundColor = colors.buttonHover;
262
+ }, onMouseLeave: (e) => {
263
+ e.currentTarget.style.backgroundColor = colors.button;
264
+ }, children: _jsx(FiSidebar, { size: 16 }) }), _jsx("button", { className: "cmnd-new-chat-button", onClick: handleNewChat, title: "New Chat", style: {
265
+ background: colors.button,
266
+ border: "none",
267
+ color: theme === "light" ? "#ffffff" : colors.text,
268
+ padding: "8px",
269
+ borderRadius: "6px",
270
+ cursor: "pointer",
271
+ display: "flex",
272
+ alignItems: "center",
273
+ justifyContent: "center",
274
+ transition: "all 0.2s ease",
275
+ ...customStyles?.newChatButtonStyle,
276
+ }, onMouseEnter: (e) => {
277
+ e.currentTarget.style.backgroundColor = colors.buttonHover;
278
+ }, onMouseLeave: (e) => {
279
+ e.currentTarget.style.backgroundColor = colors.button;
280
+ }, children: _jsx(RiAddLine, { size: 16 }) })] })] }), _jsx("div", { className: "cmnd-conversation-list", style: {
281
+ flex: 1,
282
+ overflowY: "auto",
283
+ padding: "12px",
284
+ ...customStyles?.conversationListStyle,
285
+ }, children: isSidebarCollapsed ? (_jsx("div", { style: {
286
+ textAlign: "center",
287
+ padding: "8px",
288
+ color: colors.secondaryText,
289
+ fontSize: "12px",
290
+ }, children: allConversations.length })) : loading && allConversations.length === 0 ? (_jsx("div", { style: {
291
+ textAlign: "center",
292
+ padding: "20px",
293
+ color: colors.secondaryText,
294
+ }, children: "Loading conversations..." })) : error && allConversations.length === 0 ? (_jsx("div", { style: { textAlign: "center", padding: "20px", color: "#ff6b6b" }, children: "Error loading conversations" })) : allConversations.length === 0 ? (_jsx("div", { style: {
295
+ textAlign: "center",
296
+ padding: "20px",
297
+ color: colors.secondaryText,
298
+ }, children: "No conversations yet" })) : (allConversations.map((conversation) => (_jsx(ConversationCard, { conversation: conversation, isActive: selectedConversation?.chatbotConversationId ===
299
+ conversation.chatbotConversationId, onClick: () => {
300
+ if (conversation.chatbotConversationTitle === "New Conversation") {
301
+ }
302
+ else {
303
+ handleConversationSelect(conversation);
304
+ }
305
+ }, onDelete: () => {
306
+ if (conversation.chatbotConversationTitle === "New Conversation") {
307
+ setSelectedConversation(null);
308
+ setMessages([]);
309
+ }
310
+ else {
311
+ handleDeleteConversation(conversation.chatbotConversationId);
312
+ }
313
+ }, theme: theme, customStyles: {
314
+ conversationCardStyle: customStyles?.conversationCardStyle,
315
+ activeConversationCardStyle: customStyles?.activeConversationCardStyle,
316
+ titleStyle: customStyles?.titleStyle,
317
+ dateStyle: customStyles?.dateStyle,
318
+ deleteButtonStyle: customStyles?.deleteButtonStyle,
319
+ } }, conversation.chatbotConversationId)))) })] }), _jsx("div", { className: "cmnd-chat-area", style: {
320
+ flex: 1,
321
+ display: "flex",
322
+ flexDirection: "column",
323
+ }, children: !selectedConversation ? (_jsx("div", { style: {
324
+ display: "flex",
325
+ alignItems: "center",
326
+ justifyContent: "center",
327
+ height: "100%",
328
+ color: colors.secondaryText,
329
+ fontSize: "16px",
330
+ textAlign: "center",
331
+ padding: "20px",
332
+ }, children: _jsx("div", { children: _jsx("div", { children: "Select a conversation or start a new one" }) }) })) : (_jsx(Conversation, { messages: messages, setMessages: setMessages, handleSendClick: handleSendClick, input: input, setInput: setInput, isChatLoading: isChatLoading, error: error ? "Error loading conversations" : null, messagesRef: messagesRef, setChatbotConversationId: setChatbotConversationId, chatbotConversationId: chatbotConversationId, setIsChatLoading: setIsChatLoading, setCanSendMessage: setCanSendMessage, canSendMessage: canSendMessage, enabledTools: enabledTools, postSessionMessage: postSessionMessage, theme: theme, Components: Components, UITools: UITools, customStyles: customStyles, setCurrentConversationMemory: setCurrentConversationMemory, chatbotId: chatbotId, organizationId: organizationId, isMessagesScrolledToBottom: isMessagesScrolledToBottom, resetMessagesScroll: resetMessagesScroll })) })] }));
333
+ };
@@ -1,7 +1,19 @@
1
1
  /// <reference types="react" />
2
- import { CustomStyles } from "../type.js";
2
+ import { CustomStyles, InputFieldProps, SendButtonProps } from "../type.js";
3
3
  interface LoadingBubbleProps {
4
4
  customStyles?: CustomStyles;
5
+ chatbotId: number;
6
+ organizationId: number;
7
+ theme?: "light" | "dark";
8
+ Components?: {
9
+ InputField?: (params: InputFieldProps) => JSX.Element;
10
+ SendButton?: (params: SendButtonProps) => JSX.Element;
11
+ BotAvatar?: () => JSX.Element;
12
+ UserAvatar?: () => JSX.Element;
13
+ ToolAvatar?: () => JSX.Element;
14
+ LoadingIndicator?: () => JSX.Element;
15
+ error?: any;
16
+ };
5
17
  }
6
- declare const LoadingBubble: ({ customStyles }: LoadingBubbleProps) => JSX.Element;
18
+ declare const LoadingBubble: ({ customStyles, chatbotId, organizationId, theme, Components, }: LoadingBubbleProps) => JSX.Element;
7
19
  export default LoadingBubble;