andy-widget-react 2.0.6 → 2.1.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/README.md +2 -0
- package/dist/index.cjs +44 -13
- package/dist/index.cjs.map +1 -1
- package/dist/index.esm.js +44 -13
- package/dist/index.esm.js.map +1 -1
- package/dist/types/types/index.d.ts +4 -0
- package/package.json +2 -2
- package/src/AndyChat.tsx +21 -16
- package/src/types/index.ts +4 -0
|
@@ -74,6 +74,10 @@ export interface AndyChatProps {
|
|
|
74
74
|
welcomeMessage?: string;
|
|
75
75
|
/** Optional custom label for pill-style bubble (overrides default) */
|
|
76
76
|
bubbleLabel?: string;
|
|
77
|
+
/** Optional UI language for the widget's own chrome, overrides the Agent's defaultLang */
|
|
78
|
+
lang?: 'en' | 'es';
|
|
79
|
+
/** Optional starter questions (overrides API value) */
|
|
80
|
+
predefinedQuestions?: PredefinedQuestion[];
|
|
77
81
|
/** Optional theme ('light' | 'dark' | 'auto') */
|
|
78
82
|
theme?: 'light' | 'dark' | 'auto';
|
|
79
83
|
/** Optional position ('left' | 'right') */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "andy-widget-react",
|
|
3
|
-
"version": "2.0
|
|
3
|
+
"version": "2.1.0",
|
|
4
4
|
"description": "Official React Widget for embeddable Andy agents",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.cjs",
|
|
@@ -67,6 +67,6 @@
|
|
|
67
67
|
"react-dom": "^18.0.0 || ^19.0.0"
|
|
68
68
|
},
|
|
69
69
|
"dependencies": {
|
|
70
|
-
"andy-widget-core": "2.0
|
|
70
|
+
"andy-widget-core": "2.1.0"
|
|
71
71
|
}
|
|
72
72
|
}
|
package/src/AndyChat.tsx
CHANGED
|
@@ -18,6 +18,7 @@ import {
|
|
|
18
18
|
FOOTER_TEXT,
|
|
19
19
|
getFooterUrl,
|
|
20
20
|
getDefaultBubbleLabel,
|
|
21
|
+
getUiStrings,
|
|
21
22
|
getKeyboardDetector,
|
|
22
23
|
updateKeyboardHeight,
|
|
23
24
|
isMobileDevice
|
|
@@ -74,6 +75,8 @@ const AndyChat: React.FC<AndyChatProps> = ({
|
|
|
74
75
|
description,
|
|
75
76
|
welcomeMessage,
|
|
76
77
|
bubbleLabel,
|
|
78
|
+
lang,
|
|
79
|
+
predefinedQuestions,
|
|
77
80
|
theme,
|
|
78
81
|
orientation,
|
|
79
82
|
brandColor,
|
|
@@ -84,6 +87,11 @@ const AndyChat: React.FC<AndyChatProps> = ({
|
|
|
84
87
|
initialOpen = false
|
|
85
88
|
}) => {
|
|
86
89
|
const [config, setConfig] = useState<ChatbotConfig | null>(null)
|
|
90
|
+
// The visitor's language wins over the Agent's own default: a Spanish Agent
|
|
91
|
+
// embedded on an English page must still render English chrome.
|
|
92
|
+
const uiLang = lang || config?.defaultLang || 'en'
|
|
93
|
+
const strings = getUiStrings(uiLang)
|
|
94
|
+
const activeQuestions = predefinedQuestions?.length ? predefinedQuestions : config?.predefinedQuestions
|
|
87
95
|
const [isOpen, setIsOpen] = useState(initialOpen)
|
|
88
96
|
const [messages, setMessages] = useState<Message[]>([])
|
|
89
97
|
const [isLoading, setIsLoading] = useState(false)
|
|
@@ -114,7 +122,7 @@ const AndyChat: React.FC<AndyChatProps> = ({
|
|
|
114
122
|
pendingHandoffIdsRef.current = projection.pendingProjectionIds || []
|
|
115
123
|
const projectedMessages = projection.messages.map(message => ({ id: message.id, content: message.content, sender: message.role === 'user' ? 'user' as const : 'bot' as const, timestamp: new Date(message.createdAt).toISOString(), isHuman: message.sentByHuman }))
|
|
116
124
|
setMessages(projection.control === 'requested' || projection.control === 'human'
|
|
117
|
-
? [...projectedMessages, { id: 'handoff-waiting', content:
|
|
125
|
+
? [...projectedMessages, { id: 'handoff-waiting', content: strings.handoffWaiting, sender: 'bot', timestamp: new Date().toISOString(), isWaiting: true }]
|
|
118
126
|
: projectedMessages)
|
|
119
127
|
})
|
|
120
128
|
handoffRef.current = handoff
|
|
@@ -326,12 +334,12 @@ const AndyChat: React.FC<AndyChatProps> = ({
|
|
|
326
334
|
bubbleStyle: bubbleStyle || 'icon',
|
|
327
335
|
bubbleLabel: bubbleLabel || null,
|
|
328
336
|
useBrandColor: useBrandColor !== undefined ? useBrandColor : true,
|
|
329
|
-
defaultLang:
|
|
337
|
+
defaultLang: uiLang,
|
|
330
338
|
showBranding: true,
|
|
331
339
|
showWelcomePopup: { enabled: false, seconds: 3, message: '' },
|
|
332
340
|
collectUserInfo: { enabled: false, message: '' },
|
|
333
341
|
welcomeMessage: welcomeMessage || 'Hi there! How can I help you today?',
|
|
334
|
-
predefinedQuestions: [],
|
|
342
|
+
predefinedQuestions: predefinedQuestions || [],
|
|
335
343
|
faqs: []
|
|
336
344
|
}
|
|
337
345
|
setConfig(previewConfig)
|
|
@@ -495,7 +503,7 @@ const AndyChat: React.FC<AndyChatProps> = ({
|
|
|
495
503
|
setMessages([])
|
|
496
504
|
}
|
|
497
505
|
|
|
498
|
-
if (
|
|
506
|
+
if (activeQuestions && activeQuestions.length > 0) {
|
|
499
507
|
setShowPredefinedQuestions(true)
|
|
500
508
|
}
|
|
501
509
|
}
|
|
@@ -527,7 +535,7 @@ const AndyChat: React.FC<AndyChatProps> = ({
|
|
|
527
535
|
setIsLoading(true)
|
|
528
536
|
const response = await sendMessageToAPI(embedId!, sessionId, messageText)
|
|
529
537
|
if (response.status === 'waiting') {
|
|
530
|
-
setMessages(prev => prev.some(message => message.isWaiting) ? prev : [...prev, { id: 'handoff-waiting', content:
|
|
538
|
+
setMessages(prev => prev.some(message => message.isWaiting) ? prev : [...prev, { id: 'handoff-waiting', content: strings.handoffWaiting, sender: 'bot', timestamp: new Date().toISOString(), isWaiting: true }])
|
|
531
539
|
return
|
|
532
540
|
}
|
|
533
541
|
|
|
@@ -556,10 +564,7 @@ const AndyChat: React.FC<AndyChatProps> = ({
|
|
|
556
564
|
console.error('AndyChat: Message request failed.')
|
|
557
565
|
const errorMessage: Message = {
|
|
558
566
|
id: timestamp + 3,
|
|
559
|
-
content:
|
|
560
|
-
config?.defaultLang === 'es'
|
|
561
|
-
? 'Lo siento, no pude responder. Inténtalo de nuevo.'
|
|
562
|
-
: 'Sorry, I could not answer. Please try again.',
|
|
567
|
+
content: strings.sendFailure,
|
|
563
568
|
sender: 'bot',
|
|
564
569
|
timestamp: new Date().toISOString(),
|
|
565
570
|
isError: true
|
|
@@ -704,7 +709,7 @@ const AndyChat: React.FC<AndyChatProps> = ({
|
|
|
704
709
|
|
|
705
710
|
const isPillStyle = config?.bubbleStyle === 'pill'
|
|
706
711
|
const displayLabel =
|
|
707
|
-
bubbleLabel || config?.bubbleLabel || (isPillStyle ? getDefaultBubbleLabel(
|
|
712
|
+
bubbleLabel || config?.bubbleLabel || (isPillStyle ? getDefaultBubbleLabel(uiLang) : null)
|
|
708
713
|
const bubbleLogoUrl = config?.logoUrl || CHAT_BUBBLE_DEFAULT_ICON_URL
|
|
709
714
|
|
|
710
715
|
if (bubble) {
|
|
@@ -951,7 +956,7 @@ const AndyChat: React.FC<AndyChatProps> = ({
|
|
|
951
956
|
)}
|
|
952
957
|
</div>
|
|
953
958
|
<span className='andy-bot-header__name'>
|
|
954
|
-
{message.isHuman ?
|
|
959
|
+
{message.isHuman ? strings.teamName : config?.name || 'Andy bot'}
|
|
955
960
|
</span>
|
|
956
961
|
</div>
|
|
957
962
|
<div className='andy-message__content'>
|
|
@@ -984,15 +989,15 @@ const AndyChat: React.FC<AndyChatProps> = ({
|
|
|
984
989
|
</div>
|
|
985
990
|
|
|
986
991
|
<div className='andy-chat-window__bottom'>
|
|
987
|
-
{
|
|
988
|
-
|
|
992
|
+
{activeQuestions &&
|
|
993
|
+
activeQuestions.length > 0 &&
|
|
989
994
|
showPredefinedQuestions && (
|
|
990
995
|
<div className='andy-predefined-questions' id='andy-predefined-questions'>
|
|
991
996
|
<div className='andy-predefined-questions__header'>
|
|
992
|
-
<p className='andy-predefined-questions__title'>
|
|
997
|
+
<p className='andy-predefined-questions__title'>{strings.predefinedQuestionsTitle}</p>
|
|
993
998
|
</div>
|
|
994
999
|
<div className='andy-predefined-questions__list'>
|
|
995
|
-
{
|
|
1000
|
+
{activeQuestions.map((q, index) => (
|
|
996
1001
|
<button
|
|
997
1002
|
key={index}
|
|
998
1003
|
type='button'
|
|
@@ -1015,7 +1020,7 @@ const AndyChat: React.FC<AndyChatProps> = ({
|
|
|
1015
1020
|
type='text'
|
|
1016
1021
|
className='andy-input__field'
|
|
1017
1022
|
id='andy-message-input'
|
|
1018
|
-
placeholder={config ?
|
|
1023
|
+
placeholder={config ? strings.inputPlaceholder : '...'}
|
|
1019
1024
|
aria-label='Message input'
|
|
1020
1025
|
onKeyDown={e => {
|
|
1021
1026
|
if (e.key === 'Enter' && (e.target as HTMLInputElement).value.trim()) {
|
package/src/types/index.ts
CHANGED
|
@@ -90,6 +90,10 @@ export interface AndyChatProps {
|
|
|
90
90
|
welcomeMessage?: string
|
|
91
91
|
/** Optional custom label for pill-style bubble (overrides default) */
|
|
92
92
|
bubbleLabel?: string
|
|
93
|
+
/** Optional UI language for the widget's own chrome, overrides the Agent's defaultLang */
|
|
94
|
+
lang?: 'en' | 'es'
|
|
95
|
+
/** Optional starter questions (overrides API value) */
|
|
96
|
+
predefinedQuestions?: PredefinedQuestion[]
|
|
93
97
|
/** Optional theme ('light' | 'dark' | 'auto') */
|
|
94
98
|
theme?: 'light' | 'dark' | 'auto'
|
|
95
99
|
/** Optional position ('left' | 'right') */
|