@cmnd-ai/chatbot-react 1.7.1 → 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 (38) 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/CmndChatBot/index.d.ts +15 -4
  5. package/dist/CmndChatBot/index.js +4 -4
  6. package/dist/components/Chatbubble.d.ts +13 -3
  7. package/dist/components/Chatbubble.js +18 -17
  8. package/dist/components/Conversation.d.ts +7 -3
  9. package/dist/components/Conversation.js +3 -2
  10. package/dist/components/ConversationCard.d.ts +18 -0
  11. package/dist/components/ConversationCard.js +83 -0
  12. package/dist/components/ConversationsPanel/index.d.ts +33 -0
  13. package/dist/components/ConversationsPanel/index.js +333 -0
  14. package/dist/components/LoadingBubble.d.ts +14 -2
  15. package/dist/components/LoadingBubble.js +8 -7
  16. package/dist/components/ScrollToBottomButton.d.ts +10 -0
  17. package/dist/components/ScrollToBottomButton.js +57 -0
  18. package/dist/constants/endpoints.d.ts +5 -0
  19. package/dist/constants/endpoints.js +6 -0
  20. package/dist/hooks/use-fetch-data.d.ts +9 -0
  21. package/dist/hooks/use-fetch-data.js +32 -0
  22. package/dist/hooks/use-messages-scroll.d.ts +15 -0
  23. package/dist/hooks/use-messages-scroll.js +80 -0
  24. package/dist/index.d.ts +2 -1
  25. package/dist/index.js +1 -0
  26. package/dist/services/getChatBotConversationsList/index.d.ts +7 -0
  27. package/dist/services/getChatBotConversationsList/index.js +11 -0
  28. package/dist/styles/index.css +110 -0
  29. package/dist/type.d.ts +32 -0
  30. package/dist/utils/format_date/index.d.ts +2 -0
  31. package/dist/utils/format_date/index.js +32 -0
  32. package/dist/utils/getConversationLocalStorageKey/index.d.ts +5 -0
  33. package/dist/utils/getConversationLocalStorageKey/index.js +2 -0
  34. package/dist/utils/getUTCDateTime/index.d.ts +2 -0
  35. package/dist/utils/getUTCDateTime/index.js +11 -0
  36. package/dist/utils/saveConversationIdToLocalStorage/index.d.ts +6 -0
  37. package/dist/utils/saveConversationIdToLocalStorage/index.js +19 -0
  38. package/package.json +1 -1
@@ -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;
@@ -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;
@@ -0,0 +1,57 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { FiChevronDown } from "react-icons/fi";
3
+ const ScrollToBottomButton = ({ onClick, isVisible, theme = "light", customStyles, }) => {
4
+ const themeColors = {
5
+ light: {
6
+ background: "#1a1d24",
7
+ hover: "#2a2f3a",
8
+ icon: "#ffffff",
9
+ shadow: "rgba(0, 0, 0, 0.2)",
10
+ },
11
+ dark: {
12
+ background: "#1a1d24",
13
+ hover: "#2a2f3a",
14
+ icon: "#ffffff",
15
+ shadow: "rgba(0, 0, 0, 0.4)",
16
+ },
17
+ };
18
+ const colors = themeColors[theme];
19
+ const baseStyle = {
20
+ position: "fixed",
21
+ bottom: "100px",
22
+ right: "20px",
23
+ width: "48px",
24
+ height: "48px",
25
+ borderRadius: "50%",
26
+ backgroundColor: colors.background,
27
+ color: colors.icon,
28
+ border: "none",
29
+ cursor: "pointer",
30
+ display: "flex",
31
+ alignItems: "center",
32
+ justifyContent: "center",
33
+ boxShadow: `0 4px 12px ${colors.shadow}`,
34
+ transition: "all 0.2s ease-in-out",
35
+ opacity: isVisible ? 1 : 0,
36
+ visibility: isVisible ? "visible" : "hidden",
37
+ transform: isVisible ? "translateY(0)" : "translateY(10px)",
38
+ zIndex: 1000,
39
+ };
40
+ const hoverStyle = {
41
+ backgroundColor: colors.hover,
42
+ transform: "translateY(-2px)",
43
+ boxShadow: `0 6px 16px ${colors.shadow}`,
44
+ };
45
+ return (_jsx("button", { onClick: onClick, style: {
46
+ ...baseStyle,
47
+ ...customStyles?.scrollButtonStyle,
48
+ }, onMouseEnter: (e) => {
49
+ Object.assign(e.currentTarget.style, hoverStyle);
50
+ }, onMouseLeave: (e) => {
51
+ Object.assign(e.currentTarget.style, {
52
+ ...baseStyle,
53
+ ...customStyles?.scrollButtonStyle,
54
+ });
55
+ }, title: "Scroll to bottom", "aria-label": "Scroll to bottom", children: _jsx(FiChevronDown, { size: 20 }) }));
56
+ };
57
+ export default ScrollToBottomButton;
@@ -1,5 +1,10 @@
1
1
  declare const chatbot: {
2
2
  patchChatbotConversationMemory: (organizationId: number, chatbotId: number, chatbotConversationId: number) => string;
3
3
  deleteChatbotConversationMemory: (organizationId: number, chatbotId: number, chatbotConversationId: number, memoryKeyToDelete: string) => string;
4
+ getChatBotConversationsList: ({ organizationId, chatbotId, conversationIds, }: {
5
+ organizationId: number;
6
+ chatbotId: number;
7
+ conversationIds: number[];
8
+ }) => string;
4
9
  };
5
10
  export { chatbot };
@@ -1,5 +1,11 @@
1
1
  const chatbot = {
2
2
  patchChatbotConversationMemory: (organizationId, chatbotId, chatbotConversationId) => `/organizations/${organizationId}/chatbots/${chatbotId}/conversations/${chatbotConversationId}/memory`,
3
3
  deleteChatbotConversationMemory: (organizationId, chatbotId, chatbotConversationId, memoryKeyToDelete) => `/organizations/${organizationId}/chatbots/${chatbotId}/conversations/${chatbotConversationId}/memory/${memoryKeyToDelete}`,
4
+ getChatBotConversationsList: ({ organizationId, chatbotId, conversationIds, }) => {
5
+ const ids = Array.isArray(conversationIds)
6
+ ? conversationIds.join(",")
7
+ : conversationIds;
8
+ return `/organizations/${organizationId}/chatbots/${chatbotId}/conversations-list/${ids}`;
9
+ },
4
10
  };
5
11
  export { chatbot };
@@ -0,0 +1,9 @@
1
+ import { AxiosPromise } from "axios";
2
+ type UseFetchDataResult<T = any> = {
3
+ loading: boolean;
4
+ error: boolean;
5
+ data: T;
6
+ refetch: () => void;
7
+ };
8
+ declare const useFetchData: <T = any>(apiCallFn: () => AxiosPromise<T>, deps?: any[]) => UseFetchDataResult<T>;
9
+ export default useFetchData;
@@ -0,0 +1,32 @@
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */
2
+ /* eslint-disable react-hooks/exhaustive-deps */
3
+ import { useEffect, useState } from "react";
4
+ const useFetchData = (apiCallFn, deps = []) => {
5
+ const [loading, setLoading] = useState(true);
6
+ const [error, setError] = useState(false);
7
+ const [data, setData] = useState({});
8
+ const fetchData = async () => {
9
+ setLoading(true);
10
+ setError(false);
11
+ try {
12
+ const response = await apiCallFn();
13
+ setData(response.data);
14
+ }
15
+ catch {
16
+ setError(true);
17
+ }
18
+ finally {
19
+ setLoading(false);
20
+ }
21
+ };
22
+ useEffect(() => {
23
+ fetchData();
24
+ }, deps);
25
+ return {
26
+ loading,
27
+ error,
28
+ data,
29
+ refetch: fetchData,
30
+ };
31
+ };
32
+ export default useFetchData;