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
package/dist/index.esm.js
CHANGED
|
@@ -3433,6 +3433,34 @@ const SVG_ICONS = {
|
|
|
3433
3433
|
<path d="M7.41 8.59L12 13.17l4.59-4.58L18 10l-6 6-6-6 1.41-1.41z" />
|
|
3434
3434
|
</svg>`};
|
|
3435
3435
|
|
|
3436
|
+
// Localized UI Strings
|
|
3437
|
+
// Chrome the widget renders itself, as opposed to copy the Agent supplies.
|
|
3438
|
+
// Keyed by language so React and Vanilla render identical text for a visitor.
|
|
3439
|
+
const UI_STRINGS = {
|
|
3440
|
+
en: {
|
|
3441
|
+
inputPlaceholder: 'Type your message...',
|
|
3442
|
+
predefinedQuestionsTitle: 'What would you like to know?',
|
|
3443
|
+
sendFailure: 'Sorry, I could not answer. Please try again.',
|
|
3444
|
+
handoffWaiting: 'A team member will reply soon.',
|
|
3445
|
+
teamName: 'Team'
|
|
3446
|
+
},
|
|
3447
|
+
es: {
|
|
3448
|
+
inputPlaceholder: 'Escribe tu mensaje...',
|
|
3449
|
+
predefinedQuestionsTitle: '¿Qué te gustaría saber?',
|
|
3450
|
+
sendFailure: 'Lo siento, no pude responder. Inténtalo de nuevo.',
|
|
3451
|
+
handoffWaiting: 'Un miembro del equipo te responderá pronto.',
|
|
3452
|
+
teamName: 'Equipo'
|
|
3453
|
+
}
|
|
3454
|
+
};
|
|
3455
|
+
|
|
3456
|
+
/**
|
|
3457
|
+
* Get the widget's own UI strings for a language.
|
|
3458
|
+
* Unknown languages fall back to English rather than rendering blanks.
|
|
3459
|
+
* @param {string} [lang] - Language code ('en' or 'es')
|
|
3460
|
+
* @returns {typeof UI_STRINGS.en} The localized string set
|
|
3461
|
+
*/
|
|
3462
|
+
const getUiStrings = lang => UI_STRINGS[lang] || UI_STRINGS.en;
|
|
3463
|
+
|
|
3436
3464
|
/**
|
|
3437
3465
|
* Keyboard detection utility for handling mobile virtual keyboards
|
|
3438
3466
|
* Provides cross-browser support for detecting keyboard open/close events
|
|
@@ -3851,8 +3879,13 @@ const createBrowserHandoff = (chatbotId, bootstrap, onProjection) => {
|
|
|
3851
3879
|
}
|
|
3852
3880
|
};
|
|
3853
3881
|
|
|
3854
|
-
const AndyChat = ({ embedId, tooltip, name, headline, description, welcomeMessage, bubbleLabel, theme, orientation, brandColor, bubbleStyle, useBrandColor, logoUrl, previewMode = false, initialOpen = false }) => {
|
|
3882
|
+
const AndyChat = ({ embedId, tooltip, name, headline, description, welcomeMessage, bubbleLabel, lang, predefinedQuestions, theme, orientation, brandColor, bubbleStyle, useBrandColor, logoUrl, previewMode = false, initialOpen = false }) => {
|
|
3855
3883
|
const [config, setConfig] = useState(null);
|
|
3884
|
+
// The visitor's language wins over the Agent's own default: a Spanish Agent
|
|
3885
|
+
// embedded on an English page must still render English chrome.
|
|
3886
|
+
const uiLang = lang || config?.defaultLang || 'en';
|
|
3887
|
+
const strings = getUiStrings(uiLang);
|
|
3888
|
+
const activeQuestions = predefinedQuestions?.length ? predefinedQuestions : config?.predefinedQuestions;
|
|
3856
3889
|
const [isOpen, setIsOpen] = useState(initialOpen);
|
|
3857
3890
|
const [messages, setMessages] = useState([]);
|
|
3858
3891
|
const [isLoading, setIsLoading] = useState(false);
|
|
@@ -3883,7 +3916,7 @@ const AndyChat = ({ embedId, tooltip, name, headline, description, welcomeMessag
|
|
|
3883
3916
|
pendingHandoffIdsRef.current = projection.pendingProjectionIds || [];
|
|
3884
3917
|
const projectedMessages = projection.messages.map(message => ({ id: message.id, content: message.content, sender: message.role === 'user' ? 'user' : 'bot', timestamp: new Date(message.createdAt).toISOString(), isHuman: message.sentByHuman }));
|
|
3885
3918
|
setMessages(projection.control === 'requested' || projection.control === 'human'
|
|
3886
|
-
? [...projectedMessages, { id: 'handoff-waiting', content:
|
|
3919
|
+
? [...projectedMessages, { id: 'handoff-waiting', content: strings.handoffWaiting, sender: 'bot', timestamp: new Date().toISOString(), isWaiting: true }]
|
|
3887
3920
|
: projectedMessages);
|
|
3888
3921
|
});
|
|
3889
3922
|
handoffRef.current = handoff;
|
|
@@ -4072,12 +4105,12 @@ const AndyChat = ({ embedId, tooltip, name, headline, description, welcomeMessag
|
|
|
4072
4105
|
bubbleStyle: bubbleStyle || 'icon',
|
|
4073
4106
|
bubbleLabel: bubbleLabel || null,
|
|
4074
4107
|
useBrandColor: useBrandColor !== undefined ? useBrandColor : true,
|
|
4075
|
-
defaultLang:
|
|
4108
|
+
defaultLang: uiLang,
|
|
4076
4109
|
showBranding: true,
|
|
4077
4110
|
showWelcomePopup: { enabled: false, seconds: 3, message: '' },
|
|
4078
4111
|
collectUserInfo: { enabled: false, message: '' },
|
|
4079
4112
|
welcomeMessage: welcomeMessage || 'Hi there! How can I help you today?',
|
|
4080
|
-
predefinedQuestions: [],
|
|
4113
|
+
predefinedQuestions: predefinedQuestions || [],
|
|
4081
4114
|
faqs: []
|
|
4082
4115
|
};
|
|
4083
4116
|
setConfig(previewConfig);
|
|
@@ -4230,7 +4263,7 @@ const AndyChat = ({ embedId, tooltip, name, headline, description, welcomeMessag
|
|
|
4230
4263
|
setIsLoading(true);
|
|
4231
4264
|
const response = await sendMessageForWidget(embedId, sessionId, messageText);
|
|
4232
4265
|
if (response.status === 'waiting') {
|
|
4233
|
-
setMessages(prev => prev.some(message => message.isWaiting) ? prev : [...prev, { id: 'handoff-waiting', content:
|
|
4266
|
+
setMessages(prev => prev.some(message => message.isWaiting) ? prev : [...prev, { id: 'handoff-waiting', content: strings.handoffWaiting, sender: 'bot', timestamp: new Date().toISOString(), isWaiting: true }]);
|
|
4234
4267
|
return;
|
|
4235
4268
|
}
|
|
4236
4269
|
const botMessage = {
|
|
@@ -4257,9 +4290,7 @@ const AndyChat = ({ embedId, tooltip, name, headline, description, welcomeMessag
|
|
|
4257
4290
|
console.error('AndyChat: Message request failed.');
|
|
4258
4291
|
const errorMessage = {
|
|
4259
4292
|
id: timestamp + 3,
|
|
4260
|
-
content:
|
|
4261
|
-
? 'Lo siento, no pude responder. Inténtalo de nuevo.'
|
|
4262
|
-
: 'Sorry, I could not answer. Please try again.',
|
|
4293
|
+
content: strings.sendFailure,
|
|
4263
4294
|
sender: 'bot',
|
|
4264
4295
|
timestamp: new Date().toISOString(),
|
|
4265
4296
|
isError: true
|
|
@@ -4375,7 +4406,7 @@ const AndyChat = ({ embedId, tooltip, name, headline, description, welcomeMessag
|
|
|
4375
4406
|
bubble.addEventListener('click', () => setIsOpen(prev => !prev));
|
|
4376
4407
|
}
|
|
4377
4408
|
const isPillStyle = config?.bubbleStyle === 'pill';
|
|
4378
|
-
const displayLabel = bubbleLabel || config?.bubbleLabel || (isPillStyle ? getDefaultBubbleLabel(
|
|
4409
|
+
const displayLabel = bubbleLabel || config?.bubbleLabel || (isPillStyle ? getDefaultBubbleLabel(uiLang) : null);
|
|
4379
4410
|
const bubbleLogoUrl = config?.logoUrl || CHAT_BUBBLE_DEFAULT_ICON_URL;
|
|
4380
4411
|
if (bubble) {
|
|
4381
4412
|
bubble.className = 'andy-chat-bubble';
|
|
@@ -4428,10 +4459,10 @@ const AndyChat = ({ embedId, tooltip, name, headline, description, welcomeMessag
|
|
|
4428
4459
|
if (message.isLoading) {
|
|
4429
4460
|
return (jsx("div", { className: 'andy-message-container andy-message-container--bot andy-message-container--loading', children: jsx("div", { className: 'andy-message andy-message--bot', children: jsxs("div", { className: 'andy-typing-indicator', children: [jsx("div", { className: 'andy-typing-indicator__dot' }), jsx("div", { className: 'andy-typing-indicator__dot' }), jsx("div", { className: 'andy-typing-indicator__dot' })] }) }) }, message.id));
|
|
4430
4461
|
}
|
|
4431
|
-
return (jsxs("div", { className: `andy-message-container andy-message-container--${message.sender} ${message.isWaiting ? 'andy-message-container--waiting' : ''}`, children: [message.sender === 'bot' && (jsxs("div", { className: `andy-message andy-message--bot ${message.isHuman ? 'andy-message--operator' : ''} ${message.isWaiting ? 'andy-message--waiting' : ''} ${message.isError ? 'andy-message--error' : ''}`, children: [jsxs("div", { className: 'andy-bot-header', children: [jsx("div", { className: 'andy-bot-header__icon', children: config?.logoUrl ? (jsx("img", { src: config.logoUrl, alt: 'Bot Avatar', className: 'andy-bot-header__icon-image' })) : (jsx("img", { src: CHAT_BUBBLE_DEFAULT_ICON_URL, alt: 'Bot Avatar', className: 'andy-bot-header__icon-image andy-bot-header__icon-image--default' })) }), jsx("span", { className: 'andy-bot-header__name', children: message.isHuman ?
|
|
4432
|
-
}), isLoading && (jsx("div", { className: 'andy-message-container andy-message-container--bot andy-message-container--typing', children: jsx("div", { className: 'andy-message andy-message--bot andy-message--typing', children: jsxs("div", { className: 'andy-typing-indicator', children: [jsx("div", { className: 'andy-typing-indicator__dot' }), jsx("div", { className: 'andy-typing-indicator__dot' }), jsx("div", { className: 'andy-typing-indicator__dot' })] }) }) }))] }), jsxs("div", { className: 'andy-chat-window__bottom', children: [
|
|
4433
|
-
|
|
4434
|
-
showPredefinedQuestions && (jsxs("div", { className: 'andy-predefined-questions', id: 'andy-predefined-questions', children: [jsx("div", { className: 'andy-predefined-questions__header', children: jsx("p", { className: 'andy-predefined-questions__title', children:
|
|
4462
|
+
return (jsxs("div", { className: `andy-message-container andy-message-container--${message.sender} ${message.isWaiting ? 'andy-message-container--waiting' : ''}`, children: [message.sender === 'bot' && (jsxs("div", { className: `andy-message andy-message--bot ${message.isHuman ? 'andy-message--operator' : ''} ${message.isWaiting ? 'andy-message--waiting' : ''} ${message.isError ? 'andy-message--error' : ''}`, children: [jsxs("div", { className: 'andy-bot-header', children: [jsx("div", { className: 'andy-bot-header__icon', children: config?.logoUrl ? (jsx("img", { src: config.logoUrl, alt: 'Bot Avatar', className: 'andy-bot-header__icon-image' })) : (jsx("img", { src: CHAT_BUBBLE_DEFAULT_ICON_URL, alt: 'Bot Avatar', className: 'andy-bot-header__icon-image andy-bot-header__icon-image--default' })) }), jsx("span", { className: 'andy-bot-header__name', children: message.isHuman ? strings.teamName : config?.name || 'Andy bot' })] }), jsx("div", { className: 'andy-message__content', children: jsx("div", { dangerouslySetInnerHTML: { __html: parseMarkdown(message.content) } }) })] })), message.sender === 'user' && (jsx("div", { className: 'andy-message andy-message--user', children: jsx("div", { className: 'andy-message__content', children: jsx("p", { children: message.content }) }) }))] }, message.id));
|
|
4463
|
+
}), isLoading && (jsx("div", { className: 'andy-message-container andy-message-container--bot andy-message-container--typing', children: jsx("div", { className: 'andy-message andy-message--bot andy-message--typing', children: jsxs("div", { className: 'andy-typing-indicator', children: [jsx("div", { className: 'andy-typing-indicator__dot' }), jsx("div", { className: 'andy-typing-indicator__dot' }), jsx("div", { className: 'andy-typing-indicator__dot' })] }) }) }))] }), jsxs("div", { className: 'andy-chat-window__bottom', children: [activeQuestions &&
|
|
4464
|
+
activeQuestions.length > 0 &&
|
|
4465
|
+
showPredefinedQuestions && (jsxs("div", { className: 'andy-predefined-questions', id: 'andy-predefined-questions', children: [jsx("div", { className: 'andy-predefined-questions__header', children: jsx("p", { className: 'andy-predefined-questions__title', children: strings.predefinedQuestionsTitle }) }), jsx("div", { className: 'andy-predefined-questions__list', children: activeQuestions.map((q, index) => (jsxs("button", { type: 'button', className: 'andy-predefined-question', "data-question": q.question, disabled: isCollectingUserInfo || isLoading || !config, children: [jsx("span", { className: 'andy-predefined-question__icon', children: "\uD83D\uDCAC" }), jsx("span", { className: 'andy-predefined-question__text', children: q.question })] }, index))) })] })), jsx("div", { className: 'andy-chat-window__input', children: jsx("div", { className: 'andy-input-container', children: jsxs("div", { className: 'andy-input', children: [jsx("input", { type: 'text', className: 'andy-input__field', id: 'andy-message-input', placeholder: config ? strings.inputPlaceholder : '...', "aria-label": 'Message input', onKeyDown: e => {
|
|
4435
4466
|
if (e.key === 'Enter' && e.target.value.trim()) {
|
|
4436
4467
|
handleSendMessage(e.target.value);
|
|
4437
4468
|
e.target.value = '';
|