@fusioni/client-sdk 1.1.10 → 1.1.12

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.
package/dist/index.js CHANGED
@@ -4959,11 +4959,12 @@ const DocumentVideoGrid = ({ videos, attachedVideosLabel, }) => {
4959
4959
  // Module-level Set to track which message IDs have been animated
4960
4960
  // This persists across component unmounts/remounts (e.g., when chat closes and reopens)
4961
4961
  const animatedMessageIds = new Set();
4962
+ const TYPING_PREVIEW_CHARACTER_LIMIT = 200;
4962
4963
  const Message = ({ message, showThoughts = false, fontSize = 'text-sm', onDelete, onConfirmation, enableButtons = true, apiBaseUrl, apiKey, agencyId, currentLanguage = 'en', onOpenGallery }) => {
4963
4964
  const { t } = useTranslation(currentLanguage);
4964
4965
  const [displayedContent, setDisplayedContent] = react.useState('');
4965
4966
  const typingIntervalRef = react.useRef(null);
4966
- const typingSpeed = 15; // milliseconds per character
4967
+ const typingSpeed = 5; // milliseconds per character
4967
4968
  const enhanceMessageContent = (content) => {
4968
4969
  if (!content)
4969
4970
  return content;
@@ -5113,6 +5114,7 @@ const Message = ({ message, showThoughts = false, fontSize = 'text-sm', onDelete
5113
5114
  // Now animate through segments
5114
5115
  let segmentIndex = 0;
5115
5116
  let textIndex = 0;
5117
+ let typedCharacterCount = 0;
5116
5118
  const nextTextStep = (text, index) => {
5117
5119
  if (index >= text.length)
5118
5120
  return { nextIndex: index, slice: '' };
@@ -5149,6 +5151,11 @@ const Message = ({ message, showThoughts = false, fontSize = 'text-sm', onDelete
5149
5151
  typingIntervalRef.current = setTimeout(typeNextChar, 0);
5150
5152
  }
5151
5153
  else {
5154
+ if (typedCharacterCount >= TYPING_PREVIEW_CHARACTER_LIMIT) {
5155
+ setDisplayedContent(fullContent);
5156
+ animatedMessageIds.add(messageId);
5157
+ return;
5158
+ }
5152
5159
  // Text segments are typed character by character
5153
5160
  if (textIndex < segment.content.length) {
5154
5161
  const step = nextTextStep(segment.content, textIndex);
@@ -5166,6 +5173,14 @@ const Message = ({ message, showThoughts = false, fontSize = 'text-sm', onDelete
5166
5173
  content += step.slice;
5167
5174
  setDisplayedContent(content);
5168
5175
  textIndex = step.nextIndex;
5176
+ typedCharacterCount++;
5177
+ if (typedCharacterCount >= TYPING_PREVIEW_CHARACTER_LIMIT) {
5178
+ typingIntervalRef.current = setTimeout(() => {
5179
+ setDisplayedContent(fullContent);
5180
+ animatedMessageIds.add(messageId);
5181
+ }, typingSpeed);
5182
+ return;
5183
+ }
5169
5184
  typingIntervalRef.current = setTimeout(typeNextChar, typingSpeed);
5170
5185
  }
5171
5186
  else {
@@ -5705,11 +5720,9 @@ const FloatingButton = ({ isOpen, onClick, position = 'bottom-right', primaryCol
5705
5720
  const [showAttentionSequence, setShowAttentionSequence] = react.useState(false);
5706
5721
  const [isAttentionActive, setIsAttentionActive] = react.useState(false);
5707
5722
  react.useEffect(() => {
5708
- // Sophisticated entrance animation
5709
5723
  const entranceTimer = setTimeout(() => {
5710
5724
  setIsVisible(true);
5711
5725
  }, 200);
5712
- // Periodic attention sequence (every 15 seconds)
5713
5726
  const attentionInterval = setInterval(() => {
5714
5727
  if (!isHovered && !isOpen) {
5715
5728
  setShowAttentionSequence(true);
@@ -6093,6 +6106,33 @@ function useIsMobileLayout() {
6093
6106
  return isMobile;
6094
6107
  }
6095
6108
 
6109
+ const getStoredConversationIdKey = (agencyId) => `fusioni:selectedConversationId:${agencyId}`;
6110
+ const readStoredConversationId = (agencyId) => {
6111
+ if (typeof window === 'undefined')
6112
+ return null;
6113
+ try {
6114
+ return window.sessionStorage.getItem(getStoredConversationIdKey(agencyId));
6115
+ }
6116
+ catch {
6117
+ return null;
6118
+ }
6119
+ };
6120
+ const writeStoredConversationId = (agencyId, conversationId) => {
6121
+ if (typeof window === 'undefined')
6122
+ return;
6123
+ try {
6124
+ const key = getStoredConversationIdKey(agencyId);
6125
+ if (conversationId) {
6126
+ window.sessionStorage.setItem(key, conversationId);
6127
+ }
6128
+ else {
6129
+ window.sessionStorage.removeItem(key);
6130
+ }
6131
+ }
6132
+ catch {
6133
+ // Storage can be unavailable in restricted browser contexts.
6134
+ }
6135
+ };
6096
6136
  const ChatWidget = react.forwardRef(function ChatWidget({ config, onMessageSent, onMessageReceived, onConversationCreated, onConversationDeleted, onError }, ref) {
6097
6137
  const [languageOverride, setLanguageOverride] = react.useState(null);
6098
6138
  const [isOpen, setIsOpen] = react.useState(false);
@@ -6107,12 +6147,15 @@ const ChatWidget = react.forwardRef(function ChatWidget({ config, onMessageSent,
6107
6147
  const [isDeleteDialogOpen, setIsDeleteDialogOpen] = react.useState(false);
6108
6148
  const [messageToDelete, setMessageToDelete] = react.useState(null);
6109
6149
  const [isDeleteMessageDialogOpen, setIsDeleteMessageDialogOpen] = react.useState(false);
6150
+ const [hasLoadedConversations, setHasLoadedConversations] = react.useState(false);
6110
6151
  // Refs
6111
6152
  const floatingButtonRef = react.useRef(null);
6153
+ const restoredConversationIdRef = react.useRef(null);
6112
6154
  const translationDefault = languageOverride ?? mergedConfig?.language ?? config.language ?? 'en';
6113
6155
  // Translation and language management - use merged config or fallback to user config
6114
6156
  const { t, currentLanguage, changeLanguage } = useTranslation(translationDefault);
6115
- const { conversations, currentConversation, messages, streamMessages, setCurrentConversation, setStreamMessages, addMessage, updateMessage, removeMessage, removeOptimisticUserMessages, truncateMessagesAt, addConversation, updateConversation, removeConversation, loadConversations, loadMessages, clearMessages } = useChatState(mergedConfig?.agencyId || config.agencyId);
6157
+ const activeAgencyId = mergedConfig?.agencyId || config.agencyId;
6158
+ const { conversations, currentConversation, messages, streamMessages, setCurrentConversation, setStreamMessages, addMessage, updateMessage, removeMessage, removeOptimisticUserMessages, truncateMessagesAt, addConversation, updateConversation, removeConversation, loadConversations, loadMessages, clearMessages } = useChatState(activeAgencyId);
6116
6159
  const { theme, toggleTheme, setTheme } = useTheme(mergedConfig?.theme || config.theme);
6117
6160
  const isMobileLayout = useIsMobileLayout();
6118
6161
  const handleLanguageChange = react.useCallback((language) => {
@@ -6179,12 +6222,22 @@ const ChatWidget = react.forwardRef(function ChatWidget({ config, onMessageSent,
6179
6222
  }, [config, onError, t]);
6180
6223
  // Load initial conversations
6181
6224
  react.useEffect(() => {
6182
- if (mergedConfig?.agencyId) {
6183
- loadConversations().then();
6225
+ if (activeAgencyId) {
6226
+ let isCancelled = false;
6227
+ restoredConversationIdRef.current = null;
6228
+ setHasLoadedConversations(false);
6229
+ loadConversations().finally(() => {
6230
+ if (!isCancelled) {
6231
+ setHasLoadedConversations(true);
6232
+ }
6233
+ });
6234
+ return () => {
6235
+ isCancelled = true;
6236
+ };
6184
6237
  }
6185
- }, [mergedConfig?.agencyId, loadConversations]);
6238
+ }, [activeAgencyId, loadConversations]);
6186
6239
  // SSE connection for real-time updates - only when a chat panel is open
6187
- useSSE(mergedConfig?.agencyId || config.agencyId, (data) => {
6240
+ useSSE(activeAgencyId, (data) => {
6188
6241
  // Same as fusioni-web chat.component: latest SSE line replaces stream (single loading row updates)
6189
6242
  if (data?.data != null && String(data.data).trim() !== '') {
6190
6243
  setStreamMessages([String(data.data)]);
@@ -6208,6 +6261,7 @@ const ChatWidget = react.forwardRef(function ChatWidget({ config, onMessageSent,
6208
6261
  const handleCreateConversation = react.useCallback(() => {
6209
6262
  if (!mergedConfig)
6210
6263
  return;
6264
+ writeStoredConversationId(activeAgencyId, null);
6211
6265
  // Create a new conversation with null ID - will be created on server when first message is sent
6212
6266
  const newConversation = {
6213
6267
  id: null,
@@ -6223,7 +6277,7 @@ const ChatWidget = react.forwardRef(function ChatWidget({ config, onMessageSent,
6223
6277
  // Auto-hide conversation list when a new conversation is created
6224
6278
  setIsConversationListOpen(false);
6225
6279
  onConversationCreated?.(newConversation);
6226
- }, [mergedConfig, addConversation, setCurrentConversation, clearMessages, onConversationCreated, t]);
6280
+ }, [activeAgencyId, mergedConfig, addConversation, setCurrentConversation, clearMessages, onConversationCreated, t]);
6227
6281
  const handleSelectConversation = react.useCallback(async (conversation) => {
6228
6282
  try {
6229
6283
  setIsLoading(true);
@@ -6231,6 +6285,9 @@ const ChatWidget = react.forwardRef(function ChatWidget({ config, onMessageSent,
6231
6285
  clearMessages();
6232
6286
  setStreamMessages([]);
6233
6287
  setCurrentConversation(conversation);
6288
+ if (conversation.id) {
6289
+ writeStoredConversationId(activeAgencyId, conversation.id);
6290
+ }
6234
6291
  // Auto-hide conversation list when a conversation is selected
6235
6292
  setIsConversationListOpen(false);
6236
6293
  if (conversation.id) {
@@ -6245,7 +6302,51 @@ const ChatWidget = react.forwardRef(function ChatWidget({ config, onMessageSent,
6245
6302
  finally {
6246
6303
  setIsLoading(false);
6247
6304
  }
6248
- }, [setCurrentConversation, loadMessages, clearMessages, onError]);
6305
+ }, [activeAgencyId, setCurrentConversation, loadMessages, clearMessages, onError, t]);
6306
+ react.useEffect(() => {
6307
+ if (!hasLoadedConversations || !activeAgencyId || currentConversation) {
6308
+ return;
6309
+ }
6310
+ const storedConversationId = readStoredConversationId(activeAgencyId);
6311
+ if (!storedConversationId || restoredConversationIdRef.current === storedConversationId) {
6312
+ return;
6313
+ }
6314
+ restoredConversationIdRef.current = storedConversationId;
6315
+ let isCancelled = false;
6316
+ const restoreConversation = async () => {
6317
+ let storedConversation = conversations.find((conversation) => conversation.id === storedConversationId);
6318
+ if (!storedConversation) {
6319
+ try {
6320
+ storedConversation = await getConversationService().getConversation(storedConversationId);
6321
+ }
6322
+ catch {
6323
+ storedConversation = undefined;
6324
+ }
6325
+ }
6326
+ if (isCancelled) {
6327
+ return;
6328
+ }
6329
+ if (!storedConversation) {
6330
+ writeStoredConversationId(activeAgencyId, null);
6331
+ return;
6332
+ }
6333
+ if (!conversations.some((conversation) => conversation.id === storedConversation?.id)) {
6334
+ addConversation(storedConversation);
6335
+ }
6336
+ handleSelectConversation(storedConversation);
6337
+ };
6338
+ restoreConversation();
6339
+ return () => {
6340
+ isCancelled = true;
6341
+ };
6342
+ }, [
6343
+ addConversation,
6344
+ activeAgencyId,
6345
+ conversations,
6346
+ currentConversation,
6347
+ handleSelectConversation,
6348
+ hasLoadedConversations
6349
+ ]);
6249
6350
  const handleDeleteConversation = react.useCallback((conversationId) => {
6250
6351
  setConversationToDelete(conversationId);
6251
6352
  setIsDeleteDialogOpen(true);
@@ -6258,6 +6359,9 @@ const ChatWidget = react.forwardRef(function ChatWidget({ config, onMessageSent,
6258
6359
  const conversationService = getConversationService();
6259
6360
  await conversationService.deleteConversation(conversationToDelete);
6260
6361
  removeConversation(conversationToDelete);
6362
+ if (readStoredConversationId(activeAgencyId) === conversationToDelete) {
6363
+ writeStoredConversationId(activeAgencyId, null);
6364
+ }
6261
6365
  if (currentConversation?.id === conversationToDelete) {
6262
6366
  setCurrentConversation(null);
6263
6367
  clearMessages();
@@ -6279,7 +6383,7 @@ const ChatWidget = react.forwardRef(function ChatWidget({ config, onMessageSent,
6279
6383
  finally {
6280
6384
  setIsLoading(false);
6281
6385
  }
6282
- }, [conversationToDelete, removeConversation, currentConversation, setCurrentConversation, clearMessages, setStreamMessages, onConversationDeleted, onError, t]);
6386
+ }, [activeAgencyId, conversationToDelete, removeConversation, currentConversation, setCurrentConversation, clearMessages, setStreamMessages, onConversationDeleted, onError, t]);
6283
6387
  const cancelDeleteConversation = react.useCallback(() => {
6284
6388
  setIsDeleteDialogOpen(false);
6285
6389
  setConversationToDelete(null);
@@ -6287,21 +6391,7 @@ const ChatWidget = react.forwardRef(function ChatWidget({ config, onMessageSent,
6287
6391
  const handleSendMessage = react.useCallback(async (content, image, audio, messageId) => {
6288
6392
  if (!mergedConfig)
6289
6393
  return;
6290
- // Debug logging for conversation state
6291
- console.log('🔍 ChatWidget.handleSendMessage - Starting message send:', {
6292
- currentConversation: currentConversation,
6293
- conversationId: currentConversation?.id,
6294
- content: content?.substring(0, 100) + (content?.length > 100 ? '...' : ''),
6295
- hasImage: !!image,
6296
- hasAudio: !!audio,
6297
- agencyId: mergedConfig.agencyId
6298
- });
6299
6394
  if (!currentConversation || (!content.trim() && !audio)) {
6300
- console.warn('⚠️ ChatWidget.handleSendMessage - Early return:', {
6301
- hasCurrentConversation: !!currentConversation,
6302
- hasContent: !!content?.trim(),
6303
- hasAudio: !!audio
6304
- });
6305
6395
  return;
6306
6396
  }
6307
6397
  try {
@@ -6309,18 +6399,11 @@ const ChatWidget = react.forwardRef(function ChatWidget({ config, onMessageSent,
6309
6399
  let conversationId = currentConversation.id;
6310
6400
  // If this is a new conversation (null ID), create it on the server first
6311
6401
  if (!conversationId) {
6312
- console.log('🔍 ChatWidget.handleSendMessage - Creating server conversation for new conversation:', {
6313
- agencyId: mergedConfig.agencyId
6314
- });
6315
6402
  const conversationService = getConversationService();
6316
6403
  conversationId = await conversationService.createConversation({
6317
6404
  title: t('chat.conversations.newConversation'),
6318
6405
  agency_id: mergedConfig.agencyId,
6319
6406
  });
6320
- console.log('🔍 ChatWidget.handleSendMessage - Server conversation created:', {
6321
- conversationId: conversationId,
6322
- conversationIdType: typeof conversationId
6323
- });
6324
6407
  // Update the conversation with the real server ID
6325
6408
  const updatedConversation = {
6326
6409
  ...currentConversation,
@@ -6329,10 +6412,7 @@ const ChatWidget = react.forwardRef(function ChatWidget({ config, onMessageSent,
6329
6412
  // Update the conversation in the list and set as current
6330
6413
  updateConversation(updatedConversation.id, updatedConversation);
6331
6414
  setCurrentConversation(updatedConversation);
6332
- console.log('🔍 ChatWidget.handleSendMessage - Conversation ID updated:', {
6333
- conversationId: conversationId,
6334
- updatedConversation: updatedConversation
6335
- });
6415
+ writeStoredConversationId(activeAgencyId, conversationId);
6336
6416
  }
6337
6417
  // Clear stream messages for new conversation
6338
6418
  setStreamMessages([]);
@@ -6386,7 +6466,6 @@ const ChatWidget = react.forwardRef(function ChatWidget({ config, onMessageSent,
6386
6466
  if (userMessage) {
6387
6467
  onMessageSent?.(userMessage);
6388
6468
  }
6389
- // Debug logging before pipeline execution
6390
6469
  const pipelineRequest = {
6391
6470
  conversation_id: conversationId,
6392
6471
  agency_id: mergedConfig.agencyId,
@@ -6395,14 +6474,6 @@ const ChatWidget = react.forwardRef(function ChatWidget({ config, onMessageSent,
6395
6474
  audio,
6396
6475
  message_id: messageId
6397
6476
  };
6398
- console.log('🔍 ChatWidget.handleSendMessage - About to call executePipeline:', {
6399
- conversationId: conversationId,
6400
- conversationIdType: typeof conversationId,
6401
- conversationIdLength: conversationId?.length,
6402
- isNewConversation: !conversationId,
6403
- pipelineRequest: pipelineRequest,
6404
- currentConversation: currentConversation
6405
- });
6406
6477
  // Execute pipeline - this calls /pipeline/${agency_id}/exec
6407
6478
  const pipelineService = getPipelineService();
6408
6479
  const response = await pipelineService.executePipeline(pipelineRequest);
@@ -6454,6 +6525,7 @@ const ChatWidget = react.forwardRef(function ChatWidget({ config, onMessageSent,
6454
6525
  }
6455
6526
  }, [
6456
6527
  currentConversation,
6528
+ activeAgencyId,
6457
6529
  mergedConfig,
6458
6530
  messages,
6459
6531
  addMessage,
@@ -6613,10 +6685,7 @@ const ChatWidget = react.forwardRef(function ChatWidget({ config, onMessageSent,
6613
6685
  if (error) {
6614
6686
  return (jsxRuntime.jsxs("div", { className: "fusioni-chat-error", children: [jsxRuntime.jsxs("p", { children: [t('common.error'), ": ", error] }), jsxRuntime.jsx("button", { onClick: () => setError(null), children: t('chat.errors.retry') })] }));
6615
6687
  }
6616
- // Debug: Log the primary color and button variant being applied
6617
- console.log('Primary color being applied:', mergedConfig.primaryColor || '#6366f1');
6618
- console.log('Button variant being applied:', mergedConfig.buttonVariant || 'glass');
6619
- return (jsxRuntime.jsxs("div", { className: `fusioni-chat-widget ${theme}`, style: { '--primary-color': mergedConfig.primaryColor || '#6366f1' }, children: [jsxRuntime.jsx(FloatingButton, { isOpen: isOpen, onClick: handleToggleChat, position: mergedConfig.position || 'bottom-right', primaryColor: mergedConfig.primaryColor, buttonRef: floatingButtonRef, variant: mergedConfig.buttonVariant || 'glass', shouldDisplay: !hasConfigError && (!isMobileLayout || !isOpen) }), isOpen && (jsxRuntime.jsx(ChatPanel, { isOpen: isOpen, onClose: () => setIsOpen(false), position: mergedConfig.position || 'bottom-right', isFullscreen: isFullscreen, floatingButtonRef: floatingButtonRef, children: jsxRuntime.jsxs("div", { className: "fusioni-chat-container", children: [mergedConfig.showConversationList !== false && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("div", { className: `fusioni-conversation-backdrop ${isConversationListOpen ? 'open' : ''}`, onClick: () => setIsConversationListOpen(false) }), jsxRuntime.jsx(ConversationList, { conversations: conversations, selectedConversationId: currentConversation?.id || undefined, onSelectConversation: handleSelectConversation, onDeleteConversation: handleDeleteConversation, onCreateConversation: handleCreateConversation, isOpen: isConversationListOpen, currentLanguage: currentLanguage })] })), jsxRuntime.jsxs("div", { className: "fusioni-chat-main", children: [jsxRuntime.jsxs("div", { className: "fusioni-chat-main-header", children: [mergedConfig.showConversationList !== false ? (jsxRuntime.jsxs("button", { type: "button", onClick: handleToggleConversationList, className: `fusioni-conversation-toggle ${isConversationListOpen ? 'open' : ''}`, children: [jsxRuntime.jsx("svg", { className: "fusioni-conversation-toggle-icon", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: jsxRuntime.jsx("path", { d: "M3 12h18M3 6h18M3 18h18" }) }), t('chat.conversations.title')] })) : (jsxRuntime.jsx("span", { className: "fusioni-chat-main-header-title", children: t('chat.title') })), jsxRuntime.jsxs("div", { className: "fusioni-header-actions", children: [isMobileLayout && (jsxRuntime.jsx("button", { type: "button", onClick: () => setIsOpen(false), className: "fusioni-btn fusioni-btn-icon fusioni-chat-toolbar-close-mobile", title: t('common.close'), "aria-label": t('common.close'), children: jsxRuntime.jsx("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", "aria-hidden": "true", children: jsxRuntime.jsx("path", { d: "M18 6L6 18M6 6L18 18", strokeLinecap: "round", strokeLinejoin: "round" }) }) })), mergedConfig.showThemeToggle !== false && (jsxRuntime.jsx("button", { type: "button", onClick: toggleTheme, className: "fusioni-btn fusioni-btn-icon", title: theme === 'dark' ? t('chat.theme.light') : t('chat.theme.dark'), children: theme === 'dark' ? (jsxRuntime.jsxs("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [jsxRuntime.jsx("circle", { cx: "12", cy: "12", r: "5" }), jsxRuntime.jsx("line", { x1: "12", y1: "1", x2: "12", y2: "3" }), jsxRuntime.jsx("line", { x1: "12", y1: "21", x2: "12", y2: "23" }), jsxRuntime.jsx("line", { x1: "4.22", y1: "4.22", x2: "5.64", y2: "5.64" }), jsxRuntime.jsx("line", { x1: "18.36", y1: "18.36", x2: "19.78", y2: "19.78" }), jsxRuntime.jsx("line", { x1: "1", y1: "12", x2: "3", y2: "12" }), jsxRuntime.jsx("line", { x1: "21", y1: "12", x2: "23", y2: "12" }), jsxRuntime.jsx("line", { x1: "4.22", y1: "19.78", x2: "5.64", y2: "18.36" }), jsxRuntime.jsx("line", { x1: "18.36", y1: "5.64", x2: "19.78", y2: "4.22" })] })) : (jsxRuntime.jsx("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: jsxRuntime.jsx("path", { d: "M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z" }) })) })), mergedConfig.showFullscreenToggle !== false && (jsxRuntime.jsx("button", { type: "button", onClick: handleToggleFullscreen, className: "fusioni-btn fusioni-btn-icon", title: isFullscreen ? t('chat.fullscreen.exit') : t('chat.fullscreen.enter'), children: isFullscreen ? (jsxRuntime.jsx("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: jsxRuntime.jsx("path", { d: "M8 3V5M8 3H5M8 3L3 8M16 3V5M16 3H19M16 3L21 8M8 21V19M8 21H5M8 21L3 16M16 21V19M16 21H19M16 21L21 16" }) })) : (jsxRuntime.jsx("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: jsxRuntime.jsx("path", { d: "M8 3H5C4.46957 3 3.96086 3.21071 3.58579 3.58579C3.21071 3.96086 3 4.46957 3 5V8M21 8V5C21 4.46957 20.7893 3.96086 20.4142 3.58579C20.0391 3.21071 19.5304 3 19 3H16M16 21H19C19.5304 21 20.0391 20.7893 20.4142 20.4142C20.7893 20.0391 21 19.5304 21 19V16M3 16V19C3 19.5304 3.21071 20.0391 3.58579 20.4142C3.96086 20.7893 4.46957 21 5 21H8" }) })) })), mergedConfig.showLanguageSwitcher !== false && (jsxRuntime.jsx(LanguageSwitcher, { currentLanguage: currentLanguage, onLanguageChange: handleLanguageChange }))] })] }), currentConversation ? (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(MessageList, { messages: messages, streamMessages: streamMessages, showThoughts: false, onDeleteMessage: handleDeleteMessage, onEditMessage: handleEditMessage, onConfirmation: handleConfirmation, enableButtons: !isLoading, apiBaseUrl: mergedConfig.apiBaseUrl, apiKey: mergedConfig.accessToken, agencyId: mergedConfig.agencyId, currentLanguage: currentLanguage, theme: theme }), jsxRuntime.jsx(ChatInput, { onSendMessage: handleSendMessage, onFileUpload: handleFileUpload, disabled: isLoading, placeholder: t('chat.input.placeholder'), enableAudioRecording: mergedConfig.enableAudioRecording !== false, enableFileUpload: mergedConfig.enableFileUpload !== false, maxFileSize: mergedConfig.maxFileSize || 10, allowedFileTypes: mergedConfig.allowedFileTypes || ['image/*'], currentLanguage: currentLanguage })] })) : (jsxRuntime.jsx("div", { className: "fusioni-chat-welcome", children: jsxRuntime.jsxs("div", { className: "fusioni-chat-welcome-content", children: [jsxRuntime.jsx("h3", { children: t('chat.welcome.title') }), jsxRuntime.jsx("p", { children: t('chat.welcome.description') }), jsxRuntime.jsx("button", { onClick: handleCreateConversation, disabled: isLoading, className: "fusioni-btn fusioni-btn-primary", children: isLoading ? t('chat.welcome.creating') : t('chat.welcome.startButton') })] }) }))] })] }) })), jsxRuntime.jsx(ConfirmationDialog, { isOpen: isDeleteDialogOpen, title: t('chat.conversations.deleteConfirm.title'), message: t('chat.conversations.deleteConfirm.message'), confirmText: t('chat.conversations.deleteConfirm.confirm'), cancelText: t('chat.conversations.deleteConfirm.cancel'), onConfirm: confirmDeleteConversation, onCancel: cancelDeleteConversation, currentLanguage: currentLanguage, variant: "danger" }), jsxRuntime.jsx(ConfirmationDialog, { isOpen: isDeleteMessageDialogOpen, title: t('chat.messages.deleteConfirm.title'), message: t('chat.messages.deleteConfirm.message'), confirmText: t('chat.messages.deleteConfirm.confirm'), cancelText: t('chat.messages.deleteConfirm.cancel'), onConfirm: confirmDeleteMessage, onCancel: cancelDeleteMessage, currentLanguage: currentLanguage, variant: "danger" })] }));
6688
+ return (jsxRuntime.jsxs("div", { className: `fusioni-chat-widget ${theme}`, style: { '--primary-color': mergedConfig.primaryColor || '#6366f1' }, children: [jsxRuntime.jsx(FloatingButton, { isOpen: isOpen, onClick: handleToggleChat, position: mergedConfig.position || 'bottom-right', primaryColor: mergedConfig.primaryColor, buttonRef: floatingButtonRef, variant: mergedConfig.buttonVariant || 'glass', shouldDisplay: !hasConfigError && (!isMobileLayout || !isOpen) }), isOpen && (jsxRuntime.jsx(ChatPanel, { isOpen: isOpen, onClose: () => setIsOpen(false), position: mergedConfig.position || 'bottom-right', isFullscreen: isFullscreen, floatingButtonRef: floatingButtonRef, children: jsxRuntime.jsxs("div", { className: "fusioni-chat-container", children: [mergedConfig.showConversationList !== false && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("div", { className: `fusioni-conversation-backdrop ${isConversationListOpen ? 'open' : ''}`, onClick: () => setIsConversationListOpen(false) }), jsxRuntime.jsx(ConversationList, { conversations: conversations, selectedConversationId: currentConversation?.id || undefined, onSelectConversation: handleSelectConversation, onDeleteConversation: handleDeleteConversation, onCreateConversation: handleCreateConversation, isOpen: isConversationListOpen, currentLanguage: currentLanguage })] })), jsxRuntime.jsxs("div", { className: "fusioni-chat-main", children: [jsxRuntime.jsxs("div", { className: "fusioni-chat-main-header", children: [mergedConfig.showConversationList !== false ? (jsxRuntime.jsxs("button", { type: "button", onClick: handleToggleConversationList, className: `fusioni-conversation-toggle ${isConversationListOpen ? 'open' : ''}`, children: [jsxRuntime.jsx("svg", { className: "fusioni-conversation-toggle-icon", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: jsxRuntime.jsx("path", { d: "M3 12h18M3 6h18M3 18h18" }) }), t('chat.conversations.title')] })) : (jsxRuntime.jsx("span", { className: "fusioni-chat-main-header-title", children: t('chat.title') })), jsxRuntime.jsxs("div", { className: "fusioni-header-actions", children: [mergedConfig.showThemeToggle !== false && (jsxRuntime.jsx("button", { type: "button", onClick: toggleTheme, className: "fusioni-btn fusioni-btn-icon", title: theme === 'dark' ? t('chat.theme.light') : t('chat.theme.dark'), children: theme === 'dark' ? (jsxRuntime.jsxs("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [jsxRuntime.jsx("circle", { cx: "12", cy: "12", r: "5" }), jsxRuntime.jsx("line", { x1: "12", y1: "1", x2: "12", y2: "3" }), jsxRuntime.jsx("line", { x1: "12", y1: "21", x2: "12", y2: "23" }), jsxRuntime.jsx("line", { x1: "4.22", y1: "4.22", x2: "5.64", y2: "5.64" }), jsxRuntime.jsx("line", { x1: "18.36", y1: "18.36", x2: "19.78", y2: "19.78" }), jsxRuntime.jsx("line", { x1: "1", y1: "12", x2: "3", y2: "12" }), jsxRuntime.jsx("line", { x1: "21", y1: "12", x2: "23", y2: "12" }), jsxRuntime.jsx("line", { x1: "4.22", y1: "19.78", x2: "5.64", y2: "18.36" }), jsxRuntime.jsx("line", { x1: "18.36", y1: "5.64", x2: "19.78", y2: "4.22" })] })) : (jsxRuntime.jsx("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: jsxRuntime.jsx("path", { d: "M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z" }) })) })), mergedConfig.showFullscreenToggle !== false && (jsxRuntime.jsx("button", { type: "button", onClick: handleToggleFullscreen, className: "fusioni-btn fusioni-btn-icon", title: isFullscreen ? t('chat.fullscreen.exit') : t('chat.fullscreen.enter'), children: isFullscreen ? (jsxRuntime.jsx("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: jsxRuntime.jsx("path", { d: "M8 3V5M8 3H5M8 3L3 8M16 3V5M16 3H19M16 3L21 8M8 21V19M8 21H5M8 21L3 16M16 21V19M16 21H19M16 21L21 16" }) })) : (jsxRuntime.jsx("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: jsxRuntime.jsx("path", { d: "M8 3H5C4.46957 3 3.96086 3.21071 3.58579 3.58579C3.21071 3.96086 3 4.46957 3 5V8M21 8V5C21 4.46957 20.7893 3.96086 20.4142 3.58579C20.0391 3.21071 19.5304 3 19 3H16M16 21H19C19.5304 21 20.0391 20.7893 20.4142 20.4142C20.7893 20.0391 21 19.5304 21 19V16M3 16V19C3 19.5304 3.21071 20.0391 3.58579 20.4142C3.96086 20.7893 4.46957 21 5 21H8" }) })) })), mergedConfig.showLanguageSwitcher !== false && (jsxRuntime.jsx(LanguageSwitcher, { currentLanguage: currentLanguage, onLanguageChange: handleLanguageChange })), jsxRuntime.jsx("button", { type: "button", onClick: () => setIsOpen(false), className: "fusioni-btn fusioni-btn-icon fusioni-chat-toolbar-close-mobile", title: t('common.close'), "aria-label": t('common.close'), children: jsxRuntime.jsx("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", "aria-hidden": "true", children: jsxRuntime.jsx("path", { d: "M18 6L6 18M6 6L18 18", strokeLinecap: "round", strokeLinejoin: "round" }) }) })] })] }), currentConversation ? (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(MessageList, { messages: messages, streamMessages: streamMessages, showThoughts: false, onDeleteMessage: handleDeleteMessage, onEditMessage: handleEditMessage, onConfirmation: handleConfirmation, enableButtons: !isLoading, apiBaseUrl: mergedConfig.apiBaseUrl, apiKey: mergedConfig.accessToken, agencyId: mergedConfig.agencyId, currentLanguage: currentLanguage, theme: theme }), jsxRuntime.jsx(ChatInput, { onSendMessage: handleSendMessage, onFileUpload: handleFileUpload, disabled: isLoading, placeholder: t('chat.input.placeholder'), enableAudioRecording: mergedConfig.enableAudioRecording !== false, enableFileUpload: mergedConfig.enableFileUpload !== false, maxFileSize: mergedConfig.maxFileSize || 10, allowedFileTypes: mergedConfig.allowedFileTypes || ['image/*'], currentLanguage: currentLanguage })] })) : (jsxRuntime.jsx("div", { className: "fusioni-chat-welcome", children: jsxRuntime.jsxs("div", { className: "fusioni-chat-welcome-content", children: [jsxRuntime.jsx("h3", { children: t('chat.welcome.title') }), jsxRuntime.jsx("p", { children: t('chat.welcome.description') }), jsxRuntime.jsx("button", { onClick: handleCreateConversation, disabled: isLoading, className: "fusioni-btn fusioni-btn-primary", children: isLoading ? t('chat.welcome.creating') : t('chat.welcome.startButton') })] }) }))] })] }) })), jsxRuntime.jsx(ConfirmationDialog, { isOpen: isDeleteDialogOpen, title: t('chat.conversations.deleteConfirm.title'), message: t('chat.conversations.deleteConfirm.message'), confirmText: t('chat.conversations.deleteConfirm.confirm'), cancelText: t('chat.conversations.deleteConfirm.cancel'), onConfirm: confirmDeleteConversation, onCancel: cancelDeleteConversation, currentLanguage: currentLanguage, variant: "danger" }), jsxRuntime.jsx(ConfirmationDialog, { isOpen: isDeleteMessageDialogOpen, title: t('chat.messages.deleteConfirm.title'), message: t('chat.messages.deleteConfirm.message'), confirmText: t('chat.messages.deleteConfirm.confirm'), cancelText: t('chat.messages.deleteConfirm.cancel'), onConfirm: confirmDeleteMessage, onCancel: cancelDeleteMessage, currentLanguage: currentLanguage, variant: "danger" })] }));
6620
6689
  });
6621
6690
  ChatWidget.displayName = 'ChatWidget';
6622
6691