fyrebot-widget 1.4.1 → 1.6.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.
- package/dist/ChatbotWidget.d.ts.map +1 -1
- package/dist/ChatbotWidget.js +395 -28
- package/dist/MessageRenderer.d.ts +15 -0
- package/dist/MessageRenderer.d.ts.map +1 -0
- package/dist/MessageRenderer.js +619 -0
- package/dist/api.d.ts +22 -2
- package/dist/api.d.ts.map +1 -1
- package/dist/api.js +43 -4
- package/dist/types.d.ts +8 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +7 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ChatbotWidget.d.ts","sourceRoot":"","sources":["../src/ChatbotWidget.tsx"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAmD,MAAM,OAAO,CAAC;AAGxE,OAAO,KAAK,EAAE,aAAa,EAAe,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"ChatbotWidget.d.ts","sourceRoot":"","sources":["../src/ChatbotWidget.tsx"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAmD,MAAM,OAAO,CAAC;AAGxE,OAAO,KAAK,EAAE,aAAa,EAAe,MAAM,SAAS,CAAC;AAG1D,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC,aAAa,CAmhDjD,CAAC;AAEF,eAAe,aAAa,CAAC"}
|
package/dist/ChatbotWidget.js
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
/**
|
|
3
3
|
* Chatbot Popup Widget
|
|
4
4
|
* Production-ready, standalone chatbot component
|
|
5
5
|
*/
|
|
6
6
|
import { useState, useRef, useEffect, useCallback } from 'react';
|
|
7
|
-
import { MessageCircle, X, Send, Loader2, Bot, User, Sparkles, RefreshCw } from 'lucide-react';
|
|
7
|
+
import { MessageCircle, X, Send, Loader2, Bot, User, Sparkles, RefreshCw, Mail, ArrowLeft, CheckCircle } from 'lucide-react';
|
|
8
8
|
import { ChatbotApiClient } from './api';
|
|
9
|
-
|
|
9
|
+
import { MessageRenderer } from './MessageRenderer';
|
|
10
|
+
export const ChatbotWidget = ({ apiUrl, apiKey, title = 'AI Assistant', subtitle = 'Ask me anything', brandName, primaryColor = '#6366f1', welcomeMessage = 'Hello! How can I help you today?', placeholder = 'Type your message...', position = 'bottom-right', showTypingIndicator = true, showTimestamps = true, showSources = false, showSuggestedQuestions = true, enableContactSupport = true, suggestedQuestions: customSuggestions, maxSuggestions = 4, maxHeight = '600px', maxWidth = '400px', fontSize = '13px', headerFontSize = '15px', smallFontSize = '11px', className = '', onOpen, onClose, onMessageSent, onMessageReceived, onError, }) => {
|
|
10
11
|
const [isOpen, setIsOpen] = useState(false);
|
|
11
12
|
const [messages, setMessages] = useState([]);
|
|
12
13
|
const [input, setInput] = useState('');
|
|
@@ -14,6 +15,17 @@ export const ChatbotWidget = ({ apiUrl, apiKey, title = 'AI Assistant', subtitle
|
|
|
14
15
|
const [error, setError] = useState(null);
|
|
15
16
|
const [suggestions, setSuggestions] = useState([]);
|
|
16
17
|
const [loadingSuggestions, setLoadingSuggestions] = useState(false);
|
|
18
|
+
const [showContactPrompt, setShowContactPrompt] = useState(false);
|
|
19
|
+
// Support form states
|
|
20
|
+
const [showSupportForm, setShowSupportForm] = useState(false);
|
|
21
|
+
const [supportFormData, setSupportFormData] = useState({
|
|
22
|
+
name: '',
|
|
23
|
+
email: '',
|
|
24
|
+
message: '',
|
|
25
|
+
});
|
|
26
|
+
const [isSubmittingTicket, setIsSubmittingTicket] = useState(false);
|
|
27
|
+
const [ticketSubmitted, setTicketSubmitted] = useState(false);
|
|
28
|
+
const [ticketNumber, setTicketNumber] = useState(null);
|
|
17
29
|
const scrollRef = useRef(null);
|
|
18
30
|
const apiClient = useRef(null);
|
|
19
31
|
// Initialize API client
|
|
@@ -25,7 +37,7 @@ export const ChatbotWidget = ({ apiUrl, apiKey, title = 'AI Assistant', subtitle
|
|
|
25
37
|
if (scrollRef.current) {
|
|
26
38
|
scrollRef.current.scrollTop = scrollRef.current.scrollHeight;
|
|
27
39
|
}
|
|
28
|
-
}, [messages, isLoading]);
|
|
40
|
+
}, [messages, isLoading, showContactPrompt]);
|
|
29
41
|
// Fetch suggestions when chat opens and no messages exist
|
|
30
42
|
useEffect(() => {
|
|
31
43
|
const fetchSuggestions = async () => {
|
|
@@ -53,6 +65,62 @@ export const ChatbotWidget = ({ apiUrl, apiKey, title = 'AI Assistant', subtitle
|
|
|
53
65
|
};
|
|
54
66
|
fetchSuggestions();
|
|
55
67
|
}, [isOpen, messages.length, showSuggestedQuestions, customSuggestions, maxSuggestions]);
|
|
68
|
+
// Detect if user wants to contact support
|
|
69
|
+
const detectContactIntent = useCallback((message) => {
|
|
70
|
+
if (!enableContactSupport)
|
|
71
|
+
return false;
|
|
72
|
+
const lowerMessage = message.toLowerCase().trim();
|
|
73
|
+
// Direct support keywords
|
|
74
|
+
const contactKeywords = [
|
|
75
|
+
'contact support',
|
|
76
|
+
'talk to support',
|
|
77
|
+
'speak to someone',
|
|
78
|
+
'human support',
|
|
79
|
+
'real person',
|
|
80
|
+
'customer service',
|
|
81
|
+
'help desk',
|
|
82
|
+
'create ticket',
|
|
83
|
+
'open ticket',
|
|
84
|
+
'submit ticket',
|
|
85
|
+
'generate ticket',
|
|
86
|
+
'make ticket',
|
|
87
|
+
'new ticket',
|
|
88
|
+
'email support',
|
|
89
|
+
'need help',
|
|
90
|
+
'talk to team',
|
|
91
|
+
'speak to team',
|
|
92
|
+
'contact team',
|
|
93
|
+
'reach out',
|
|
94
|
+
'get in touch',
|
|
95
|
+
'escalate',
|
|
96
|
+
'not satisfied',
|
|
97
|
+
'doesn\'t work',
|
|
98
|
+
'still having issues',
|
|
99
|
+
'not working',
|
|
100
|
+
'urgent',
|
|
101
|
+
'contact you',
|
|
102
|
+
'contact aasim',
|
|
103
|
+
'talk to aasim',
|
|
104
|
+
'reach aasim',
|
|
105
|
+
'speak with',
|
|
106
|
+
'get support',
|
|
107
|
+
];
|
|
108
|
+
// Question-based patterns (user asking how to contact)
|
|
109
|
+
const questionPatterns = [
|
|
110
|
+
/can i (contact|reach|talk to|speak to|speak with|get in touch)/i,
|
|
111
|
+
/how (do i|can i|to) (contact|reach|talk to|speak to|get support)/i,
|
|
112
|
+
/i (want|need|would like) to (contact|reach|talk to|speak to|create|generate|open|submit|make).*(support|ticket|team|you|aasim|someone)/i,
|
|
113
|
+
/where (can|do) i (contact|reach|get support)/i,
|
|
114
|
+
/is there (a way|someone) (to|i can) (contact|talk to|reach)/i,
|
|
115
|
+
/(contact|support|help).*(email|phone|number)/i,
|
|
116
|
+
/can.*(help|support|assist).*(me|us)/i,
|
|
117
|
+
];
|
|
118
|
+
// Check direct keywords
|
|
119
|
+
const hasKeyword = contactKeywords.some(keyword => lowerMessage.includes(keyword));
|
|
120
|
+
// Check question patterns
|
|
121
|
+
const hasPattern = questionPatterns.some(pattern => pattern.test(message));
|
|
122
|
+
return hasKeyword || hasPattern;
|
|
123
|
+
}, [enableContactSupport]);
|
|
56
124
|
// Handle open/close
|
|
57
125
|
const handleToggle = useCallback(() => {
|
|
58
126
|
const newState = !isOpen;
|
|
@@ -60,6 +128,8 @@ export const ChatbotWidget = ({ apiUrl, apiKey, title = 'AI Assistant', subtitle
|
|
|
60
128
|
if (newState) {
|
|
61
129
|
onOpen?.();
|
|
62
130
|
setError(null);
|
|
131
|
+
setShowSupportForm(false);
|
|
132
|
+
setTicketSubmitted(false);
|
|
63
133
|
}
|
|
64
134
|
else {
|
|
65
135
|
onClose?.();
|
|
@@ -90,7 +160,10 @@ export const ChatbotWidget = ({ apiUrl, apiKey, title = 'AI Assistant', subtitle
|
|
|
90
160
|
setInput('');
|
|
91
161
|
setIsLoading(true);
|
|
92
162
|
setError(null);
|
|
163
|
+
setShowContactPrompt(false); // Reset prompt
|
|
93
164
|
onMessageSent?.(userMessage.content);
|
|
165
|
+
// Check if user wants to contact support
|
|
166
|
+
const wantsContact = detectContactIntent(textToSend);
|
|
94
167
|
try {
|
|
95
168
|
const response = await apiClient.current.sendMessage(userMessage.content);
|
|
96
169
|
const assistantMessage = {
|
|
@@ -102,6 +175,10 @@ export const ChatbotWidget = ({ apiUrl, apiKey, title = 'AI Assistant', subtitle
|
|
|
102
175
|
};
|
|
103
176
|
setMessages((prev) => [...prev, assistantMessage]);
|
|
104
177
|
onMessageReceived?.(assistantMessage);
|
|
178
|
+
// Show contact prompt if detected and enabled
|
|
179
|
+
if (wantsContact && enableContactSupport) {
|
|
180
|
+
setShowContactPrompt(true);
|
|
181
|
+
}
|
|
105
182
|
}
|
|
106
183
|
catch (err) {
|
|
107
184
|
const error = err;
|
|
@@ -111,7 +188,7 @@ export const ChatbotWidget = ({ apiUrl, apiKey, title = 'AI Assistant', subtitle
|
|
|
111
188
|
finally {
|
|
112
189
|
setIsLoading(false);
|
|
113
190
|
}
|
|
114
|
-
}, [input, isLoading, onMessageSent, onMessageReceived, onError]);
|
|
191
|
+
}, [input, isLoading, detectContactIntent, enableContactSupport, onMessageSent, onMessageReceived, onError]);
|
|
115
192
|
// Handle Enter key
|
|
116
193
|
const handleKeyPress = useCallback((e) => {
|
|
117
194
|
if (e.key === 'Enter' && !e.shiftKey) {
|
|
@@ -123,8 +200,55 @@ export const ChatbotWidget = ({ apiUrl, apiKey, title = 'AI Assistant', subtitle
|
|
|
123
200
|
const handleReset = useCallback(() => {
|
|
124
201
|
setMessages([]);
|
|
125
202
|
setError(null);
|
|
203
|
+
setShowSupportForm(false);
|
|
204
|
+
setTicketSubmitted(false);
|
|
205
|
+
setShowContactPrompt(false);
|
|
126
206
|
apiClient.current?.resetSession();
|
|
127
207
|
}, []);
|
|
208
|
+
// Handle support form submission
|
|
209
|
+
const handleSupportFormSubmit = useCallback(async (e) => {
|
|
210
|
+
e.preventDefault();
|
|
211
|
+
if (!supportFormData.email || !supportFormData.message || !apiClient.current) {
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
setIsSubmittingTicket(true);
|
|
215
|
+
setError(null);
|
|
216
|
+
try {
|
|
217
|
+
const result = await apiClient.current.createTicket({
|
|
218
|
+
name: supportFormData.name || undefined,
|
|
219
|
+
email: supportFormData.email,
|
|
220
|
+
message: supportFormData.message,
|
|
221
|
+
priority: 'medium',
|
|
222
|
+
});
|
|
223
|
+
setTicketNumber(result.ticketNumber);
|
|
224
|
+
setTicketSubmitted(true);
|
|
225
|
+
// Reset form
|
|
226
|
+
setSupportFormData({ name: '', email: '', message: '' });
|
|
227
|
+
}
|
|
228
|
+
catch (err) {
|
|
229
|
+
const error = err;
|
|
230
|
+
setError(error.message);
|
|
231
|
+
onError?.(error);
|
|
232
|
+
}
|
|
233
|
+
finally {
|
|
234
|
+
setIsSubmittingTicket(false);
|
|
235
|
+
}
|
|
236
|
+
}, [supportFormData, onError]);
|
|
237
|
+
// Toggle support form
|
|
238
|
+
const handleShowSupportForm = useCallback(() => {
|
|
239
|
+
setShowSupportForm(true);
|
|
240
|
+
setShowContactPrompt(false);
|
|
241
|
+
setError(null);
|
|
242
|
+
}, []);
|
|
243
|
+
const handleBackToChat = useCallback(() => {
|
|
244
|
+
setShowSupportForm(false);
|
|
245
|
+
setTicketSubmitted(false);
|
|
246
|
+
setShowContactPrompt(false);
|
|
247
|
+
setError(null);
|
|
248
|
+
}, []);
|
|
249
|
+
const handleDismissContactPrompt = useCallback(() => {
|
|
250
|
+
setShowContactPrompt(false);
|
|
251
|
+
}, []);
|
|
128
252
|
// Position styles
|
|
129
253
|
const positionStyles = {
|
|
130
254
|
'bottom-right': { bottom: '40px', right: '40px' },
|
|
@@ -226,8 +350,8 @@ export const ChatbotWidget = ({ apiUrl, apiKey, title = 'AI Assistant', subtitle
|
|
|
226
350
|
|
|
227
351
|
.chatbot-title h3 {
|
|
228
352
|
margin: 0;
|
|
229
|
-
font-size:
|
|
230
|
-
font-weight:
|
|
353
|
+
font-size: ${headerFontSize};
|
|
354
|
+
font-weight: 500;
|
|
231
355
|
white-space: nowrap;
|
|
232
356
|
overflow: hidden;
|
|
233
357
|
text-overflow: ellipsis;
|
|
@@ -235,7 +359,7 @@ export const ChatbotWidget = ({ apiUrl, apiKey, title = 'AI Assistant', subtitle
|
|
|
235
359
|
|
|
236
360
|
.chatbot-title p {
|
|
237
361
|
margin: 0;
|
|
238
|
-
font-size:
|
|
362
|
+
font-size: ${smallFontSize};
|
|
239
363
|
opacity: 0.9;
|
|
240
364
|
white-space: nowrap;
|
|
241
365
|
overflow: hidden;
|
|
@@ -306,6 +430,244 @@ export const ChatbotWidget = ({ apiUrl, apiKey, title = 'AI Assistant', subtitle
|
|
|
306
430
|
color: ${primaryColor};
|
|
307
431
|
}
|
|
308
432
|
|
|
433
|
+
.chatbot-support-link {
|
|
434
|
+
margin-top: 20px;
|
|
435
|
+
padding-top: 20px;
|
|
436
|
+
border-top: 1px solid #333;
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
.chatbot-support-button {
|
|
440
|
+
background: #2a2a2a;
|
|
441
|
+
border: 1px solid #333;
|
|
442
|
+
color: ${primaryColor};
|
|
443
|
+
padding: 12px 20px;
|
|
444
|
+
border-radius: 8px;
|
|
445
|
+
font-size: ${fontSize};
|
|
446
|
+
cursor: pointer;
|
|
447
|
+
transition: all 0.2s;
|
|
448
|
+
display: inline-flex;
|
|
449
|
+
align-items: center;
|
|
450
|
+
gap: 8px;
|
|
451
|
+
font-weight: 500;
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
.chatbot-support-button:hover {
|
|
455
|
+
background: #333;
|
|
456
|
+
border-color: ${primaryColor};
|
|
457
|
+
transform: translateY(-2px);
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
.chatbot-contact-prompt {
|
|
461
|
+
background: linear-gradient(135deg, ${primaryColor}15, ${primaryColor}08);
|
|
462
|
+
border: 1px solid ${primaryColor}40;
|
|
463
|
+
border-radius: 12px;
|
|
464
|
+
padding: 16px;
|
|
465
|
+
margin: 16px 0;
|
|
466
|
+
animation: slideIn 0.3s ease;
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
@keyframes slideIn {
|
|
470
|
+
from {
|
|
471
|
+
opacity: 0;
|
|
472
|
+
transform: translateY(-10px);
|
|
473
|
+
}
|
|
474
|
+
to {
|
|
475
|
+
opacity: 1;
|
|
476
|
+
transform: translateY(0);
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
.chatbot-contact-prompt-header {
|
|
481
|
+
display: flex;
|
|
482
|
+
align-items: center;
|
|
483
|
+
gap: 12px;
|
|
484
|
+
margin-bottom: 12px;
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
.chatbot-contact-prompt-icon {
|
|
488
|
+
width: 40px;
|
|
489
|
+
height: 40px;
|
|
490
|
+
border-radius: 50%;
|
|
491
|
+
background: ${primaryColor};
|
|
492
|
+
display: flex;
|
|
493
|
+
align-items: center;
|
|
494
|
+
justify-content: center;
|
|
495
|
+
color: white;
|
|
496
|
+
flex-shrink: 0;
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
.chatbot-contact-prompt-title {
|
|
500
|
+
font-size: ${headerFontSize};
|
|
501
|
+
font-weight: 600;
|
|
502
|
+
color: #e0e0e0;
|
|
503
|
+
margin: 0;
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
.chatbot-contact-prompt-description {
|
|
507
|
+
font-size: ${fontSize};
|
|
508
|
+
color: #aaa;
|
|
509
|
+
margin: 0 0 16px 0;
|
|
510
|
+
line-height: 1.5;
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
.chatbot-contact-prompt-actions {
|
|
514
|
+
display: flex;
|
|
515
|
+
gap: 8px;
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
.chatbot-contact-prompt-button {
|
|
519
|
+
flex: 1;
|
|
520
|
+
padding: 12px 16px;
|
|
521
|
+
border-radius: 8px;
|
|
522
|
+
font-size: ${fontSize};
|
|
523
|
+
font-weight: 600;
|
|
524
|
+
cursor: pointer;
|
|
525
|
+
transition: all 0.2s;
|
|
526
|
+
display: flex;
|
|
527
|
+
align-items: center;
|
|
528
|
+
justify-content: center;
|
|
529
|
+
gap: 8px;
|
|
530
|
+
border: none;
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
.chatbot-contact-prompt-button.primary {
|
|
534
|
+
background: ${primaryColor};
|
|
535
|
+
color: white;
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
.chatbot-contact-prompt-button.primary:hover {
|
|
539
|
+
opacity: 0.9;
|
|
540
|
+
transform: translateY(-2px);
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
.chatbot-contact-prompt-button.secondary {
|
|
544
|
+
background: #2a2a2a;
|
|
545
|
+
color: #ccc;
|
|
546
|
+
border: 1px solid #333;
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
.chatbot-contact-prompt-button.secondary:hover {
|
|
550
|
+
background: #333;
|
|
551
|
+
color: #fff;
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
.chatbot-support-form {
|
|
555
|
+
flex: 1;
|
|
556
|
+
overflow-y: auto;
|
|
557
|
+
padding: 20px;
|
|
558
|
+
background: #1a1a1a;
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
.chatbot-form-group {
|
|
562
|
+
margin-bottom: 16px;
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
.chatbot-form-label {
|
|
566
|
+
display: block;
|
|
567
|
+
color: #ccc;
|
|
568
|
+
font-size: ${fontSize};
|
|
569
|
+
font-weight: 500;
|
|
570
|
+
margin-bottom: 8px;
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
.chatbot-form-input {
|
|
574
|
+
width: 100%;
|
|
575
|
+
padding: 12px;
|
|
576
|
+
background: #2a2a2a;
|
|
577
|
+
border: 1px solid #333;
|
|
578
|
+
border-radius: 8px;
|
|
579
|
+
color: #e0e0e0;
|
|
580
|
+
font-size: ${fontSize};
|
|
581
|
+
font-family: inherit;
|
|
582
|
+
transition: border-color 0.2s;
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
.chatbot-form-input:focus {
|
|
586
|
+
outline: none;
|
|
587
|
+
border-color: ${primaryColor};
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
.chatbot-form-textarea {
|
|
591
|
+
min-height: 120px;
|
|
592
|
+
resize: vertical;
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
.chatbot-form-submit {
|
|
596
|
+
width: 100%;
|
|
597
|
+
padding: 14px;
|
|
598
|
+
background: ${primaryColor};
|
|
599
|
+
border: none;
|
|
600
|
+
border-radius: 8px;
|
|
601
|
+
color: white;
|
|
602
|
+
font-size: ${fontSize};
|
|
603
|
+
font-weight: 600;
|
|
604
|
+
cursor: pointer;
|
|
605
|
+
transition: all 0.2s;
|
|
606
|
+
display: flex;
|
|
607
|
+
align-items: center;
|
|
608
|
+
justify-content: center;
|
|
609
|
+
gap: 8px;
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
.chatbot-form-submit:hover:not(:disabled) {
|
|
613
|
+
opacity: 0.9;
|
|
614
|
+
transform: translateY(-2px);
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
.chatbot-form-submit:disabled {
|
|
618
|
+
opacity: 0.5;
|
|
619
|
+
cursor: not-allowed;
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
.chatbot-success-message {
|
|
623
|
+
text-align: center;
|
|
624
|
+
padding: 40px 20px;
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
.chatbot-success-icon {
|
|
628
|
+
width: 64px;
|
|
629
|
+
height: 64px;
|
|
630
|
+
margin: 0 auto 16px;
|
|
631
|
+
border-radius: 50%;
|
|
632
|
+
background: rgba(16, 185, 129, 0.1);
|
|
633
|
+
display: flex;
|
|
634
|
+
align-items: center;
|
|
635
|
+
justify-content: center;
|
|
636
|
+
color: #10b981;
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
.chatbot-ticket-number {
|
|
640
|
+
display: inline-block;
|
|
641
|
+
padding: 8px 16px;
|
|
642
|
+
background: #2a2a2a;
|
|
643
|
+
border: 1px solid #333;
|
|
644
|
+
border-radius: 8px;
|
|
645
|
+
color: ${primaryColor};
|
|
646
|
+
font-family: monospace;
|
|
647
|
+
font-size: ${fontSize};
|
|
648
|
+
margin: 16px 0;
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
.chatbot-back-button {
|
|
652
|
+
margin-top: 20px;
|
|
653
|
+
background: #2a2a2a;
|
|
654
|
+
border: 1px solid #333;
|
|
655
|
+
color: #ccc;
|
|
656
|
+
padding: 12px 20px;
|
|
657
|
+
border-radius: 8px;
|
|
658
|
+
font-size: ${fontSize};
|
|
659
|
+
cursor: pointer;
|
|
660
|
+
transition: all 0.2s;
|
|
661
|
+
display: inline-flex;
|
|
662
|
+
align-items: center;
|
|
663
|
+
gap: 8px;
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
.chatbot-back-button:hover {
|
|
667
|
+
background: #333;
|
|
668
|
+
color: #fff;
|
|
669
|
+
}
|
|
670
|
+
|
|
309
671
|
.chatbot-message {
|
|
310
672
|
display: flex;
|
|
311
673
|
gap: 12px;
|
|
@@ -376,7 +738,7 @@ export const ChatbotWidget = ({ apiUrl, apiKey, title = 'AI Assistant', subtitle
|
|
|
376
738
|
}
|
|
377
739
|
|
|
378
740
|
.chatbot-timestamp {
|
|
379
|
-
font-size:
|
|
741
|
+
font-size: ${smallFontSize};
|
|
380
742
|
color: #666;
|
|
381
743
|
margin-top: 4px;
|
|
382
744
|
}
|
|
@@ -389,7 +751,7 @@ export const ChatbotWidget = ({ apiUrl, apiKey, title = 'AI Assistant', subtitle
|
|
|
389
751
|
}
|
|
390
752
|
|
|
391
753
|
.chatbot-source {
|
|
392
|
-
font-size:
|
|
754
|
+
font-size: ${smallFontSize};
|
|
393
755
|
padding: 4px 8px;
|
|
394
756
|
background: rgba(99, 102, 241, 0.1);
|
|
395
757
|
color: ${primaryColor};
|
|
@@ -446,7 +808,7 @@ export const ChatbotWidget = ({ apiUrl, apiKey, title = 'AI Assistant', subtitle
|
|
|
446
808
|
padding: 12px;
|
|
447
809
|
border-radius: 8px;
|
|
448
810
|
margin: 0 16px 16px;
|
|
449
|
-
font-size:
|
|
811
|
+
font-size: ${fontSize};
|
|
450
812
|
display: flex;
|
|
451
813
|
align-items: center;
|
|
452
814
|
gap: 8px;
|
|
@@ -484,7 +846,7 @@ export const ChatbotWidget = ({ apiUrl, apiKey, title = 'AI Assistant', subtitle
|
|
|
484
846
|
outline: none;
|
|
485
847
|
padding: 12px 0;
|
|
486
848
|
color: #e0e0e0;
|
|
487
|
-
font-size:
|
|
849
|
+
font-size: ${fontSize};
|
|
488
850
|
min-width: 0;
|
|
489
851
|
}
|
|
490
852
|
|
|
@@ -539,7 +901,7 @@ export const ChatbotWidget = ({ apiUrl, apiKey, title = 'AI Assistant', subtitle
|
|
|
539
901
|
}
|
|
540
902
|
|
|
541
903
|
.chatbot-suggestions-title {
|
|
542
|
-
font-size:
|
|
904
|
+
font-size: ${smallFontSize};
|
|
543
905
|
color: #888;
|
|
544
906
|
font-weight: 500;
|
|
545
907
|
margin-bottom: 4px;
|
|
@@ -553,7 +915,7 @@ export const ChatbotWidget = ({ apiUrl, apiKey, title = 'AI Assistant', subtitle
|
|
|
553
915
|
color: #ccc;
|
|
554
916
|
padding: 10px 14px;
|
|
555
917
|
border-radius: 20px;
|
|
556
|
-
font-size:
|
|
918
|
+
font-size: ${fontSize};
|
|
557
919
|
cursor: pointer;
|
|
558
920
|
transition: all 0.2s ease;
|
|
559
921
|
text-align: left;
|
|
@@ -595,7 +957,7 @@ export const ChatbotWidget = ({ apiUrl, apiKey, title = 'AI Assistant', subtitle
|
|
|
595
957
|
.chatbot-suggestion-icon {
|
|
596
958
|
color: ${primaryColor};
|
|
597
959
|
opacity: 0.7;
|
|
598
|
-
font-size:
|
|
960
|
+
font-size: ${headerFontSize};
|
|
599
961
|
flex-shrink: 0;
|
|
600
962
|
}
|
|
601
963
|
|
|
@@ -636,19 +998,16 @@ export const ChatbotWidget = ({ apiUrl, apiKey, title = 'AI Assistant', subtitle
|
|
|
636
998
|
|
|
637
999
|
/* Mobile responsiveness */
|
|
638
1000
|
@media (max-width: 480px) {
|
|
639
|
-
/* Don't modify the container positioning - let it stay fixed at bottom-right for the button */
|
|
640
1001
|
.chatbot-widget-container {
|
|
641
1002
|
/* Keep default positioning from parent styles */
|
|
642
1003
|
}
|
|
643
1004
|
|
|
644
1005
|
.chatbot-button {
|
|
645
|
-
/* Button stays in corner */
|
|
646
1006
|
width: 56px;
|
|
647
1007
|
height: 56px;
|
|
648
1008
|
}
|
|
649
1009
|
|
|
650
1010
|
.chatbot-window {
|
|
651
|
-
/* Only the chat window covers full screen when open */
|
|
652
1011
|
position: fixed;
|
|
653
1012
|
bottom: 0 !important;
|
|
654
1013
|
right: 0 !important;
|
|
@@ -684,17 +1043,21 @@ export const ChatbotWidget = ({ apiUrl, apiKey, title = 'AI Assistant', subtitle
|
|
|
684
1043
|
}
|
|
685
1044
|
|
|
686
1045
|
.chatbot-title h3 {
|
|
687
|
-
font-size:
|
|
1046
|
+
font-size: ${fontSize};
|
|
688
1047
|
}
|
|
689
1048
|
|
|
690
1049
|
.chatbot-title p {
|
|
691
|
-
font-size:
|
|
1050
|
+
font-size: ${smallFontSize};
|
|
692
1051
|
}
|
|
693
1052
|
|
|
694
1053
|
.chatbot-messages {
|
|
695
1054
|
padding: 12px;
|
|
696
1055
|
}
|
|
697
1056
|
|
|
1057
|
+
.chatbot-support-form {
|
|
1058
|
+
padding: 16px;
|
|
1059
|
+
}
|
|
1060
|
+
|
|
698
1061
|
.chatbot-welcome {
|
|
699
1062
|
padding: 30px 16px;
|
|
700
1063
|
}
|
|
@@ -715,7 +1078,7 @@ export const ChatbotWidget = ({ apiUrl, apiKey, title = 'AI Assistant', subtitle
|
|
|
715
1078
|
|
|
716
1079
|
.chatbot-bubble {
|
|
717
1080
|
padding: 10px 14px;
|
|
718
|
-
font-size:
|
|
1081
|
+
font-size: ${fontSize};
|
|
719
1082
|
}
|
|
720
1083
|
|
|
721
1084
|
.chatbot-input-area {
|
|
@@ -740,7 +1103,7 @@ export const ChatbotWidget = ({ apiUrl, apiKey, title = 'AI Assistant', subtitle
|
|
|
740
1103
|
|
|
741
1104
|
.chatbot-suggestion-chip {
|
|
742
1105
|
padding: 12px 16px;
|
|
743
|
-
font-size:
|
|
1106
|
+
font-size: ${fontSize};
|
|
744
1107
|
min-height: 48px;
|
|
745
1108
|
}
|
|
746
1109
|
|
|
@@ -761,16 +1124,20 @@ export const ChatbotWidget = ({ apiUrl, apiKey, title = 'AI Assistant', subtitle
|
|
|
761
1124
|
}
|
|
762
1125
|
|
|
763
1126
|
.chatbot-title h3 {
|
|
764
|
-
font-size:
|
|
1127
|
+
font-size: ${fontSize};
|
|
765
1128
|
}
|
|
766
1129
|
|
|
767
1130
|
.chatbot-messages {
|
|
768
1131
|
padding: 10px;
|
|
769
1132
|
}
|
|
770
1133
|
|
|
1134
|
+
.chatbot-support-form {
|
|
1135
|
+
padding: 12px;
|
|
1136
|
+
}
|
|
1137
|
+
|
|
771
1138
|
.chatbot-bubble {
|
|
772
1139
|
padding: 8px 12px;
|
|
773
|
-
font-size:
|
|
1140
|
+
font-size: ${fontSize};
|
|
774
1141
|
}
|
|
775
1142
|
|
|
776
1143
|
.chatbot-input-area {
|
|
@@ -794,10 +1161,10 @@ export const ChatbotWidget = ({ apiUrl, apiKey, title = 'AI Assistant', subtitle
|
|
|
794
1161
|
padding: 10px 16px;
|
|
795
1162
|
}
|
|
796
1163
|
}
|
|
797
|
-
` }), !isOpen && (_jsx("button", { className: "chatbot-button", onClick: handleToggle, "aria-label": "Open chat", children: _jsx(MessageCircle, { size: 28 }) })), isOpen && (_jsxs("div", { className: "chatbot-window", children: [_jsxs("div", { className: "chatbot-header", children: [_jsxs("div", { className: "chatbot-header-content", children: [_jsx("div", { className: "chatbot-icon", children: _jsx(Sparkles, { size: 20 }) }), _jsxs("div", { className: "chatbot-title", children: [_jsx("h3", { children: title }), subtitle && _jsx("p", { children: subtitle })] })] }), _jsxs("div", { style: { display: 'flex', gap: '8px' }, children: [messages.length > 0 && (_jsx("button", { className: "chatbot-close", onClick: handleReset, "aria-label": "Reset conversation", title: "Start new conversation", children: _jsx(RefreshCw, { size: 18 }) })), _jsx("button", { className: "chatbot-close", onClick: handleToggle, "aria-label": "Close chat", children: _jsx(X, { size: 20 }) })] })] }), _jsxs("div", { className: "chatbot-messages", ref: scrollRef, children: [messages.length === 0 ? (_jsxs("div", { className: "chatbot-welcome", children: [_jsx("div", { className: "chatbot-welcome-icon", children: _jsx(Bot, { size: 32 }) }), _jsx("h4", { style: { margin: '0 0 8px 0', color: '#ccc' }, children: brandName ? `Welcome to ${brandName}!` : 'Welcome!' }), _jsx("p", { style: { margin: 0, fontSize: '14px' }, children: welcomeMessage })] })) : (messages.map((message) => (_jsxs("div", { className: `chatbot-message ${message.role}`, children: [_jsx("div", { className: `chatbot-avatar ${message.role === 'user' ? 'user' : 'bot'}`, children: message.role === 'user' ? _jsx(User, { size: 18 }) : _jsx(Bot, { size: 18 }) }), _jsxs("div", { className: "chatbot-message-content", children: [_jsx("div", { className: `chatbot-bubble ${message.role === 'user' ? 'user' : 'bot'}`, children: message.content }), showSources && message.sources && message.sources.length > 0 && (_jsx("div", { className: "chatbot-sources", children: message.sources.map((source, idx) => (_jsxs("span", { className: "chatbot-source", children: [source.title, " (", Math.round(source.score * 100), "%)"] }, idx))) })), showTimestamps && (_jsx("div", { className: "chatbot-timestamp", children: new Date(message.timestamp).toLocaleTimeString([], {
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
1164
|
+
` }), !isOpen && (_jsx("button", { className: "chatbot-button", onClick: handleToggle, "aria-label": "Open chat", children: _jsx(MessageCircle, { size: 28 }) })), isOpen && (_jsxs("div", { className: "chatbot-window", children: [_jsxs("div", { className: "chatbot-header", children: [_jsxs("div", { className: "chatbot-header-content", children: [showSupportForm && (_jsx("button", { className: "chatbot-close", onClick: handleBackToChat, "aria-label": "Back to chat", title: "Back to chat", style: { marginRight: '8px' }, children: _jsx(ArrowLeft, { size: 18 }) })), _jsx("div", { className: "chatbot-icon", children: showSupportForm ? _jsx(Mail, { size: 20 }) : _jsx(Sparkles, { size: 20 }) }), _jsxs("div", { className: "chatbot-title", children: [_jsx("h3", { children: showSupportForm ? 'Contact Support' : title }), subtitle && !showSupportForm && _jsx("p", { children: subtitle }), showSupportForm && _jsx("p", { children: "We'll get back to you soon" })] })] }), _jsxs("div", { style: { display: 'flex', gap: '8px' }, children: [messages.length > 0 && !showSupportForm && (_jsx("button", { className: "chatbot-close", onClick: handleReset, "aria-label": "Reset conversation", title: "Start new conversation", children: _jsx(RefreshCw, { size: 18 }) })), _jsx("button", { className: "chatbot-close", onClick: handleToggle, "aria-label": "Close chat", children: _jsx(X, { size: 20 }) })] })] }), showSupportForm && !ticketSubmitted && (_jsxs("form", { className: "chatbot-support-form", onSubmit: handleSupportFormSubmit, children: [_jsxs("div", { className: "chatbot-form-group", children: [_jsx("label", { className: "chatbot-form-label", children: "Name (Optional)" }), _jsx("input", { type: "text", className: "chatbot-form-input", value: supportFormData.name, onChange: (e) => setSupportFormData({ ...supportFormData, name: e.target.value }), placeholder: "Your name", disabled: isSubmittingTicket })] }), _jsxs("div", { className: "chatbot-form-group", children: [_jsxs("label", { className: "chatbot-form-label", children: ["Email Address ", _jsx("span", { style: { color: '#ef4444' }, children: "*" })] }), _jsx("input", { type: "email", className: "chatbot-form-input", value: supportFormData.email, onChange: (e) => setSupportFormData({ ...supportFormData, email: e.target.value }), placeholder: "your@email.com", required: true, disabled: isSubmittingTicket })] }), _jsxs("div", { className: "chatbot-form-group", children: [_jsxs("label", { className: "chatbot-form-label", children: ["Message ", _jsx("span", { style: { color: '#ef4444' }, children: "*" })] }), _jsx("textarea", { className: "chatbot-form-input chatbot-form-textarea", value: supportFormData.message, onChange: (e) => setSupportFormData({ ...supportFormData, message: e.target.value }), placeholder: "Please describe your issue or question...", required: true, minLength: 10, disabled: isSubmittingTicket })] }), _jsx("button", { type: "submit", className: "chatbot-form-submit", disabled: isSubmittingTicket || !supportFormData.email || !supportFormData.message, children: isSubmittingTicket ? (_jsxs(_Fragment, { children: [_jsx(Loader2, { size: 18, className: "spin" }), "Submitting..."] })) : (_jsxs(_Fragment, { children: [_jsx(Send, { size: 18 }), "Submit Ticket"] })) }), error && (_jsxs("div", { className: "chatbot-error", style: { marginTop: '16px' }, children: [_jsx("span", { children: "\u26A0\uFE0F" }), error] }))] })), ticketSubmitted && (_jsx("div", { className: "chatbot-support-form", children: _jsxs("div", { className: "chatbot-success-message", children: [_jsx("div", { className: "chatbot-success-icon", children: _jsx(CheckCircle, { size: 32 }) }), _jsx("h4", { style: { margin: '0 0 8px 0', color: '#10b981', fontSize: '18px' }, children: "Ticket Submitted!" }), _jsx("p", { style: { margin: '0 0 16px 0', color: '#888', fontSize: '14px' }, children: "Thank you for contacting us. We've received your message and will get back to you soon." }), ticketNumber && (_jsxs("div", { children: [_jsx("p", { style: { margin: '0 0 8px 0', color: '#ccc', fontSize: '13px' }, children: "Your ticket number:" }), _jsx("div", { className: "chatbot-ticket-number", children: ticketNumber })] })), _jsx("p", { style: { margin: '20px 0 0 0', color: '#666', fontSize: '12px' }, children: "Please check your email for confirmation and updates." }), _jsxs("button", { className: "chatbot-back-button", onClick: handleBackToChat, children: [_jsx(ArrowLeft, { size: 16 }), "Back to Chat"] })] }) })), !showSupportForm && (_jsxs(_Fragment, { children: [_jsxs("div", { className: "chatbot-messages", ref: scrollRef, children: [messages.length === 0 ? (_jsxs("div", { className: "chatbot-welcome", children: [_jsx("div", { className: "chatbot-welcome-icon", children: _jsx(Bot, { size: 32 }) }), _jsx("h4", { style: { margin: '0 0 8px 0', color: '#ccc' }, children: brandName ? `Welcome to ${brandName}!` : 'Welcome!' }), _jsx("p", { style: { margin: 0, fontSize: '14px' }, children: welcomeMessage })] })) : (messages.map((message) => (_jsxs("div", { className: `chatbot-message ${message.role}`, children: [_jsx("div", { className: `chatbot-avatar ${message.role === 'user' ? 'user' : 'bot'}`, children: message.role === 'user' ? _jsx(User, { size: 18 }) : _jsx(Bot, { size: 18 }) }), _jsxs("div", { className: "chatbot-message-content", children: [_jsx("div", { className: `chatbot-bubble ${message.role === 'user' ? 'user' : 'bot'}`, children: message.role === 'user' ? (message.content) : (_jsx(MessageRenderer, { content: message.content, primaryColor: primaryColor, fontSize: fontSize, headerFontSize: headerFontSize, smallFontSize: smallFontSize })) }), showSources && message.sources && message.sources.length > 0 && (_jsx("div", { className: "chatbot-sources", children: message.sources.map((source, idx) => (_jsxs("span", { className: "chatbot-source", children: [source.title, " (", Math.round(source.score * 100), "%)"] }, idx))) })), showTimestamps && (_jsx("div", { className: "chatbot-timestamp", children: new Date(message.timestamp).toLocaleTimeString([], {
|
|
1165
|
+
hour: '2-digit',
|
|
1166
|
+
minute: '2-digit',
|
|
1167
|
+
}) }))] })] }, message.id)))), isLoading && showTypingIndicator && (_jsxs("div", { className: "chatbot-typing", children: [_jsx("div", { className: "chatbot-avatar bot", children: _jsx(Bot, { size: 18 }) }), _jsxs("div", { className: "chatbot-typing-dots", children: [_jsx("div", { className: "chatbot-typing-dot" }), _jsx("div", { className: "chatbot-typing-dot" }), _jsx("div", { className: "chatbot-typing-dot" })] })] })), showContactPrompt && enableContactSupport && (_jsxs("div", { className: "chatbot-contact-prompt", children: [_jsxs("div", { className: "chatbot-contact-prompt-header", children: [_jsx("div", { className: "chatbot-contact-prompt-icon", children: _jsx(Mail, { size: 20 }) }), _jsx("h4", { className: "chatbot-contact-prompt-title", children: "Need to Contact Support?" })] }), _jsx("p", { className: "chatbot-contact-prompt-description", children: "It looks like you may need additional help. Would you like to create a support ticket? Our team will get back to you as soon as possible." }), _jsxs("div", { className: "chatbot-contact-prompt-actions", children: [_jsxs("button", { className: "chatbot-contact-prompt-button primary", onClick: handleShowSupportForm, children: [_jsx(Mail, { size: 16 }), "Create Ticket"] }), _jsx("button", { className: "chatbot-contact-prompt-button secondary", onClick: handleDismissContactPrompt, children: "Continue Chat" })] })] }))] }), showSuggestedQuestions && messages.length === 0 && !isLoading && (loadingSuggestions || suggestions.length > 0) && (_jsxs("div", { className: "chatbot-suggestions", children: [(loadingSuggestions || suggestions.length > 0) && (_jsx("div", { className: "chatbot-suggestions-title", children: "Suggested Questions" })), loadingSuggestions ? (_jsxs("div", { className: "chatbot-suggestions-skeleton", children: [_jsx("div", { className: "chatbot-skeleton-chip" }), _jsx("div", { className: "chatbot-skeleton-chip" }), _jsx("div", { className: "chatbot-skeleton-chip" }), _jsx("div", { className: "chatbot-skeleton-chip" })] })) : (suggestions.map((suggestion, idx) => (_jsxs("button", { className: "chatbot-suggestion-chip", onClick: () => handleSuggestionClick(suggestion), disabled: isLoading, children: [_jsx("span", { className: "chatbot-suggestion-icon", children: "\uD83D\uDCAC" }), suggestion] }, idx))))] })), error && (_jsxs("div", { className: "chatbot-error", children: [_jsx("span", { children: "\u26A0\uFE0F" }), error] })), _jsxs("div", { className: "chatbot-input-area", children: [_jsx("div", { className: "chatbot-input-wrapper", children: _jsx("input", { type: "text", className: "chatbot-input", value: input, onChange: (e) => setInput(e.target.value), onKeyPress: handleKeyPress, placeholder: placeholder, disabled: isLoading }) }), _jsx("button", { className: "chatbot-button-icon", onClick: () => handleSendMessage(), disabled: !input.trim() || isLoading, "aria-label": "Send message", children: isLoading ? _jsx(Loader2, { size: 20, className: "spin" }) : _jsx(Send, { size: 20 }) })] })] }))] })), _jsx("style", { children: `
|
|
801
1168
|
.spin {
|
|
802
1169
|
animation: spin 1s linear infinite;
|
|
803
1170
|
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
interface MessageRendererProps {
|
|
3
|
+
content: string;
|
|
4
|
+
primaryColor?: string;
|
|
5
|
+
fontSize?: string;
|
|
6
|
+
headerFontSize?: string;
|
|
7
|
+
smallFontSize?: string;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Production-ready message renderer
|
|
11
|
+
* Handles: Lists, Tables, Code, Links, JSON, Markdown
|
|
12
|
+
*/
|
|
13
|
+
export declare const MessageRenderer: React.FC<MessageRendererProps>;
|
|
14
|
+
export {};
|
|
15
|
+
//# sourceMappingURL=MessageRenderer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MessageRenderer.d.ts","sourceRoot":"","sources":["../src/MessageRenderer.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,UAAU,oBAAoB;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED;;;GAGG;AACH,eAAO,MAAM,eAAe,EAAE,KAAK,CAAC,EAAE,CAAC,oBAAoB,CA4vB1D,CAAC"}
|