@cmnd-ai/chatbot-react 1.7.1 → 1.9.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 (42) hide show
  1. package/Readme.md +239 -15
  2. package/dist/ChatProvider/index.d.ts +1 -1
  3. package/dist/ChatProvider/index.js +54 -55
  4. package/dist/ChatProvider/useChatContext.d.ts +2 -2
  5. package/dist/ChatProvider/useChatContext.js +2 -2
  6. package/dist/CmndChatBot/index.d.ts +15 -4
  7. package/dist/CmndChatBot/index.js +4 -4
  8. package/dist/components/ChatInputBox.d.ts +2 -1
  9. package/dist/components/ChatInputBox.js +3 -3
  10. package/dist/components/Chatbubble.d.ts +13 -3
  11. package/dist/components/Chatbubble.js +18 -17
  12. package/dist/components/Conversation.d.ts +8 -3
  13. package/dist/components/Conversation.js +3 -2
  14. package/dist/components/ConversationCard.d.ts +18 -0
  15. package/dist/components/ConversationCard.js +83 -0
  16. package/dist/components/ConversationsPanel/index.d.ts +46 -0
  17. package/dist/components/ConversationsPanel/index.js +355 -0
  18. package/dist/components/LoadingBubble.d.ts +14 -2
  19. package/dist/components/LoadingBubble.js +8 -7
  20. package/dist/components/ScrollToBottomButton.d.ts +10 -0
  21. package/dist/components/ScrollToBottomButton.js +57 -0
  22. package/dist/constants/endpoints.d.ts +5 -0
  23. package/dist/constants/endpoints.js +6 -0
  24. package/dist/hooks/use-fetch-data.d.ts +8 -0
  25. package/dist/hooks/use-fetch-data.js +32 -0
  26. package/dist/hooks/use-messages-scroll.d.ts +15 -0
  27. package/dist/hooks/use-messages-scroll.js +80 -0
  28. package/dist/index.d.ts +3 -1
  29. package/dist/index.js +2 -0
  30. package/dist/services/getChatBotConversationsList/index.d.ts +7 -0
  31. package/dist/services/getChatBotConversationsList/index.js +12 -0
  32. package/dist/styles/index.css +110 -0
  33. package/dist/type.d.ts +57 -0
  34. package/dist/utils/format_date/index.d.ts +2 -0
  35. package/dist/utils/format_date/index.js +32 -0
  36. package/dist/utils/getConversationLocalStorageKey/index.d.ts +5 -0
  37. package/dist/utils/getConversationLocalStorageKey/index.js +2 -0
  38. package/dist/utils/getUTCDateTime/index.d.ts +2 -0
  39. package/dist/utils/getUTCDateTime/index.js +11 -0
  40. package/dist/utils/saveConversationIdToLocalStorage/index.d.ts +6 -0
  41. package/dist/utils/saveConversationIdToLocalStorage/index.js +19 -0
  42. package/package.json +1 -1
@@ -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,11 @@ 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;
32
+ inputRef?: React.RefObject<HTMLInputElement>;
28
33
  }
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;
34
+ 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, inputRef, }: ConversationProps) => JSX.Element;
30
35
  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, inputRef, }) => {
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, inputRef } })) : (_jsx(ChatInputBox, { input: input, setInput: setInput, handleSendClick: handleSendClick, inputRef: inputRef })), 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,46 @@
1
+ import React, { Dispatch, SetStateAction } from "react";
2
+ import { ChatbotConversation, 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
+ isSidebarCollapsed?: boolean;
32
+ setIsSidebarCollapsed?: React.Dispatch<React.SetStateAction<boolean>>;
33
+ selectedConversation: ChatbotConversation | null;
34
+ setSelectedConversation: React.Dispatch<React.SetStateAction<ChatbotConversation | null>>;
35
+ messages: any[];
36
+ setMessages: React.Dispatch<React.SetStateAction<any[]>>;
37
+ input: string;
38
+ setInput: React.Dispatch<React.SetStateAction<string>>;
39
+ inputRef: React.RefObject<HTMLInputElement>;
40
+ }
41
+ export interface ConversationsPanelRef {
42
+ handleSendClick: () => void;
43
+ handleNewChat: () => void;
44
+ }
45
+ export declare const ConversationsPanel: React.ForwardRefExoticComponent<ConversationsPanelProps & React.RefAttributes<ConversationsPanelRef>>;
46
+ export {};
@@ -0,0 +1,355 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import React, { useState, useEffect, forwardRef, useImperativeHandle, } 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 = forwardRef(({ organizationId, chatbotId, baseUrl, theme = "light", enabledTools = [], setChatbotConversationId, chatbotConversationId, postSessionMessage, Components, UITools, customStyles, isSidebarCollapsed, setIsSidebarCollapsed, selectedConversation, setSelectedConversation, messages, setMessages, input, setInput, inputRef, }, ref) => {
14
+ const [isChatLoading, setIsChatLoading] = useState(false);
15
+ const [canSendMessage, setCanSendMessage] = useState(true);
16
+ const [conversationIds, setConversationIds] = useState([]);
17
+ const isSidebarCollapsedProp = typeof isSidebarCollapsed === "boolean" ? isSidebarCollapsed : false;
18
+ const setIsSidebarCollapsedProp = setIsSidebarCollapsed;
19
+ const [internalSidebarCollapsed, setInternalSidebarCollapsed] = useState(false);
20
+ const isSidebarCollapsedFinal = typeof isSidebarCollapsed === "boolean"
21
+ ? isSidebarCollapsed
22
+ : internalSidebarCollapsed;
23
+ const setIsSidebarCollapsedFinal = setIsSidebarCollapsedProp || setInternalSidebarCollapsed;
24
+ const { messagesRef, resetMessagesScroll, isMessagesScrolledToBottom } = useMessagesScroll(messages);
25
+ const themeColors = {
26
+ light: {
27
+ background: "#ffffff",
28
+ sidebar: "#f8f9fa",
29
+ card: "#ffffff",
30
+ activeCard: "#f0f2f5",
31
+ border: "#e0e0e0",
32
+ text: "#212121",
33
+ secondaryText: "#757575",
34
+ button: "#373E4E",
35
+ buttonHover: "#2a2f3a",
36
+ deleteHover: "#ff6b6b",
37
+ deleteHoverBg: "#ffebee",
38
+ },
39
+ dark: {
40
+ background: "#1a1d24",
41
+ sidebar: "#20232c",
42
+ card: "#2a2f3a",
43
+ activeCard: "#3d4354",
44
+ border: "#3d4354",
45
+ text: "#ffffff",
46
+ secondaryText: "#848d97",
47
+ button: "#3d4354",
48
+ buttonHover: "#4a5568",
49
+ deleteHover: "#ff6b6b",
50
+ deleteHoverBg: "#ff6b6b20",
51
+ },
52
+ };
53
+ const colors = themeColors[theme];
54
+ const localStorageKey = getConversationLocalStorageKey({
55
+ organizationId,
56
+ chatbotId,
57
+ });
58
+ useEffect(() => {
59
+ try {
60
+ const conversationsFromLocalStorage = JSON.parse(localStorage.getItem(localStorageKey) || "[]") ?? [];
61
+ setConversationIds(conversationsFromLocalStorage);
62
+ }
63
+ catch (error) {
64
+ console.error("Error parsing conversations from localStorage:", error);
65
+ setConversationIds([]);
66
+ }
67
+ }, [organizationId, chatbotId, localStorageKey]);
68
+ const refetchConversationIds = () => {
69
+ try {
70
+ const conversationsFromLocalStorage = JSON.parse(localStorage.getItem(localStorageKey) || "[]") ?? [];
71
+ setConversationIds(conversationsFromLocalStorage);
72
+ }
73
+ catch (error) {
74
+ console.error("Error parsing conversations from localStorage:", error);
75
+ setConversationIds([]);
76
+ }
77
+ };
78
+ const { data, loading, error, refetch } = useFetchData(async () => {
79
+ // Only fetch if we have conversation IDs
80
+ if (conversationIds.length === 0) {
81
+ return { chatbotConversations: [] };
82
+ }
83
+ try {
84
+ return await getChatBotConversationsList({
85
+ organizationId,
86
+ chatbotId,
87
+ conversationIds,
88
+ baseUrl,
89
+ }).catch((error) => {
90
+ // Ignore any error from axios and return an empty list
91
+ console.error("Error fetching conversations (ignored):", error);
92
+ return { chatbotConversations: [] };
93
+ });
94
+ }
95
+ catch (error) {
96
+ console.error("Error fetching conversations (sync):", error);
97
+ return { chatbotConversations: [] };
98
+ }
99
+ }, [organizationId, chatbotId, conversationIds, baseUrl]);
100
+ const handleSendClick = () => {
101
+ if (!input.trim() || !canSendMessage)
102
+ return;
103
+ const userMessage = {
104
+ role: "user",
105
+ message: input,
106
+ id: Date.now().toString(),
107
+ unuseful: false,
108
+ hiddenFromUser: false,
109
+ };
110
+ const newMessages = [...messages, userMessage];
111
+ setMessages(newMessages);
112
+ setInput("");
113
+ setIsChatLoading(true);
114
+ setCanSendMessage(false);
115
+ const onData = async (data) => {
116
+ if (data.finalResponseWithUsageData) {
117
+ setIsChatLoading(false);
118
+ setCanSendMessage(true);
119
+ const { chatbotConversationId: newConversationId, messages: updatedMessages, } = data;
120
+ if (newConversationId) {
121
+ setChatbotConversationId(newConversationId);
122
+ await saveConversationIdToLocalStorage({
123
+ chatbotConversationId: newConversationId,
124
+ chatbotId,
125
+ organizationId,
126
+ });
127
+ refetchConversationIds();
128
+ if (selectedConversation &&
129
+ selectedConversation.chatbotConversationTitle ===
130
+ "New Conversation") {
131
+ setSelectedConversation({
132
+ ...selectedConversation,
133
+ chatbotConversationId: newConversationId,
134
+ chatbotConversationTitle: input.substring(0, 50) + (input.length > 50 ? "..." : ""),
135
+ messages: updatedMessages || newMessages,
136
+ });
137
+ }
138
+ }
139
+ if (updatedMessages) {
140
+ setMessages(updatedMessages);
141
+ }
142
+ }
143
+ if (data.message) {
144
+ setIsChatLoading(false);
145
+ setCanSendMessage(true);
146
+ const assistantMessage = {
147
+ role: "assistant",
148
+ message: data.message,
149
+ id: Date.now().toString(),
150
+ unuseful: false,
151
+ hiddenFromUser: false,
152
+ };
153
+ setMessages([...newMessages, assistantMessage]);
154
+ }
155
+ };
156
+ postSessionMessage(newMessages, onData).catch((error) => {
157
+ console.error(error);
158
+ setIsChatLoading(false);
159
+ setCanSendMessage(true);
160
+ });
161
+ };
162
+ const handleConversationSelect = (conversation) => {
163
+ setSelectedConversation(conversation);
164
+ setChatbotConversationId(conversation.chatbotConversationId);
165
+ const formattedMessages = conversation.messages.map((msg) => ({
166
+ ...msg,
167
+ id: msg.id || Date.now().toString(),
168
+ }));
169
+ setMessages(formattedMessages);
170
+ };
171
+ const handleNewChat = () => {
172
+ setSelectedConversation(null);
173
+ setChatbotConversationId(undefined);
174
+ setMessages([]);
175
+ setInput("");
176
+ const dateString = getUTCDateTime();
177
+ const newConversation = {
178
+ chatbotConversationId: Date.now(),
179
+ messages: [],
180
+ chatbotId: chatbotId,
181
+ chatbotConversationTitle: "New Conversation",
182
+ createdAt: dateString,
183
+ updatedAt: dateString,
184
+ totalCostSoFar: 0,
185
+ totalTokensSoFar: 0,
186
+ };
187
+ setSelectedConversation(newConversation);
188
+ };
189
+ const handleDeleteConversation = async (conversationId) => {
190
+ try {
191
+ const currentConversations = JSON.parse(localStorage.getItem(localStorageKey) || "[]") ?? [];
192
+ const updatedConversations = currentConversations.filter((id) => id !== conversationId);
193
+ localStorage.setItem(localStorageKey, JSON.stringify(updatedConversations));
194
+ if (selectedConversation?.chatbotConversationId === conversationId) {
195
+ setSelectedConversation(null);
196
+ setMessages([]);
197
+ setChatbotConversationId(undefined);
198
+ }
199
+ refetchConversationIds();
200
+ }
201
+ catch (error) {
202
+ console.error("Error deleting conversation:", error);
203
+ }
204
+ };
205
+ const setCurrentConversationMemory = async (memory) => {
206
+ console.log("Set conversation memory:", memory);
207
+ };
208
+ const allConversations = React.useMemo(() => {
209
+ const existingConversations = data?.chatbotConversations || [];
210
+ const newConversation = selectedConversation &&
211
+ selectedConversation.chatbotConversationTitle === "New Conversation"
212
+ ? selectedConversation
213
+ : null;
214
+ let conversations = [...existingConversations];
215
+ if (newConversation) {
216
+ conversations.push(newConversation);
217
+ }
218
+ return conversations.sort((a, b) => {
219
+ const dateA = new Date(a.updatedAt);
220
+ const dateB = new Date(b.updatedAt);
221
+ return dateB.getTime() - dateA.getTime();
222
+ });
223
+ }, [data?.chatbotConversations, selectedConversation]);
224
+ useImperativeHandle(ref, () => ({
225
+ handleSendClick,
226
+ handleNewChat,
227
+ }));
228
+ return (_jsxs("div", { className: "cmnd-conversations-panel", style: {
229
+ display: "flex",
230
+ height: "100%",
231
+ backgroundColor: colors.background,
232
+ color: colors.text,
233
+ ...customStyles?.panelStyle,
234
+ }, children: [_jsxs("div", { className: "cmnd-conversations-sidebar", style: {
235
+ width: isSidebarCollapsedFinal ? "50px" : "300px",
236
+ borderRight: `1px solid ${colors.border}`,
237
+ display: "flex",
238
+ flexDirection: "column",
239
+ backgroundColor: colors.sidebar,
240
+ transition: "width 0.3s ease",
241
+ ...customStyles?.sidebarStyle,
242
+ }, children: [_jsxs("div", { className: "cmnd-conversations-header", style: {
243
+ padding: isSidebarCollapsedFinal ? "12px 8px" : "16px",
244
+ borderBottom: `1px solid ${colors.border}`,
245
+ display: "flex",
246
+ justifyContent: isSidebarCollapsedFinal
247
+ ? "center"
248
+ : "space-between",
249
+ alignItems: "center",
250
+ flexDirection: isSidebarCollapsedFinal ? "column" : "row",
251
+ gap: isSidebarCollapsedFinal ? "8px" : "0",
252
+ ...customStyles?.headerStyle,
253
+ }, children: [!isSidebarCollapsedFinal && (_jsx("h3", { style: {
254
+ margin: 0,
255
+ fontSize: "16px",
256
+ fontWeight: "600",
257
+ color: colors.text,
258
+ }, children: "Conversations" })), _jsxs("div", { style: {
259
+ display: "flex",
260
+ gap: "8px",
261
+ flexDirection: isSidebarCollapsedFinal ? "column" : "row",
262
+ }, children: [_jsx("button", { className: "cmnd-toggle-sidebar-button", onClick: () => setIsSidebarCollapsedFinal((prev) => !prev), title: isSidebarCollapsedFinal
263
+ ? "Expand Sidebar"
264
+ : "Collapse Sidebar", 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(FiSidebar, { size: 16 }) }), _jsx("button", { className: "cmnd-new-chat-button", onClick: handleNewChat, title: "New Chat", style: {
281
+ background: colors.button,
282
+ border: "none",
283
+ color: theme === "light" ? "#ffffff" : colors.text,
284
+ padding: "8px",
285
+ borderRadius: "6px",
286
+ cursor: "pointer",
287
+ display: "flex",
288
+ alignItems: "center",
289
+ justifyContent: "center",
290
+ transition: "all 0.2s ease",
291
+ ...customStyles?.newChatButtonStyle,
292
+ }, onMouseEnter: (e) => {
293
+ e.currentTarget.style.backgroundColor = colors.buttonHover;
294
+ }, onMouseLeave: (e) => {
295
+ e.currentTarget.style.backgroundColor = colors.button;
296
+ }, children: _jsx(RiAddLine, { size: 16 }) })] })] }), _jsx("div", { className: "cmnd-conversation-list", style: {
297
+ flex: 1,
298
+ overflowY: "auto",
299
+ padding: "12px",
300
+ ...customStyles?.conversationListStyle,
301
+ }, children: isSidebarCollapsedFinal ? (_jsx("div", { style: {
302
+ textAlign: "center",
303
+ padding: "8px",
304
+ color: colors.secondaryText,
305
+ fontSize: "12px",
306
+ }, children: allConversations.length })) : loading && allConversations.length === 0 ? (_jsx("div", { style: {
307
+ textAlign: "center",
308
+ padding: "20px",
309
+ color: colors.secondaryText,
310
+ }, children: "Loading conversations..." })) : error && allConversations.length === 0 ? (_jsx("div", { style: {
311
+ textAlign: "center",
312
+ padding: "20px",
313
+ color: "#ff6b6b",
314
+ }, children: "Error loading conversations" })) : allConversations.length === 0 ? (_jsx("div", { style: {
315
+ textAlign: "center",
316
+ padding: "20px",
317
+ color: colors.secondaryText,
318
+ }, children: "No conversations yet" })) : (allConversations.map((conversation) => (_jsx(ConversationCard, { conversation: conversation, isActive: selectedConversation?.chatbotConversationId ===
319
+ conversation.chatbotConversationId, onClick: () => {
320
+ if (conversation.chatbotConversationTitle ===
321
+ "New Conversation") {
322
+ }
323
+ else {
324
+ handleConversationSelect(conversation);
325
+ }
326
+ }, onDelete: () => {
327
+ if (conversation.chatbotConversationTitle ===
328
+ "New Conversation") {
329
+ setSelectedConversation(null);
330
+ setMessages([]);
331
+ }
332
+ else {
333
+ handleDeleteConversation(conversation.chatbotConversationId);
334
+ }
335
+ }, theme: theme, customStyles: {
336
+ conversationCardStyle: customStyles?.conversationCardStyle,
337
+ activeConversationCardStyle: customStyles?.activeConversationCardStyle,
338
+ titleStyle: customStyles?.titleStyle,
339
+ dateStyle: customStyles?.dateStyle,
340
+ deleteButtonStyle: customStyles?.deleteButtonStyle,
341
+ } }, conversation.chatbotConversationId)))) })] }), _jsx("div", { className: "cmnd-chat-area", style: {
342
+ flex: 1,
343
+ display: "flex",
344
+ flexDirection: "column",
345
+ }, children: !selectedConversation ? (_jsx("div", { style: {
346
+ display: "flex",
347
+ alignItems: "center",
348
+ justifyContent: "center",
349
+ height: "100%",
350
+ color: colors.secondaryText,
351
+ fontSize: "16px",
352
+ textAlign: "center",
353
+ padding: "20px",
354
+ }, 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, inputRef: inputRef })) })] }));
355
+ });
@@ -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;
@@ -1,12 +1,13 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { MessageRole } from "../type.js";
2
+ import { MessageRole, } from "../type.js";
3
3
  import Chatbubble from "./Chatbubble.js";
4
- const LoadingBubble = ({ customStyles }) => {
4
+ const LoadingBubble = ({ customStyles, chatbotId, organizationId, theme, Components, }) => {
5
5
  const color = "white";
6
- return (_jsx(Chatbubble, { isLoadingBubble: true, customStyles: customStyles, message: _jsx("div", { className: "loading-container", children: _jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", xmlnsXlink: "http://www.w3.org/1999/xlink", style: {
7
- margin: "auto",
8
- display: "block",
9
- shapeRendering: "auto",
10
- }, width: "60px", height: "30px", viewBox: "0 0 100 100", preserveAspectRatio: "xMidYMid", children: [_jsxs("circle", { cx: "84", cy: "50", r: "10", fill: color, children: [_jsx("animate", { attributeName: "r", repeatCount: "indefinite", dur: "0.25s", calcMode: "spline", keyTimes: "0;1", values: "10;0", keySplines: "0 0.5 0.5 1", begin: "0s" }), _jsx("animate", { attributeName: "fill", repeatCount: "indefinite", dur: "1s", calcMode: "discrete", keyTimes: "0;0.25;0.5;0.75;1", values: color, begin: "0s" })] }), _jsxs("circle", { cx: "16", cy: "50", r: "10", fill: color, children: [_jsx("animate", { attributeName: "r", repeatCount: "indefinite", dur: "1s", calcMode: "spline", keyTimes: "0;0.25;0.5;0.75;1", values: "0;0;10;10;10", keySplines: "0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1", begin: "0s" }), _jsx("animate", { attributeName: "cx", repeatCount: "indefinite", dur: "1s", calcMode: "spline", keyTimes: "0;0.25;0.5;0.75;1", values: "16;16;16;50;84", keySplines: "0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1", begin: "0s" })] }), _jsxs("circle", { cx: "50", cy: "50", r: "10", fill: color, children: [_jsx("animate", { attributeName: "r", repeatCount: "indefinite", dur: "1s", calcMode: "spline", keyTimes: "0;0.25;0.5;0.75;1", values: "0;0;10;10;10", keySplines: "0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1", begin: "-0.25s" }), _jsx("animate", { attributeName: "cx", repeatCount: "indefinite", dur: "1s", calcMode: "spline", keyTimes: "0;0.25;0.5;0.75;1", values: "16;16;16;50;84", keySplines: "0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1", begin: "-0.25s" })] }), _jsxs("circle", { cx: "84", cy: "50", r: "10", fill: color, children: [_jsx("animate", { attributeName: "r", repeatCount: "indefinite", dur: "1s", calcMode: "spline", keyTimes: "0;0.25;0.5;0.75;1", values: "0;0;10;10;10", keySplines: "0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1", begin: "-0.5s" }), _jsx("animate", { attributeName: "cx", repeatCount: "indefinite", dur: "1s", calcMode: "spline", keyTimes: "0;0.25;0.5;0.75;1", values: "16;16;16;50;84", keySplines: "0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1", begin: "-0.5s" })] }), _jsxs("circle", { cx: "16", cy: "50", r: "10", fill: color, children: [_jsx("animate", { attributeName: "r", repeatCount: "indefinite", dur: "1s", calcMode: "spline", keyTimes: "0;0.25;0.5;0.75;1", values: "0;0;10;10;10", keySplines: "0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1", begin: "-0.75s" }), _jsx("animate", { attributeName: "cx", repeatCount: "indefinite", dur: "1s", calcMode: "spline", keyTimes: "0;0.25;0.5;0.75;1", values: "16;16;16;50;84", keySplines: "0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1", begin: "-0.75s" })] })] }) }), role: MessageRole.ASSISTANT, messages: [], postSessionMessage: () => { }, id: "__loading__", setMessages: () => { }, setChatbotConversationId: () => { }, setCanSendMessage: () => { }, setIsChatLoading: () => { }, scrollToBottom: () => { } }));
6
+ const defaultLoadingIndicator = (_jsx("div", { className: "loading-container", children: _jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", xmlnsXlink: "http://www.w3.org/1999/xlink", style: {
7
+ margin: "auto",
8
+ display: "block",
9
+ shapeRendering: "auto",
10
+ }, width: "60px", height: "30px", viewBox: "0 0 100 100", preserveAspectRatio: "xMidYMid", children: [_jsxs("circle", { cx: "84", cy: "50", r: "10", fill: "#000", children: [_jsx("animate", { attributeName: "r", repeatCount: "indefinite", dur: "0.25s", calcMode: "spline", keyTimes: "0;1", values: "10;0", keySplines: "0 0.5 0.5 1", begin: "0s" }), _jsx("animate", { attributeName: "fill", repeatCount: "indefinite", dur: "1s", calcMode: "discrete", keyTimes: "0;0.25;0.5;0.75;1", values: color, begin: "0s" })] }), _jsxs("circle", { cx: "16", cy: "50", r: "10", fill: color, children: [_jsx("animate", { attributeName: "r", repeatCount: "indefinite", dur: "1s", calcMode: "spline", keyTimes: "0;0.25;0.5;0.75;1", values: "0;0;10;10;10", keySplines: "0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1", begin: "0s" }), _jsx("animate", { attributeName: "cx", repeatCount: "indefinite", dur: "1s", calcMode: "spline", keyTimes: "0;0.25;0.5;0.75;1", values: "16;16;16;50;84", keySplines: "0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1", begin: "0s" })] }), _jsxs("circle", { cx: "50", cy: "50", r: "10", fill: color, children: [_jsx("animate", { attributeName: "r", repeatCount: "indefinite", dur: "1s", calcMode: "spline", keyTimes: "0;0.25;0.5;0.75;1", values: "0;0;10;10;10", keySplines: "0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1", begin: "-0.25s" }), _jsx("animate", { attributeName: "cx", repeatCount: "indefinite", dur: "1s", calcMode: "spline", keyTimes: "0;0.25;0.5;0.75;1", values: "16;16;16;50;84", keySplines: "0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1", begin: "-0.25s" })] }), _jsxs("circle", { cx: "84", cy: "50", r: "10", fill: color, children: [_jsx("animate", { attributeName: "r", repeatCount: "indefinite", dur: "1s", calcMode: "spline", keyTimes: "0;0.25;0.5;0.75;1", values: "0;0;10;10;10", keySplines: "0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1", begin: "-0.5s" }), _jsx("animate", { attributeName: "cx", repeatCount: "indefinite", dur: "1s", calcMode: "spline", keyTimes: "0;0.25;0.5;0.75;1", values: "16;16;16;50;84", keySplines: "0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1", begin: "-0.5s" })] }), _jsxs("circle", { cx: "16", cy: "50", r: "10", fill: color, children: [_jsx("animate", { attributeName: "r", repeatCount: "indefinite", dur: "1s", calcMode: "spline", keyTimes: "0;0.25;0.5;0.75;1", values: "0;0;10;10;10", keySplines: "0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1", begin: "-0.75s" }), _jsx("animate", { attributeName: "cx", repeatCount: "indefinite", dur: "1s", calcMode: "spline", keyTimes: "0;0.25;0.5;0.75;1", values: "16;16;16;50;84", keySplines: "0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1", begin: "-0.75s" })] })] }) }));
11
+ return (_jsx(Chatbubble, { chatbotId: chatbotId, organizationId: organizationId, isLoadingBubble: true, customStyles: customStyles, theme: theme, Components: Components, message: Components?.LoadingIndicator ? (_jsx(Components.LoadingIndicator, {})) : (defaultLoadingIndicator), role: MessageRole.ASSISTANT, messages: [], postSessionMessage: () => { }, id: "__loading__", setMessages: () => { }, setChatbotConversationId: () => { }, setCanSendMessage: () => { }, setIsChatLoading: () => { } }));
11
12
  };
12
13
  export default LoadingBubble;
@@ -0,0 +1,10 @@
1
+ import React from "react";
2
+ import { CustomStyles } from "../type.js";
3
+ interface ScrollToBottomButtonProps {
4
+ onClick: () => void;
5
+ isVisible: boolean;
6
+ theme?: "light" | "dark";
7
+ customStyles?: CustomStyles;
8
+ }
9
+ declare const ScrollToBottomButton: React.FC<ScrollToBottomButtonProps>;
10
+ export default ScrollToBottomButton;