@xapp/chat-widget 1.81.5 → 1.83.1
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/components/ChatFooter/ChatFooter.d.ts +0 -0
- package/dist/components/ChatWidget/ChatWidget.d.ts +0 -0
- package/dist/components/ChatWidget/ChatWidgetContainer.d.ts +0 -0
- package/dist/components/ChatWidget/StaticChatWidgetContainer.d.ts +0 -0
- package/dist/components/ChatWidget/StaticMessagesChatWidgetContainer.d.ts +0 -0
- package/dist/components/ChatWidget/index.d.ts +0 -0
- package/dist/components/MessageList/MessageList.d.ts +0 -0
- package/dist/index.css +1 -1
- package/dist/index.es.js +683 -531
- package/dist/index.es.js.map +1 -1
- package/dist/index.js +1121 -969
- package/dist/index.js.map +1 -1
- package/dist/xapp-chat-widget.css +1 -1
- package/dist/xapp-chat-widget.js +2 -2
- package/dist/xapp-chat-widget.js.map +1 -1
- package/package.json +9 -9
package/dist/index.es.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import require$$1, { useRef, useEffect, useCallback, createContext,
|
|
1
|
+
import require$$1, { useRef, useEffect, useCallback, createContext, useContext, useMemo, memo, useState, useLayoutEffect } from 'react';
|
|
2
2
|
export { default as React } from 'react';
|
|
3
3
|
import require$$0, { jsx, Fragment, jsxs } from 'react/jsx-runtime';
|
|
4
4
|
import { useSelector, useDispatch, Provider } from 'react-redux';
|
|
@@ -1612,7 +1612,7 @@ var RichText = function (props) {
|
|
|
1612
1612
|
};
|
|
1613
1613
|
|
|
1614
1614
|
var RichInput = function (props) {
|
|
1615
|
-
var id = props.id, value = props.value, type = props.type, autoFocus = props.autoFocus, spellCheck = props.spellCheck, tabIndex = props.tabIndex, onChange = props.onChange, onInput = props.onInput, onKeyDown = props.onKeyDown, onSearch = props.onSearch;
|
|
1615
|
+
var id = props.id, value = props.value, type = props.type, autoFocus = props.autoFocus, spellCheck = props.spellCheck, tabIndex = props.tabIndex, maxLength = props.maxLength, onChange = props.onChange, onInput = props.onInput, onKeyDown = props.onKeyDown, onSearch = props.onSearch;
|
|
1616
1616
|
var rich = value.formats.some(function (f) { return f.type === "inputText"; });
|
|
1617
1617
|
var handleChange = react.useCallback(function (ev) {
|
|
1618
1618
|
if (onChange) {
|
|
@@ -1665,7 +1665,7 @@ var RichInput = function (props) {
|
|
|
1665
1665
|
}
|
|
1666
1666
|
return undefined;
|
|
1667
1667
|
}, [inputNode, onSearch]);
|
|
1668
|
-
return (jsxRuntime.jsx("div", { className: "xappw-rich-input ".concat(props.className), children: rich ? (jsxRuntime.jsx(RichText, { id: id, value: value, onChange: handleRichChange, onInput: handleRichInput, onKeyDown: handleKeyDown, className: "xappw-rich-input__input ".concat(props.className, "__input") })) : (jsxRuntime.jsx("input", { id: id, ref: inputRef, type: type, value: value.text, autoComplete: "off", autoFocus: autoFocus, placeholder: props.placeholder, spellCheck: spellCheck, tabIndex: tabIndex ? Number(tabIndex) : 0, className: "xappw-rich-input__input ".concat(props.className, "__input"), onFocus: props.onFocus, onChange: handleChange, onInput: handleInput, onKeyDown: handleKeyDown })) }));
|
|
1668
|
+
return (jsxRuntime.jsx("div", { className: "xappw-rich-input ".concat(props.className), children: rich ? (jsxRuntime.jsx(RichText, { id: id, value: value, onChange: handleRichChange, onInput: handleRichInput, onKeyDown: handleKeyDown, className: "xappw-rich-input__input ".concat(props.className, "__input") })) : (jsxRuntime.jsx("input", { id: id, ref: inputRef, type: type, value: value.text, autoComplete: "off", autoFocus: autoFocus, placeholder: props.placeholder, spellCheck: spellCheck, tabIndex: tabIndex ? Number(tabIndex) : 0, maxLength: maxLength, className: "xappw-rich-input__input ".concat(props.className, "__input"), onFocus: props.onFocus, onChange: handleChange, onInput: handleInput, onKeyDown: handleKeyDown })) }));
|
|
1669
1669
|
};
|
|
1670
1670
|
|
|
1671
1671
|
var SuggestionsGroupHeading = function (props) {
|
|
@@ -2541,6 +2541,8 @@ var StentorDirectChat = /** @class */ (function () {
|
|
|
2541
2541
|
if (origin) {
|
|
2542
2542
|
attributes["origin"] = origin;
|
|
2543
2543
|
}
|
|
2544
|
+
// Add current time for accurate date/time responses
|
|
2545
|
+
attributes["currentTime"] = new Date().toISOString();
|
|
2544
2546
|
now = new Date().getTime();
|
|
2545
2547
|
if (this.isNewSession && !((_a = message === null || message === void 0 ? void 0 : message.msg) === null || _a === void 0 ? void 0 : _a.text)) {
|
|
2546
2548
|
request = {
|
|
@@ -3767,6 +3769,8 @@ var StentorRouterChat = /** @class */ (function () {
|
|
|
3767
3769
|
if (origin) {
|
|
3768
3770
|
attributes["origin"] = origin;
|
|
3769
3771
|
}
|
|
3772
|
+
// Add current time for accurate date/time responses
|
|
3773
|
+
attributes["currentTime"] = new Date().toISOString();
|
|
3770
3774
|
request = requestFromMessage(message, userId, this.isNewSession, sessionId, accessToken, attributes, this.visitorInfo);
|
|
3771
3775
|
// Router attributes are now added at the payload root level in emit()
|
|
3772
3776
|
this.emit("new message", request);
|
|
@@ -9046,7 +9050,7 @@ var ChatMessage = function (props) {
|
|
|
9046
9050
|
var agentInfo = (_a = props.agents) === null || _a === void 0 ? void 0 : _a[props.message.user.nick];
|
|
9047
9051
|
var hideUserInfo = (agentInfo === null || agentInfo === void 0 ? void 0 : agentInfo.hideUserInfo) || false;
|
|
9048
9052
|
function renderByType() {
|
|
9049
|
-
var _a, _b, _c, _d;
|
|
9053
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
|
|
9050
9054
|
var msg = props.message.msg;
|
|
9051
9055
|
switch (props.message.type) {
|
|
9052
9056
|
// TODO: props actually requires it to be "chat.msg". Fix prop typing?
|
|
@@ -9055,15 +9059,15 @@ var ChatMessage = function (props) {
|
|
|
9055
9059
|
// OR card OR list only. Avatar with text bubble.
|
|
9056
9060
|
var avaKey = avaKeys.find(function (key) { return !!msg[key]; });
|
|
9057
9061
|
return (jsxs(Fragment, { children: [msg.text &&
|
|
9058
|
-
jsx(ChatMessagePart, { showAvatar: avaKey === "text", user: user, avatarPosition: (_a = chatConfig.env.theme.messages) === null ||
|
|
9059
|
-
jsx(ChatMessagePart, { showAvatar: avaKey === "html", user: user, avatarPosition: (
|
|
9062
|
+
jsx(ChatMessagePart, { showAvatar: avaKey === "text", user: user, avatarPosition: (_c = (_b = (_a = chatConfig === null || chatConfig === void 0 ? void 0 : chatConfig.env) === null || _a === void 0 ? void 0 : _a.theme) === null || _b === void 0 ? void 0 : _b.messages) === null || _c === void 0 ? void 0 : _c.avatarPosition, hideUserInfo: hideUserInfo, children: jsx(ChatTextMessage, { message: props.message, sibling: props.sibling }) }), msg.html &&
|
|
9063
|
+
jsx(ChatMessagePart, { showAvatar: avaKey === "html", user: user, avatarPosition: (_f = (_e = (_d = chatConfig === null || chatConfig === void 0 ? void 0 : chatConfig.env) === null || _d === void 0 ? void 0 : _d.theme) === null || _e === void 0 ? void 0 : _e.messages) === null || _f === void 0 ? void 0 : _f.avatarPosition, hideUserInfo: hideUserInfo, children: jsx(ChatMarkdownMessage, { message: props.message, sibling: props.sibling, onOpenUrl: (_g = props.middlewareContext) === null || _g === void 0 ? void 0 : _g.openUrl }) }), msg.displays && middleware && msg.displays.map(function (display, index) {
|
|
9060
9064
|
if (display.type === "ScheduleButton") {
|
|
9061
9065
|
return (jsx(ChatScheduleWidget, { minimizeOnClick: props.minimizeOnClick, display: display }));
|
|
9062
9066
|
}
|
|
9063
9067
|
var Middleware = middleware;
|
|
9064
9068
|
return (jsx(Middleware, { msg: display, ctx: props.middlewareContext }, index));
|
|
9065
9069
|
}), msg.permissionRequest && ctx &&
|
|
9066
|
-
jsx(ChatMessagePart, { showAvatar: avaKey === "permissionRequest", user: user, avatarPosition: (
|
|
9070
|
+
jsx(ChatMessagePart, { showAvatar: avaKey === "permissionRequest", user: user, avatarPosition: (_k = (_j = (_h = chatConfig === null || chatConfig === void 0 ? void 0 : chatConfig.env) === null || _h === void 0 ? void 0 : _h.theme) === null || _j === void 0 ? void 0 : _j.messages) === null || _k === void 0 ? void 0 : _k.avatarPosition, hideUserInfo: hideUserInfo, children: jsx(ChatPermissionMessage, { message: props.message, sibling: props.sibling, ctx: ctx }) })] }));
|
|
9067
9071
|
}
|
|
9068
9072
|
return (jsx(Fragment, {}));
|
|
9069
9073
|
}
|
|
@@ -9170,10 +9174,12 @@ function useChatServerVisitorId() {
|
|
|
9170
9174
|
}
|
|
9171
9175
|
//send whenever server settings or visitor id changes
|
|
9172
9176
|
function useGreeting(active) {
|
|
9177
|
+
var _a, _b;
|
|
9173
9178
|
var curr = useChatServerVisitorId();
|
|
9174
9179
|
var snapshotRef = useRef(null);
|
|
9175
9180
|
var ctx = useContext(ChatConfigContext);
|
|
9176
|
-
|
|
9181
|
+
// Handle null context (e.g., in preview mode)
|
|
9182
|
+
var isAdmin = (_b = (_a = ctx === null || ctx === void 0 ? void 0 : ctx.env) === null || _a === void 0 ? void 0 : _a.isAdmin) !== null && _b !== void 0 ? _b : false;
|
|
9177
9183
|
var sessionId = useSelector(function (state) { return state.sessionId; });
|
|
9178
9184
|
useEffect(function () {
|
|
9179
9185
|
if (active) {
|
|
@@ -9452,10 +9458,16 @@ var SendButton = function (props) {
|
|
|
9452
9458
|
return (jsx(Fragment, { children: !props.sendButtonIcon ? (jsx(IconButton_1, { className: "xappw-send-button ".concat(props.className || "", " ").concat(disabled ? 'disabled' : ''), tabIndex: props.tabIndex, onClick: disabled ? undefined : props.onClick, icon: SendIcon })) : (jsx("button", { className: "xappw-custom-send-button ".concat(disabled ? 'disabled' : ''), tabIndex: props.tabIndex ? Number(props.tabIndex) : 0, onClick: props.onClick, disabled: disabled, onMouseEnter: function () { return setIsHovered(true); }, onMouseLeave: function () { return setIsHovered(false); }, children: jsx("img", { src: getIconSrc(), alt: "Send button", draggable: false, className: "send-button-icon" }) })) }));
|
|
9453
9459
|
};
|
|
9454
9460
|
|
|
9461
|
+
// Show counter when within this percentage of the limit
|
|
9462
|
+
var COUNTER_THRESHOLD_PERCENT = 0.8;
|
|
9455
9463
|
var Input = function (props) {
|
|
9456
9464
|
var _a, _b;
|
|
9457
9465
|
var value = props.value, placeholder = props.placeholder, sendButtonIcon = props.sendButtonIcon, sendButtonIconHover = props.sendButtonIconHover, sendButtonIconDisabled = props.sendButtonIconDisabled, suggestion = props.suggestion, footerConfig = props.footerConfig, inputConfig = props.inputConfig, onChange = props.onChange, onSubmit = props.onSubmit, onSuggestionCommand = props.onSuggestionCommand;
|
|
9458
9466
|
var _c = useState(false), dragover = _c[0], setDragover = _c[1];
|
|
9467
|
+
var maxLength = inputConfig === null || inputConfig === void 0 ? void 0 : inputConfig.maxLength;
|
|
9468
|
+
var currentLength = value.text.length;
|
|
9469
|
+
var isAtLimit = maxLength !== undefined && currentLength >= maxLength;
|
|
9470
|
+
var showCounter = maxLength !== undefined && currentLength >= maxLength * COUNTER_THRESHOLD_PERCENT;
|
|
9459
9471
|
function onDragOver(event) {
|
|
9460
9472
|
setDragover(true);
|
|
9461
9473
|
event.preventDefault();
|
|
@@ -9503,9 +9515,9 @@ var Input = function (props) {
|
|
|
9503
9515
|
return (jsx("div", { className: "xappw-input-container ".concat(props.addClass, " ").concat(dragover ? "drag-drop-zone" : ""), "aria-label": "To start typing click on rounded rectangle at the bottom of widget. To send your message click icon on right side of rounded rectangle at the bottom of widget" +
|
|
9504
9516
|
value.text
|
|
9505
9517
|
? "To clear input field click on clear icon on the left of send button"
|
|
9506
|
-
: "", "aria-hidden": false, onDrop: onDrop, onDragOver: onDragOver, onDragLeave: onDragLeave, children: jsxs("form", { className: "xappw-input-form", onSubmit: handleOnSubmit, children: [jsx(RichInput_1, { id: "chatWidgetInput", className: "xappw-input", placeholder: placeholder !== null && placeholder !== void 0 ? placeholder : "type your question here", tabIndex: inputConfig === null || inputConfig === void 0 ? void 0 : inputConfig.tabIndex, onInput: onChange, onChange: onChange, onKeyDown: handleKeyDown,
|
|
9518
|
+
: "", "aria-hidden": false, onDrop: onDrop, onDragOver: onDragOver, onDragLeave: onDragLeave, children: jsxs("form", { className: "xappw-input-form", onSubmit: handleOnSubmit, children: [jsx(RichInput_1, { id: "chatWidgetInput", className: "xappw-input", placeholder: placeholder !== null && placeholder !== void 0 ? placeholder : "type your question here", tabIndex: inputConfig === null || inputConfig === void 0 ? void 0 : inputConfig.tabIndex, maxLength: maxLength, onInput: onChange, onChange: onChange, onKeyDown: handleKeyDown,
|
|
9507
9519
|
// onFocus={onFocus}
|
|
9508
|
-
value: value, spellCheck: true }, "input"), jsxs("div", { className: "xappw-input-form__buttons", children: [value.text && (jsx(IconButton_1, { icon: CloseIcon, tabIndex: (_a = footerConfig === null || footerConfig === void 0 ? void 0 : footerConfig.clearButton) === null || _a === void 0 ? void 0 : _a.tabIndex, className: "xappw-input-form__btn", onClick: handleClear })), jsx(SendButton, { className: "xappw-input-form__btn", sendButtonIcon: sendButtonIcon, sendButtonIconHover: sendButtonIconHover, sendButtonIconDisabled: sendButtonIconDisabled, tabIndex: (_b = footerConfig === null || footerConfig === void 0 ? void 0 : footerConfig.sendButton) === null || _b === void 0 ? void 0 : _b.tabIndex, disabled: !value.text, onClick: handleOnSubmit })] })] }) }));
|
|
9520
|
+
value: value, spellCheck: true }, "input"), jsxs("div", { className: "xappw-input-form__buttons", children: [showCounter && (jsxs("span", { className: "xappw-input-form__counter".concat(isAtLimit ? " xappw-input-form__counter--limit" : ""), children: [currentLength, "/", maxLength] })), value.text && (jsx(IconButton_1, { icon: CloseIcon, tabIndex: (_a = footerConfig === null || footerConfig === void 0 ? void 0 : footerConfig.clearButton) === null || _a === void 0 ? void 0 : _a.tabIndex, className: "xappw-input-form__btn", onClick: handleClear })), jsx(SendButton, { className: "xappw-input-form__btn", sendButtonIcon: sendButtonIcon, sendButtonIconHover: sendButtonIconHover, sendButtonIconDisabled: sendButtonIconDisabled, tabIndex: (_b = footerConfig === null || footerConfig === void 0 ? void 0 : footerConfig.sendButton) === null || _b === void 0 ? void 0 : _b.tabIndex, disabled: !value.text, onClick: handleOnSubmit })] })] }) }));
|
|
9509
9521
|
};
|
|
9510
9522
|
|
|
9511
9523
|
function createActions(onItemUse) {
|
|
@@ -9566,7 +9578,7 @@ var Suggestions = function (props) {
|
|
|
9566
9578
|
|
|
9567
9579
|
var ChatFooter = function (props) {
|
|
9568
9580
|
var _a, _b, _c;
|
|
9569
|
-
var isAdmin = props.isAdmin, isChatting = props.isChatting, visible = props.visible, placeholder = props.placeholder, sendButtonIcon = props.sendButtonIcon, sendButtonIconHover = props.sendButtonIconHover, sendButtonIconDisabled = props.sendButtonIconDisabled, footerConfig = props.footerConfig, menuConfig = props.menuConfig, inputConfig = props.inputConfig, hasWsButton = props.hasWsButton, onSubmit = props.onSubmit;
|
|
9581
|
+
var isAdmin = props.isAdmin, isChatting = props.isChatting, visible = props.visible, placeholder = props.placeholder, sendButtonIcon = props.sendButtonIcon, sendButtonIconHover = props.sendButtonIconHover, sendButtonIconDisabled = props.sendButtonIconDisabled, footerConfig = props.footerConfig, menuConfig = props.menuConfig, inputConfig = props.inputConfig, hasWsButton = props.hasWsButton, disabled = props.disabled, onSubmit = props.onSubmit;
|
|
9570
9582
|
var innerDispatch = useChatDispatch();
|
|
9571
9583
|
var _d = useState(false), drawerOpen = _d[0], setDrawerState = _d[1]; // false initially
|
|
9572
9584
|
var _e = useState(), suggestionSearch = _e[0], setSuggestionSearch = _e[1];
|
|
@@ -9624,7 +9636,7 @@ var ChatFooter = function (props) {
|
|
|
9624
9636
|
setEnableInput(status);
|
|
9625
9637
|
};
|
|
9626
9638
|
return (jsxs("div", { className: "chat-footer background-footer", "aria-label": menuItems.length ? "to open menu click a button above the rounded rectangle at the bottom of widget" : "", "aria-hidden": false, children: [showMenu && menuItems.length ?
|
|
9627
|
-
jsxs(Fragment, { children: [drawerOpen ? jsx(ChatMenu, { opened: drawerOpen, tabIndex: menuItemsTabIndex, onItemClick: handleMenuItem, items: menuItems }) : jsx(Fragment, {}), jsx("div", { className: "chat-footer__menu-icon", children: jsx(DrawerBars, { tabIndex: menuButtonTabIndex, onToggle: toggleDrawer }) })] }) : jsx(Fragment, {}), jsx(Suggestions, { className: "xappw-chat-footer__suggestions", data: suggestions.suggestions, index: suggestions.index, searchTerms: suggestionSearch, hasWsButton: hasWsButton, onItemClick: handleItemClick, onItemUse: handleItemUse }), isAdmin && isChatting && visible && jsx(AdminBar, { onAdminJoin: handleAdminJoin }), jsx("div", { style: { pointerEvents: enableInput ? "auto" : "none", opacity: enableInput ? 1 : 0.5 }, children: jsx(Input, { addClass: "chat-footer__input " + (isChatting && visible ? "visible" : ""), suggestion: suggestions.item, value: input, placeholder: placeholder, sendButtonIcon: sendButtonIcon, sendButtonIconHover: sendButtonIconHover, sendButtonIconDisabled: sendButtonIconDisabled, footerConfig: footerConfig, inputConfig: inputConfig, onSubmit: handleSubmit, onChange: handleChange, onSuggestionCommand: suggestions.execute,
|
|
9639
|
+
jsxs(Fragment, { children: [drawerOpen ? jsx(ChatMenu, { opened: drawerOpen, tabIndex: menuItemsTabIndex, onItemClick: handleMenuItem, items: menuItems }) : jsx(Fragment, {}), jsx("div", { className: "chat-footer__menu-icon", children: jsx(DrawerBars, { tabIndex: menuButtonTabIndex, onToggle: toggleDrawer }) })] }) : jsx(Fragment, {}), jsx(Suggestions, { className: "xappw-chat-footer__suggestions", data: suggestions.suggestions, index: suggestions.index, searchTerms: suggestionSearch, hasWsButton: hasWsButton, onItemClick: handleItemClick, onItemUse: handleItemUse }), isAdmin && isChatting && visible && jsx(AdminBar, { onAdminJoin: handleAdminJoin }), jsx("div", { style: { pointerEvents: enableInput && !disabled ? "auto" : "none", opacity: enableInput ? 1 : 0.5 }, children: jsx(Input, { addClass: "chat-footer__input " + (isChatting && visible ? "visible" : ""), suggestion: suggestions.item, value: input, placeholder: placeholder, sendButtonIcon: sendButtonIcon, sendButtonIconHover: sendButtonIconHover, sendButtonIconDisabled: sendButtonIconDisabled, footerConfig: footerConfig, inputConfig: inputConfig, onSubmit: handleSubmit, onChange: handleChange, onSuggestionCommand: suggestions.execute,
|
|
9628
9640
|
// onFocus={this.inputOnFocus}
|
|
9629
9641
|
onFileUpload: props.onFileUpload }) }), brandingEnabled && brandingText && jsx(ChatBranding, { text: brandingText })] }));
|
|
9630
9642
|
};
|
|
@@ -31384,7 +31396,7 @@ var TypingStatus = function (props) {
|
|
|
31384
31396
|
};
|
|
31385
31397
|
|
|
31386
31398
|
var MessageList = function (_a) {
|
|
31387
|
-
_a.visible; var _c = _a.messages, messages = _c === void 0 ? [] : _c, _d = _a.agents, agents = _d === void 0 ? {} : _d; _a.isOffline; _a.isChatting; var _g = _a.queuePosition, queuePosition = _g === void 0 ? 0 : _g, _h = _a.lastRatingRequestTimestamp, lastRatingRequestTimestamp = _h === void 0 ? 0 : _h, _j = _a.hasRating, hasRating = _j === void 0 ? false : _j; _a.visitorId; var messageMiddleware = _a.messageMiddleware, textTypingStatusEnabled = _a.textTypingStatusEnabled, agent = _a.agent, hasWsButton = _a.hasWsButton, _l = _a.onSend, onSend =
|
|
31399
|
+
_a.visible; var _c = _a.messages, messages = _c === void 0 ? [] : _c, _d = _a.agents, agents = _d === void 0 ? {} : _d; _a.isOffline; _a.isChatting; var _g = _a.queuePosition, queuePosition = _g === void 0 ? 0 : _g, _h = _a.lastRatingRequestTimestamp, lastRatingRequestTimestamp = _h === void 0 ? 0 : _h, _j = _a.hasRating, hasRating = _j === void 0 ? false : _j; _a.visitorId; var messageMiddleware = _a.messageMiddleware, textTypingStatusEnabled = _a.textTypingStatusEnabled, agent = _a.agent, hasWsButton = _a.hasWsButton, _l = _a.disableAutoScroll, disableAutoScroll = _l === void 0 ? false : _l, _m = _a.onSend, onSend = _m === void 0 ? function () { return Promise.resolve(); } : _m, _o = _a.onWrite, onWrite = _o === void 0 ? function () { return Promise.resolve(); } : _o, _p = _a.onOpenUrl, onOpenUrl = _p === void 0 ? function () { } : _p, _q = _a.minimizeOnClick, minimizeOnClick = _q === void 0 ? function () { } : _q; _a.children;
|
|
31388
31400
|
var messagesEndRef = useRef(null);
|
|
31389
31401
|
var containerRef = useRef(null);
|
|
31390
31402
|
var prevHasWsButtonRef = useRef(hasWsButton);
|
|
@@ -31402,12 +31414,17 @@ var MessageList = function (_a) {
|
|
|
31402
31414
|
messagesEndRef.current.scrollIntoView({ behavior: behavior });
|
|
31403
31415
|
}
|
|
31404
31416
|
}, []);
|
|
31405
|
-
// Always scroll to bottom when messages change
|
|
31417
|
+
// Always scroll to bottom when messages change (unless disabled)
|
|
31406
31418
|
useEffect(function () {
|
|
31407
|
-
|
|
31408
|
-
|
|
31409
|
-
|
|
31419
|
+
if (!disableAutoScroll) {
|
|
31420
|
+
scrollToBottom("smooth");
|
|
31421
|
+
}
|
|
31422
|
+
}, [messages, agents, scrollToBottom, disableAutoScroll]);
|
|
31423
|
+
// Handle WS button dismissal - only scroll when button is removed (unless disabled)
|
|
31410
31424
|
useEffect(function () {
|
|
31425
|
+
if (disableAutoScroll) {
|
|
31426
|
+
return undefined;
|
|
31427
|
+
}
|
|
31411
31428
|
var prevHasButton = prevHasWsButtonRef.current;
|
|
31412
31429
|
var currentHasButton = hasWsButton;
|
|
31413
31430
|
// Update ref for next render
|
|
@@ -31424,15 +31441,19 @@ var MessageList = function (_a) {
|
|
|
31424
31441
|
}
|
|
31425
31442
|
}
|
|
31426
31443
|
return undefined;
|
|
31427
|
-
}, [hasWsButton, isAtBottom, scrollToBottom]);
|
|
31444
|
+
}, [hasWsButton, isAtBottom, scrollToBottom, disableAutoScroll]);
|
|
31428
31445
|
var handleSend = useCallback(function (msg) {
|
|
31429
31446
|
onSend(msg);
|
|
31430
|
-
messagesEndRef.current
|
|
31431
|
-
|
|
31447
|
+
if (!disableAutoScroll && messagesEndRef.current) {
|
|
31448
|
+
messagesEndRef.current.scrollIntoView({ behavior: "smooth" });
|
|
31449
|
+
}
|
|
31450
|
+
}, [onSend, disableAutoScroll]);
|
|
31432
31451
|
var handleWrite = useCallback(function (msg) {
|
|
31433
31452
|
onWrite(msg);
|
|
31434
|
-
messagesEndRef.current
|
|
31435
|
-
|
|
31453
|
+
if (!disableAutoScroll && messagesEndRef.current) {
|
|
31454
|
+
messagesEndRef.current.scrollIntoView({ behavior: "smooth" });
|
|
31455
|
+
}
|
|
31456
|
+
}, [onWrite, disableAutoScroll]);
|
|
31436
31457
|
var ctxCache = useMemo(function () {
|
|
31437
31458
|
return new MiddlewareContextFactory({
|
|
31438
31459
|
send: handleSend,
|
|
@@ -32139,425 +32160,61 @@ var ModalContent = function (_a) {
|
|
|
32139
32160
|
};
|
|
32140
32161
|
|
|
32141
32162
|
/**
|
|
32142
|
-
*
|
|
32143
|
-
*
|
|
32163
|
+
* Id the visitor (cookies, browser fingerprint, etc)
|
|
32164
|
+
*
|
|
32165
|
+
* @export
|
|
32166
|
+
* @returns {string}
|
|
32144
32167
|
*/
|
|
32145
|
-
|
|
32146
|
-
|
|
32147
|
-
|
|
32148
|
-
|
|
32149
|
-
|
|
32150
|
-
|
|
32151
|
-
|
|
32152
|
-
|
|
32153
|
-
var cancelled = false;
|
|
32154
|
-
if (props.getConfig) {
|
|
32155
|
-
setConfigLoading(true);
|
|
32156
|
-
setConfigError(undefined);
|
|
32157
|
-
props
|
|
32158
|
-
.getConfig()
|
|
32159
|
-
.then(function (config) {
|
|
32160
|
-
if (!cancelled) {
|
|
32161
|
-
setRawConfig(config);
|
|
32162
|
-
setConfigLoading(false);
|
|
32163
|
-
log("[ChatWidget] Config loaded from getConfig callback");
|
|
32164
|
-
}
|
|
32165
|
-
})
|
|
32166
|
-
.catch(function (error) {
|
|
32167
|
-
if (!cancelled) {
|
|
32168
|
-
setConfigError(error);
|
|
32169
|
-
setConfigLoading(false);
|
|
32170
|
-
err("[ChatWidget] Failed to load config: ".concat(error.message));
|
|
32171
|
-
}
|
|
32172
|
-
});
|
|
32173
|
-
}
|
|
32174
|
-
else if (props.config) {
|
|
32175
|
-
// If no callback, use the config prop directly
|
|
32176
|
-
setRawConfig(props.config);
|
|
32177
|
-
setConfigLoading(false);
|
|
32178
|
-
}
|
|
32179
|
-
return function () {
|
|
32180
|
-
cancelled = true;
|
|
32181
|
-
};
|
|
32182
|
-
// Only depend on getConfig and config - not the entire props object to avoid infinite loops
|
|
32183
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
32184
|
-
}, [props.getConfig, props.config]);
|
|
32185
|
-
var connection = useConnectionInfo(rawConfig);
|
|
32186
|
-
var config = useMemo(function () {
|
|
32187
|
-
var _a;
|
|
32188
|
-
return (__assign(__assign({}, rawConfig), { connection: connection, assetUrl: (_a = connection === null || connection === void 0 ? void 0 : connection.serverUrl) !== null && _a !== void 0 ? _a : defaultServerUrl, env: rawConfig }));
|
|
32189
|
-
}, [connection, rawConfig]);
|
|
32190
|
-
var token = useSelector(function (state) { return state.connection.token; });
|
|
32191
|
-
var options = useMemo(function () {
|
|
32192
|
-
var configurableMessages = getConfigurableMessages();
|
|
32193
|
-
if ((rawConfig === null || rawConfig === void 0 ? void 0 : rawConfig.configurableMessages) &&
|
|
32194
|
-
Array.isArray(rawConfig.configurableMessages.items) &&
|
|
32195
|
-
rawConfig.configurableMessages.items.length > 0) {
|
|
32196
|
-
configurableMessages = rawConfig.configurableMessages;
|
|
32197
|
-
}
|
|
32198
|
-
return {
|
|
32199
|
-
token: token,
|
|
32200
|
-
bot: {
|
|
32201
|
-
nick: "Bot",
|
|
32202
|
-
displayName: rawConfig === null || rawConfig === void 0 ? void 0 : rawConfig.botName,
|
|
32203
|
-
avatarPath: rawConfig === null || rawConfig === void 0 ? void 0 : rawConfig.avatarUrl,
|
|
32204
|
-
},
|
|
32205
|
-
configurableMessages: configurableMessages,
|
|
32206
|
-
hooks: rawConfig === null || rawConfig === void 0 ? void 0 : rawConfig.hooks,
|
|
32207
|
-
env: rawConfig,
|
|
32208
|
-
};
|
|
32209
|
-
}, [
|
|
32210
|
-
token,
|
|
32211
|
-
rawConfig === null || rawConfig === void 0 ? void 0 : rawConfig.botName,
|
|
32212
|
-
rawConfig === null || rawConfig === void 0 ? void 0 : rawConfig.avatarUrl,
|
|
32213
|
-
rawConfig === null || rawConfig === void 0 ? void 0 : rawConfig.configurableMessages,
|
|
32214
|
-
rawConfig === null || rawConfig === void 0 ? void 0 : rawConfig.hooks,
|
|
32215
|
-
]);
|
|
32216
|
-
// Only create chat server when config is ready (not loading and no error)
|
|
32217
|
-
var chatServer = useChatServer(configLoading || configError ? null : connection, configLoading || configError ? null : options);
|
|
32218
|
-
// Determine mode class for loading/error states
|
|
32219
|
-
var mode = (_a = props.mode) !== null && _a !== void 0 ? _a : "normal";
|
|
32220
|
-
var modeClass = "widget-container--".concat(mode);
|
|
32221
|
-
// Show loading state while config is being fetched
|
|
32222
|
-
if (configLoading) {
|
|
32223
|
-
return (jsx("div", { className: "widget-container widget-container--loading ".concat(modeClass), children: jsx("div", { className: "xa-spinner-container visible", children: jsx("div", { className: "xa-spinner" }) }) }));
|
|
32224
|
-
}
|
|
32225
|
-
// Show error state if config failed to load
|
|
32226
|
-
if (configError) {
|
|
32227
|
-
return (jsx("div", { className: "widget-container widget-container--error ".concat(modeClass), children: jsxs("div", { className: "widget-error-message", children: ["Failed to load chat configuration: ", configError.message] }) }));
|
|
32228
|
-
}
|
|
32229
|
-
return (jsx(ChatConfigContext.Provider, { value: config, children: jsx(ChatServerContext.Provider, { value: chatServer, children: jsx(ChatWidget, __assign({}, props, { config: rawConfig })) }) }));
|
|
32168
|
+
function visitorFingerprint() {
|
|
32169
|
+
return uuid_1();
|
|
32170
|
+
}
|
|
32171
|
+
|
|
32172
|
+
var DEFAULT_VISITOR = {
|
|
32173
|
+
displayName: "Visitor",
|
|
32174
|
+
nick: "visitor:",
|
|
32175
|
+
typing: false
|
|
32230
32176
|
};
|
|
32231
|
-
|
|
32232
|
-
var _a
|
|
32233
|
-
|
|
32234
|
-
|
|
32235
|
-
// From Redux
|
|
32236
|
-
var chatState = useSelector(function (state) { return state; });
|
|
32237
|
-
// Refresh modalReference
|
|
32238
|
-
var modalRef = useRef({});
|
|
32239
|
-
var mode = (_a = props.mode) !== null && _a !== void 0 ? _a : "normal";
|
|
32240
|
-
var dockedMode = mode === "docked";
|
|
32241
|
-
var staticMode = mode === "static";
|
|
32242
|
-
var modeClass = "widget-container--".concat(mode);
|
|
32243
|
-
var canRefresh = (_c = (_b = props.config.header) === null || _b === void 0 ? void 0 : _b.actions) === null || _c === void 0 ? void 0 : _c.refresh;
|
|
32244
|
-
// can't minimize in docked mode or static mode.
|
|
32245
|
-
var canMinimize = !dockedMode && !staticMode && ((_e = (_d = props.config.header) === null || _d === void 0 ? void 0 : _d.actions) === null || _e === void 0 ? void 0 : _e.minimize);
|
|
32246
|
-
log("docked: ".concat(dockedMode, " static: ").concat(staticMode, " minimized: ").concat((_g = (_f = props.config.header) === null || _f === void 0 ? void 0 : _f.actions) === null || _g === void 0 ? void 0 : _g.minimize));
|
|
32247
|
-
var canCancel;
|
|
32248
|
-
// To preserve legacy behavior, cancel needs a little more checks
|
|
32249
|
-
if (typeof ((_j = (_h = props.config.header) === null || _h === void 0 ? void 0 : _h.actions) === null || _j === void 0 ? void 0 : _j.cancel) === "boolean") {
|
|
32250
|
-
canCancel = !dockedMode && !staticMode && ((_l = (_k = props.config.header) === null || _k === void 0 ? void 0 : _k.actions) === null || _l === void 0 ? void 0 : _l.cancel);
|
|
32251
|
-
}
|
|
32252
|
-
else {
|
|
32253
|
-
canCancel = !dockedMode && !staticMode;
|
|
32254
|
-
}
|
|
32255
|
-
// For backward compatibility. Note: the action will create the actual "visuals" object" (this is a copy).
|
|
32256
|
-
if (!chatState.visuals) {
|
|
32257
|
-
chatState.visuals = {};
|
|
32177
|
+
function createDefaultState(state, options) {
|
|
32178
|
+
var _a;
|
|
32179
|
+
if (!state) {
|
|
32180
|
+
state = {};
|
|
32258
32181
|
}
|
|
32259
|
-
|
|
32260
|
-
|
|
32261
|
-
|
|
32262
|
-
|
|
32263
|
-
|
|
32264
|
-
|
|
32265
|
-
|
|
32266
|
-
|
|
32267
|
-
var typingRef = useRef(false);
|
|
32268
|
-
// Timeout ref for debouncing "stop typing" events
|
|
32269
|
-
var stopTypingTimeoutRef = useRef(null);
|
|
32270
|
-
var chatServer = useContext(ChatServerContext);
|
|
32271
|
-
var patternsConfig = (_q = (_p = props.config) === null || _p === void 0 ? void 0 : _p.autoOpenOnPattern) === null || _q === void 0 ? void 0 : _q.patterns;
|
|
32272
|
-
var currentUrl = window.location.href;
|
|
32273
|
-
var patternExist = patternsConfig && patternsConfig.length > 0;
|
|
32274
|
-
var patternMatches = patternsConfig === null || patternsConfig === void 0 ? void 0 : patternsConfig.some(function (pattern) { return currentUrl.includes(pattern); });
|
|
32275
|
-
var configWidth = (_s = (_r = props.config) === null || _r === void 0 ? void 0 : _r.autoOpenOnPattern) === null || _s === void 0 ? void 0 : _s.minimumWidth;
|
|
32276
|
-
// eslint-disable-next-line no-restricted-globals
|
|
32277
|
-
var currentWidth = screen.width;
|
|
32278
|
-
var setVisible = useCallback(function (newVisible) {
|
|
32279
|
-
if (staticMode) {
|
|
32280
|
-
return;
|
|
32281
|
-
}
|
|
32282
|
-
log("setVisible: ".concat(newVisible));
|
|
32283
|
-
setVisibleState(newVisible);
|
|
32284
|
-
innerDispatch(setVisualStatus({
|
|
32285
|
-
visible: newVisible,
|
|
32286
|
-
}));
|
|
32287
|
-
}, [innerDispatch, staticMode]);
|
|
32288
|
-
useEffect(function () {
|
|
32289
|
-
var _a, _b;
|
|
32290
|
-
var handleKeyDown = function (event) {
|
|
32291
|
-
var body = document.getElementsByTagName("body")[0];
|
|
32292
|
-
body.tabIndex = -1;
|
|
32293
|
-
if (event.key === "Escape") {
|
|
32294
|
-
body.focus();
|
|
32295
|
-
}
|
|
32296
|
-
};
|
|
32297
|
-
document.addEventListener("keydown", handleKeyDown);
|
|
32298
|
-
if (checkSessionExpiration((chatState === null || chatState === void 0 ? void 0 : chatState.sessionExpiration) || ((_a = props.config) === null || _a === void 0 ? void 0 : _a.sessionExpiration), (_b = chatState === null || chatState === void 0 ? void 0 : chatState.chats[chatState.chats.length - 1]) === null || _b === void 0 ? void 0 : _b.timestamp, chatState === null || chatState === void 0 ? void 0 : chatState.lastTimestamp)) {
|
|
32299
|
-
innerDispatch(setSessionId(undefined));
|
|
32300
|
-
innerDispatch(reset());
|
|
32301
|
-
}
|
|
32302
|
-
return function () {
|
|
32303
|
-
document.removeEventListener("keydown", handleKeyDown);
|
|
32304
|
-
// Cleanup typing timeout on unmount
|
|
32305
|
-
if (stopTypingTimeoutRef.current) {
|
|
32306
|
-
clearTimeout(stopTypingTimeoutRef.current);
|
|
32307
|
-
}
|
|
32308
|
-
};
|
|
32309
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
32310
|
-
}, []);
|
|
32311
|
-
var _10 = useState(!document.hidden), isTabVisible = _10[0], setIsTabVisible = _10[1];
|
|
32312
|
-
useEffect(function () {
|
|
32313
|
-
var handleVisibilityChange = function () {
|
|
32314
|
-
setIsTabVisible(!document.hidden);
|
|
32315
|
-
};
|
|
32316
|
-
document.addEventListener("visibilitychange", handleVisibilityChange);
|
|
32317
|
-
return function () {
|
|
32318
|
-
document.removeEventListener("visibilitychange", handleVisibilityChange);
|
|
32319
|
-
};
|
|
32320
|
-
}, []);
|
|
32321
|
-
useEffect(function () {
|
|
32322
|
-
// Too early?
|
|
32323
|
-
if (!chatServer) {
|
|
32324
|
-
log("Tab visibility changed but no chatServer yet");
|
|
32325
|
-
return;
|
|
32326
|
-
}
|
|
32327
|
-
if (!isTabVisible) {
|
|
32328
|
-
log("Tab is HIDDEN - calling sleep()");
|
|
32329
|
-
chatServer.sleep();
|
|
32330
|
-
}
|
|
32331
|
-
else {
|
|
32332
|
-
log("Tab is VISIBLE - calling wakeup()");
|
|
32333
|
-
chatServer.wakeup();
|
|
32334
|
-
}
|
|
32335
|
-
}, [chatServer, innerDispatch, isTabVisible]);
|
|
32336
|
-
// Handle beforeunload to notify router when user is leaving
|
|
32337
|
-
useEffect(function () {
|
|
32338
|
-
if (!chatServer) {
|
|
32339
|
-
return undefined;
|
|
32340
|
-
}
|
|
32341
|
-
var handleBeforeUnload = function () {
|
|
32342
|
-
log("beforeunload - notifying router of user disconnecting");
|
|
32343
|
-
if (chatServer.notifyDisconnecting) {
|
|
32344
|
-
chatServer.notifyDisconnecting();
|
|
32345
|
-
}
|
|
32346
|
-
};
|
|
32347
|
-
window.addEventListener("beforeunload", handleBeforeUnload);
|
|
32348
|
-
return function () {
|
|
32349
|
-
window.removeEventListener("beforeunload", handleBeforeUnload);
|
|
32350
|
-
};
|
|
32351
|
-
}, [chatServer]);
|
|
32352
|
-
useEffect(function () {
|
|
32353
|
-
// For reopen widget after move on same window
|
|
32354
|
-
// if (get("opened")) {
|
|
32355
|
-
// setVisible(true);
|
|
32356
|
-
// }
|
|
32357
|
-
if (chatState.visuals.opened) {
|
|
32358
|
-
setVisible(true);
|
|
32359
|
-
}
|
|
32360
|
-
else {
|
|
32361
|
-
if (mode === "normal") {
|
|
32362
|
-
setVisible(false);
|
|
32363
|
-
}
|
|
32364
|
-
}
|
|
32365
|
-
if (patternExist && patternMatches) {
|
|
32366
|
-
setVisible(true);
|
|
32367
|
-
}
|
|
32368
|
-
if (currentWidth < +configWidth) {
|
|
32369
|
-
setVisible(false);
|
|
32370
|
-
}
|
|
32371
|
-
}, [
|
|
32372
|
-
currentWidth,
|
|
32373
|
-
patternExist,
|
|
32374
|
-
patternMatches,
|
|
32375
|
-
configWidth,
|
|
32376
|
-
setVisible,
|
|
32377
|
-
chatState.visuals.opened,
|
|
32378
|
-
mode,
|
|
32379
|
-
]);
|
|
32380
|
-
var stopTyping = useCallback(function () {
|
|
32381
|
-
if (!typingRef.current)
|
|
32382
|
-
return;
|
|
32383
|
-
// Clear the timeout if it exists
|
|
32384
|
-
if (stopTypingTimeoutRef.current) {
|
|
32385
|
-
clearTimeout(stopTypingTimeoutRef.current);
|
|
32386
|
-
stopTypingTimeoutRef.current = null;
|
|
32387
|
-
}
|
|
32388
|
-
dispatch(sendTyping(false));
|
|
32389
|
-
setTypingState(false);
|
|
32390
|
-
typingRef.current = false;
|
|
32391
|
-
}, [dispatch]);
|
|
32392
|
-
var handleOnChange = useCallback(function () {
|
|
32393
|
-
// Send "typing" event only on first keystroke
|
|
32394
|
-
if (!typingRef.current) {
|
|
32395
|
-
dispatch(sendTyping(true));
|
|
32396
|
-
setTypingState(true);
|
|
32397
|
-
typingRef.current = true;
|
|
32398
|
-
}
|
|
32399
|
-
// Clear any existing timeout
|
|
32400
|
-
if (stopTypingTimeoutRef.current) {
|
|
32401
|
-
clearTimeout(stopTypingTimeoutRef.current);
|
|
32182
|
+
state.userId = state.userId ? state.userId : visitorFingerprint();
|
|
32183
|
+
state.visitorId = state.userId;
|
|
32184
|
+
// Determine if debug mode should be enabled
|
|
32185
|
+
var debugMode = false;
|
|
32186
|
+
if (typeof window !== 'undefined') {
|
|
32187
|
+
var localStorageSetting = (_a = window.localStorage) === null || _a === void 0 ? void 0 : _a.getItem('xaErrorOverlay');
|
|
32188
|
+
if (localStorageSetting === 'enabled') {
|
|
32189
|
+
debugMode = true;
|
|
32402
32190
|
}
|
|
32403
|
-
|
|
32404
|
-
|
|
32405
|
-
stopTyping();
|
|
32406
|
-
}, TYPING_INDICATOR_DEBOUNCE_MS);
|
|
32407
|
-
}, [dispatch, stopTyping]);
|
|
32408
|
-
function handleSendMessage(msg) {
|
|
32409
|
-
dispatch(sendMessage(msg));
|
|
32410
|
-
}
|
|
32411
|
-
function handleWriteMessage(msg) {
|
|
32412
|
-
innerDispatch(writeMessage(msg.msg, msg.user));
|
|
32413
|
-
}
|
|
32414
|
-
var handleOpenUrl = useOpenUrlCallback();
|
|
32415
|
-
function handleOnSubmit(rawInput) {
|
|
32416
|
-
// Don't allow visitor to send msg if not chatting
|
|
32417
|
-
if (chatState.accountStatus === "offline" && !chatState.isChatting)
|
|
32418
|
-
return;
|
|
32419
|
-
// Don't send empty messages
|
|
32420
|
-
if (!rawInput)
|
|
32421
|
-
return;
|
|
32422
|
-
// Immediately stop typing
|
|
32423
|
-
stopTyping();
|
|
32424
|
-
chatServer.flush();
|
|
32425
|
-
dispatch(executeAction(rawInput));
|
|
32426
|
-
}
|
|
32427
|
-
function handleFileUpload(event) {
|
|
32428
|
-
var _a;
|
|
32429
|
-
event.preventDefault();
|
|
32430
|
-
// Only send the first file dropped on input
|
|
32431
|
-
var file = (_a = event === null || event === void 0 ? void 0 : event.dataTransfer) === null || _a === void 0 ? void 0 : _a.files[0];
|
|
32432
|
-
if (!file) {
|
|
32433
|
-
return;
|
|
32191
|
+
else if (localStorageSetting === 'disabled') {
|
|
32192
|
+
debugMode = false;
|
|
32434
32193
|
}
|
|
32435
|
-
|
|
32436
|
-
|
|
32437
|
-
|
|
32438
|
-
return visible ? "visible" : "";
|
|
32439
|
-
}
|
|
32440
|
-
function openRestartConfirmationModal() {
|
|
32441
|
-
// Interesting, this call the modalRef of the restart modal
|
|
32442
|
-
modalRef.current.style.display = "block";
|
|
32443
|
-
}
|
|
32444
|
-
function closeRestartConfirmationModal() {
|
|
32445
|
-
modalRef.current.style.display = "none";
|
|
32446
|
-
}
|
|
32447
|
-
function handleReset() {
|
|
32448
|
-
innerDispatch(reset());
|
|
32449
|
-
}
|
|
32450
|
-
function handleRestartClick() {
|
|
32451
|
-
if (config.header.actions.refreshShowConfirmation) {
|
|
32452
|
-
// show the modal
|
|
32453
|
-
openRestartConfirmationModal();
|
|
32454
|
-
// we will close when
|
|
32194
|
+
else if (options === null || options === void 0 ? void 0 : options.enableErrorOverlay) {
|
|
32195
|
+
// Use config option if no localStorage override
|
|
32196
|
+
debugMode = true;
|
|
32455
32197
|
}
|
|
32456
|
-
else {
|
|
32457
|
-
|
|
32198
|
+
else if (typeof globalThis.__DEV__ !== 'undefined' && globalThis.__DEV__) {
|
|
32199
|
+
// For React Native, default to true in development mode
|
|
32200
|
+
debugMode = true;
|
|
32458
32201
|
}
|
|
32459
32202
|
}
|
|
32460
|
-
|
|
32461
|
-
|
|
32462
|
-
|
|
32463
|
-
|
|
32464
|
-
|
|
32465
|
-
|
|
32466
|
-
|
|
32467
|
-
|
|
32468
|
-
|
|
32469
|
-
|
|
32470
|
-
}
|
|
32471
|
-
|
|
32472
|
-
function handleCancelClick() {
|
|
32473
|
-
// First reset to clear all state
|
|
32474
|
-
innerDispatch(reset());
|
|
32475
|
-
// Then set hasInteracted to prevent CTA from showing after cancel
|
|
32476
|
-
innerDispatch(setVisualStatus({
|
|
32477
|
-
opened: false,
|
|
32478
|
-
hasInteracted: true,
|
|
32479
|
-
}));
|
|
32480
|
-
setVisible(false);
|
|
32481
|
-
}
|
|
32482
|
-
function chatButtonOnClick() {
|
|
32483
|
-
innerDispatch(setVisualStatus({
|
|
32203
|
+
return __assign({ connection: {
|
|
32204
|
+
connectionStatus: "offline",
|
|
32205
|
+
token: null,
|
|
32206
|
+
greetingRequested: false
|
|
32207
|
+
}, accountStatus: "offline", departments: {}, visitor: DEFAULT_VISITOR, agents: {}, chats: [], lastTimestamp: 0, lastRatingRequestTimestamp: 0, hasRating: false, isChatting: false, queuePosition: 0, failureMsg: null, visitorId: visitorFingerprint(), chips: [], sessionExpiration: "24h", visuals: {}, debugMode: debugMode }, state);
|
|
32208
|
+
}
|
|
32209
|
+
var DEFAULT_STATE = createDefaultState();
|
|
32210
|
+
|
|
32211
|
+
function createStateFromMessages(messages) {
|
|
32212
|
+
var def = createDefaultState();
|
|
32213
|
+
return __assign(__assign({}, def), { connection: __assign(__assign({}, def.connection), { connectionStatus: "online" }), accountStatus: "online", chats: __spreadArray$1([], messages, true), isChatting: true, visuals: {
|
|
32214
|
+
visible: true,
|
|
32484
32215
|
opened: true,
|
|
32485
|
-
|
|
32486
|
-
|
|
32487
|
-
setVisible(true);
|
|
32488
|
-
setTimeout(function () {
|
|
32489
|
-
document.getElementById("chatWidgetInput").focus();
|
|
32490
|
-
}, 100);
|
|
32491
|
-
}
|
|
32492
|
-
function handleCtaDismiss() {
|
|
32493
|
-
innerDispatch(setVisualStatus({
|
|
32494
|
-
hasInteracted: true,
|
|
32495
|
-
}));
|
|
32496
|
-
}
|
|
32497
|
-
function handleWsButtonPress(buttonId) {
|
|
32498
|
-
var _a, _b;
|
|
32499
|
-
log("WS Button pressed: ".concat(buttonId));
|
|
32500
|
-
// If the button has spinning behavior, update state to show spinner
|
|
32501
|
-
if (((_a = chatState.wsButton) === null || _a === void 0 ? void 0 : _a.pressBehavior) === "spinning") {
|
|
32502
|
-
// Update the button state to show it's pressed
|
|
32503
|
-
innerDispatch({
|
|
32504
|
-
type: "ws_button_display",
|
|
32505
|
-
detail: __assign(__assign({}, chatState.wsButton), { isPressed: true, timestamp: +new Date() })
|
|
32506
|
-
});
|
|
32507
|
-
}
|
|
32508
|
-
// Send the button pressed event to the server
|
|
32509
|
-
if (chatServer && chatServer.sendButtonPressed) {
|
|
32510
|
-
chatServer.sendButtonPressed(buttonId).catch(function (error) {
|
|
32511
|
-
err("Failed to send button press: ".concat(error));
|
|
32512
|
-
// Reset button state on error
|
|
32513
|
-
if (chatState.wsButton) {
|
|
32514
|
-
innerDispatch({
|
|
32515
|
-
type: "ws_button_display",
|
|
32516
|
-
detail: __assign(__assign({}, chatState.wsButton), { isPressed: false, timestamp: +new Date() })
|
|
32517
|
-
});
|
|
32518
|
-
}
|
|
32519
|
-
});
|
|
32520
|
-
}
|
|
32521
|
-
// If the button has disabled behavior, animate out then dismiss
|
|
32522
|
-
if (((_b = chatState.wsButton) === null || _b === void 0 ? void 0 : _b.pressBehavior) === "disabled") {
|
|
32523
|
-
// First set dismissing state to trigger animation
|
|
32524
|
-
innerDispatch({
|
|
32525
|
-
type: "ws_button_display",
|
|
32526
|
-
detail: __assign(__assign({}, chatState.wsButton), { isDismissing: true, timestamp: +new Date() })
|
|
32527
|
-
});
|
|
32528
|
-
// Then actually dismiss after animation completes
|
|
32529
|
-
setTimeout(function () {
|
|
32530
|
-
innerDispatch({
|
|
32531
|
-
type: "ws_button_dismiss",
|
|
32532
|
-
detail: {
|
|
32533
|
-
id: buttonId,
|
|
32534
|
-
timestamp: +new Date()
|
|
32535
|
-
}
|
|
32536
|
-
});
|
|
32537
|
-
}, WS_BUTTON_DISMISS_ANIMATION_DURATION);
|
|
32538
|
-
}
|
|
32539
|
-
}
|
|
32540
|
-
var isOffline = chatState.accountStatus === "offline" && !chatState.isChatting;
|
|
32541
|
-
var messages = chatState && chatState.chats;
|
|
32542
|
-
log("Rendering - accountStatus: \"".concat(chatState.accountStatus, "\", connectionStatus: \"").concat(chatState.connection.connectionStatus, "\""));
|
|
32543
|
-
var config = props.config, onConnectionStatusChange = props.onConnectionStatusChange;
|
|
32544
|
-
useGreeting(!isOffline && !props.preChatFormEnabled && visible);
|
|
32545
|
-
var connectionStatus = chatState.connection.connectionStatus;
|
|
32546
|
-
useEffect(function () {
|
|
32547
|
-
if (onConnectionStatusChange) {
|
|
32548
|
-
onConnectionStatusChange(connectionStatus);
|
|
32549
|
-
}
|
|
32550
|
-
}, [connectionStatus, onConnectionStatusChange]);
|
|
32551
|
-
useExternalScript((_t = props.config) === null || _t === void 0 ? void 0 : _t.middlewareUrl);
|
|
32552
|
-
// This is a pseudo agent. It represent's the widget (shown in the header avatar for instance)
|
|
32553
|
-
var widgetAgent = ((_u = chatState.agents["agent:robot"]) === null || _u === void 0 ? void 0 : _u.user) ||
|
|
32554
|
-
(config === null || config === void 0 ? void 0 : config.agent) || {
|
|
32555
|
-
nick: "agent:robot",
|
|
32556
|
-
avatarPath: config.avatarUrl,
|
|
32557
|
-
display_name: "Agent",
|
|
32558
|
-
};
|
|
32559
|
-
return (jsxs(Fragment, { children: [jsxs("div", { className: "widget-container ".concat(modeClass, " ").concat(getVisibilityClass()), children: [jsx(WidgetStylesheet, { theme: config === null || config === void 0 ? void 0 : config.theme }), jsx(ChatHeader, { accountStatus: chatState.accountStatus, refreshOnClick: handleRestartClick, minimizeOnClick: handleMinimizeClick, cancelOnClick: handleCancelClick, agent: widgetAgent, canRefresh: canRefresh, canMinimize: canMinimize, canCancel: canCancel, config: config === null || config === void 0 ? void 0 : config.header, menuConfig: config.menu, onSubmit: handleOnSubmit }), jsx(MessageList, { visible: visible, queuePosition: chatState.queuePosition, isChatting: chatState.isChatting, isOffline: isOffline, messages: messages, agents: chatState.agents, agent: config === null || config === void 0 ? void 0 : config.agent, lastRatingRequestTimestamp: chatState.lastRatingRequestTimestamp, hasRating: chatState.hasRating, visitorId: chatState.visitorId, hasWsButton: !!chatState.wsButton, messageMiddleware: props.messageMiddleware, textTypingStatusEnabled: (_w = (_v = props.config) === null || _v === void 0 ? void 0 : _v.typingStatus) === null || _w === void 0 ? void 0 : _w.textTypingStatusEnabled, onSend: handleSendMessage, onWrite: handleWriteMessage, onOpenUrl: handleOpenUrl, minimizeOnClick: handleMinimizeClick }), jsx("div", { className: "xa-spinner-container ".concat(visible && connectionStatus === "pending" ? "visible" : ""), children: jsx("div", { className: "xa-spinner" }) }), connectionStatus === "offline" && jsx(ServerOffline, {}), chatState.wsButton && visible && (jsx(WsButton, { button: chatState.wsButton, onPress: handleWsButtonPress })), jsx(ChatFooter, { isAdmin: config === null || config === void 0 ? void 0 : config.isAdmin, isChatting: chatState.isChatting, placeholder: (_x = config === null || config === void 0 ? void 0 : config.input) === null || _x === void 0 ? void 0 : _x.placeholder, sendButtonIcon: (_z = (_y = config === null || config === void 0 ? void 0 : config.footer) === null || _y === void 0 ? void 0 : _y.sendButton) === null || _z === void 0 ? void 0 : _z.icon, sendButtonIconHover: (_1 = (_0 = config === null || config === void 0 ? void 0 : config.footer) === null || _0 === void 0 ? void 0 : _0.sendButton) === null || _1 === void 0 ? void 0 : _1.iconHover, sendButtonIconDisabled: (_3 = (_2 = config === null || config === void 0 ? void 0 : config.footer) === null || _2 === void 0 ? void 0 : _2.sendButton) === null || _3 === void 0 ? void 0 : _3.iconDisabled, visible: visible, hasWsButton: !!chatState.wsButton, menuConfig: props.config.menu, footerConfig: (_4 = props.config) === null || _4 === void 0 ? void 0 : _4.footer, inputConfig: (_5 = props.config) === null || _5 === void 0 ? void 0 : _5.input, onChange: handleOnChange, onSubmit: handleOnSubmit, onFileUpload: handleFileUpload }), jsx("div", { className: "restartModal", ref: modalRef, onClick: handleRestartModalCloseClick, children: jsx(ModalContent, { onClose: handleRestartModalCloseClick, onReset: handleReset }) })] }), jsx(ChatButton, { addClass: getVisibilityClass(), onClick: chatButtonOnClick, config: config === null || config === void 0 ? void 0 : config.cta, imageUrl: (_6 = config === null || config === void 0 ? void 0 : config.chatButton) === null || _6 === void 0 ? void 0 : _6.imageUrl, visible: visible, hasInteracted: (_7 = chatState.visuals) === null || _7 === void 0 ? void 0 : _7.hasInteracted, onCtaDismiss: handleCtaDismiss }), jsx(ErrorOverlay, { enableErrorOverlay: config === null || config === void 0 ? void 0 : config.enableErrorOverlay })] }));
|
|
32560
|
-
};
|
|
32216
|
+
} });
|
|
32217
|
+
}
|
|
32561
32218
|
|
|
32562
32219
|
// src/utils/formatProdErrorMessage.ts
|
|
32563
32220
|
function formatProdErrorMessage$1(code) {
|
|
@@ -33714,6 +33371,576 @@ function formatProdErrorMessage(code) {
|
|
|
33714
33371
|
return `Minified Redux Toolkit error #${code}; visit https://redux-toolkit.js.org/Errors?code=${code} for the full message or use the non-minified dev environment for full errors. `;
|
|
33715
33372
|
}
|
|
33716
33373
|
|
|
33374
|
+
// Function to create a static reducer
|
|
33375
|
+
function createStaticReducer(state) {
|
|
33376
|
+
return function (oldState, action) {
|
|
33377
|
+
if (oldState === void 0) { oldState = state; }
|
|
33378
|
+
log("static reducer", oldState, action);
|
|
33379
|
+
return oldState;
|
|
33380
|
+
};
|
|
33381
|
+
}
|
|
33382
|
+
// Function to create the store using @reduxjs/toolkit's configureStore
|
|
33383
|
+
function createStaticStore(state) {
|
|
33384
|
+
var reducer = createStaticReducer(state);
|
|
33385
|
+
var store = configureStore({
|
|
33386
|
+
reducer: reducer,
|
|
33387
|
+
middleware: function (getDefaultMiddleware) {
|
|
33388
|
+
return getDefaultMiddleware({
|
|
33389
|
+
thunk: true, // Thunk is included by default, this is just for explicitness
|
|
33390
|
+
});
|
|
33391
|
+
},
|
|
33392
|
+
devTools: "production" !== 'production', // Redux DevTools in non-production environments
|
|
33393
|
+
});
|
|
33394
|
+
return store;
|
|
33395
|
+
}
|
|
33396
|
+
|
|
33397
|
+
var StaticChatWidgetContainer = function (props) {
|
|
33398
|
+
var state = props.state;
|
|
33399
|
+
var store = useMemo(function () {
|
|
33400
|
+
return createStaticStore(state);
|
|
33401
|
+
}, [state]);
|
|
33402
|
+
var config = useMemo(function () {
|
|
33403
|
+
return __assign(__assign({}, props.config), { connection: {
|
|
33404
|
+
serverUrl: "",
|
|
33405
|
+
type: "local",
|
|
33406
|
+
} });
|
|
33407
|
+
}, [props.config]);
|
|
33408
|
+
return (jsx(Provider, { store: store, children: jsx(ChatWidgetUI, __assign({}, props, { config: config, disableAutoScroll: props.disableAutoScroll, preview: props.preview })) }));
|
|
33409
|
+
};
|
|
33410
|
+
|
|
33411
|
+
var StaticMessagesChatWidgetContainer = function (props) {
|
|
33412
|
+
var messages = props.messages;
|
|
33413
|
+
var state = useMemo(function () {
|
|
33414
|
+
return createStateFromMessages(messages);
|
|
33415
|
+
}, [messages]);
|
|
33416
|
+
return jsx(StaticChatWidgetContainer, { state: state, mode: props.mode, config: props.config, disableAutoScroll: props.disableAutoScroll, preview: props.preview });
|
|
33417
|
+
};
|
|
33418
|
+
|
|
33419
|
+
/**
|
|
33420
|
+
* Debounce delay for typing indicator in milliseconds.
|
|
33421
|
+
* After this delay of inactivity, the "stop typing" event will be sent.
|
|
33422
|
+
*/
|
|
33423
|
+
var TYPING_INDICATOR_DEBOUNCE_MS = 2000;
|
|
33424
|
+
/**
|
|
33425
|
+
* Check if we're in development mode. Uses typeof to prevent TypeScript
|
|
33426
|
+
* errors after Rollup replaces "production" with a literal string.
|
|
33427
|
+
*/
|
|
33428
|
+
typeof process !== "undefined" &&
|
|
33429
|
+
typeof process.env !== "undefined" &&
|
|
33430
|
+
"production" !== "production";
|
|
33431
|
+
/**
|
|
33432
|
+
* Converts preview messages to ChatDetail format for rendering.
|
|
33433
|
+
* This allows preview mode to use the existing message rendering infrastructure.
|
|
33434
|
+
*
|
|
33435
|
+
* @param messages - Array of preview messages to convert
|
|
33436
|
+
* @returns Array of ChatDetail objects suitable for MessageList rendering
|
|
33437
|
+
*/
|
|
33438
|
+
function convertPreviewMessagesToChatDetails(messages) {
|
|
33439
|
+
var timestamp = Date.now();
|
|
33440
|
+
return messages.map(function (msg, index) {
|
|
33441
|
+
var _a;
|
|
33442
|
+
var chatDetail = {
|
|
33443
|
+
type: "chat.msg",
|
|
33444
|
+
user: {
|
|
33445
|
+
nick: "agent:robot",
|
|
33446
|
+
display_name: "Assistant",
|
|
33447
|
+
},
|
|
33448
|
+
timestamp: timestamp + index,
|
|
33449
|
+
msg: {
|
|
33450
|
+
text: msg.displayText,
|
|
33451
|
+
html: msg.html,
|
|
33452
|
+
// Use "#" as fallback for suggestions without URLs to prevent navigation
|
|
33453
|
+
options: (_a = msg.suggestions) === null || _a === void 0 ? void 0 : _a.map(function (s) { return ({
|
|
33454
|
+
label: s.title,
|
|
33455
|
+
actionUrl: s.url || "#"
|
|
33456
|
+
}); }),
|
|
33457
|
+
list: msg.list ? {
|
|
33458
|
+
type: msg.list.type,
|
|
33459
|
+
title: msg.list.title,
|
|
33460
|
+
// description maps to subTitle in internal representation
|
|
33461
|
+
items: msg.list.items.map(function (item) { return ({
|
|
33462
|
+
title: item.title,
|
|
33463
|
+
subTitle: item.description,
|
|
33464
|
+
url: item.url,
|
|
33465
|
+
imageUrl: item.imageUrl,
|
|
33466
|
+
}); })
|
|
33467
|
+
} : undefined
|
|
33468
|
+
}
|
|
33469
|
+
};
|
|
33470
|
+
return chatDetail;
|
|
33471
|
+
});
|
|
33472
|
+
}
|
|
33473
|
+
/**
|
|
33474
|
+
* Preview mode component - renders a static chat widget without server connection.
|
|
33475
|
+
* Separated to avoid violating React hooks rules in the main wrapper.
|
|
33476
|
+
*/
|
|
33477
|
+
var ChatWidgetPreview = function (props) {
|
|
33478
|
+
var _a;
|
|
33479
|
+
var mode = (_a = props.mode) !== null && _a !== void 0 ? _a : "preview";
|
|
33480
|
+
// Memoize preview message conversion to avoid recalculating on every render
|
|
33481
|
+
var previewChatDetails = useMemo(function () {
|
|
33482
|
+
return convertPreviewMessagesToChatDetails(props.previewMessages || []);
|
|
33483
|
+
}, [props.previewMessages]);
|
|
33484
|
+
return (jsx(StaticMessagesChatWidgetContainer, { messages: previewChatDetails, mode: mode, config: props.config, disableAutoScroll: props.disableAutoScroll, preview: true }));
|
|
33485
|
+
};
|
|
33486
|
+
/**
|
|
33487
|
+
* Main wrapper component that handles config loading and server connection.
|
|
33488
|
+
*/
|
|
33489
|
+
var ChatWidgetConnected = function (props) {
|
|
33490
|
+
var _a;
|
|
33491
|
+
var mode = (_a = props.mode) !== null && _a !== void 0 ? _a : "normal";
|
|
33492
|
+
var _b = useState(props.config), rawConfig = _b[0], setRawConfig = _b[1];
|
|
33493
|
+
var _c = useState(!!props.getConfig), configLoading = _c[0], setConfigLoading = _c[1];
|
|
33494
|
+
var _d = useState(), configError = _d[0], setConfigError = _d[1];
|
|
33495
|
+
// Load config from callback if provided
|
|
33496
|
+
useEffect(function () {
|
|
33497
|
+
var cancelled = false;
|
|
33498
|
+
if (props.getConfig) {
|
|
33499
|
+
setConfigLoading(true);
|
|
33500
|
+
setConfigError(undefined);
|
|
33501
|
+
props
|
|
33502
|
+
.getConfig()
|
|
33503
|
+
.then(function (config) {
|
|
33504
|
+
if (!cancelled) {
|
|
33505
|
+
setRawConfig(config);
|
|
33506
|
+
setConfigLoading(false);
|
|
33507
|
+
log("[ChatWidget] Config loaded from getConfig callback");
|
|
33508
|
+
}
|
|
33509
|
+
})
|
|
33510
|
+
.catch(function (error) {
|
|
33511
|
+
if (!cancelled) {
|
|
33512
|
+
setConfigError(error);
|
|
33513
|
+
setConfigLoading(false);
|
|
33514
|
+
err("[ChatWidget] Failed to load config: ".concat(error.message));
|
|
33515
|
+
}
|
|
33516
|
+
});
|
|
33517
|
+
}
|
|
33518
|
+
else if (props.config) {
|
|
33519
|
+
// If no callback, use the config prop directly
|
|
33520
|
+
setRawConfig(props.config);
|
|
33521
|
+
setConfigLoading(false);
|
|
33522
|
+
}
|
|
33523
|
+
return function () {
|
|
33524
|
+
cancelled = true;
|
|
33525
|
+
};
|
|
33526
|
+
// Only depend on getConfig and config - not the entire props object to avoid infinite loops
|
|
33527
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
33528
|
+
}, [props.getConfig, props.config]);
|
|
33529
|
+
var connection = useConnectionInfo(rawConfig);
|
|
33530
|
+
var config = useMemo(function () {
|
|
33531
|
+
var _a;
|
|
33532
|
+
return (__assign(__assign({}, rawConfig), { connection: connection, assetUrl: (_a = connection === null || connection === void 0 ? void 0 : connection.serverUrl) !== null && _a !== void 0 ? _a : defaultServerUrl, env: rawConfig }));
|
|
33533
|
+
}, [connection, rawConfig]);
|
|
33534
|
+
var token = useSelector(function (state) { return state.connection.token; });
|
|
33535
|
+
var options = useMemo(function () {
|
|
33536
|
+
var configurableMessages = getConfigurableMessages();
|
|
33537
|
+
if ((rawConfig === null || rawConfig === void 0 ? void 0 : rawConfig.configurableMessages) &&
|
|
33538
|
+
Array.isArray(rawConfig.configurableMessages.items) &&
|
|
33539
|
+
rawConfig.configurableMessages.items.length > 0) {
|
|
33540
|
+
configurableMessages = rawConfig.configurableMessages;
|
|
33541
|
+
}
|
|
33542
|
+
return {
|
|
33543
|
+
token: token,
|
|
33544
|
+
bot: {
|
|
33545
|
+
nick: "Bot",
|
|
33546
|
+
displayName: rawConfig === null || rawConfig === void 0 ? void 0 : rawConfig.botName,
|
|
33547
|
+
avatarPath: rawConfig === null || rawConfig === void 0 ? void 0 : rawConfig.avatarUrl,
|
|
33548
|
+
},
|
|
33549
|
+
configurableMessages: configurableMessages,
|
|
33550
|
+
hooks: rawConfig === null || rawConfig === void 0 ? void 0 : rawConfig.hooks,
|
|
33551
|
+
env: rawConfig,
|
|
33552
|
+
};
|
|
33553
|
+
}, [
|
|
33554
|
+
token,
|
|
33555
|
+
rawConfig === null || rawConfig === void 0 ? void 0 : rawConfig.botName,
|
|
33556
|
+
rawConfig === null || rawConfig === void 0 ? void 0 : rawConfig.avatarUrl,
|
|
33557
|
+
rawConfig === null || rawConfig === void 0 ? void 0 : rawConfig.configurableMessages,
|
|
33558
|
+
rawConfig === null || rawConfig === void 0 ? void 0 : rawConfig.hooks,
|
|
33559
|
+
]);
|
|
33560
|
+
// Only create chat server when config is ready (not loading and no error)
|
|
33561
|
+
var chatServer = useChatServer(configLoading || configError ? null : connection, configLoading || configError ? null : options);
|
|
33562
|
+
// Determine mode class for loading/error states (mode already declared above)
|
|
33563
|
+
var modeClass = "widget-container--".concat(mode);
|
|
33564
|
+
// Show loading state while config is being fetched
|
|
33565
|
+
if (configLoading) {
|
|
33566
|
+
return (jsx("div", { className: "widget-container widget-container--loading ".concat(modeClass), children: jsx("div", { className: "xa-spinner-container visible", children: jsx("div", { className: "xa-spinner" }) }) }));
|
|
33567
|
+
}
|
|
33568
|
+
// Show error state if config failed to load
|
|
33569
|
+
if (configError) {
|
|
33570
|
+
return (jsx("div", { className: "widget-container widget-container--error ".concat(modeClass), children: jsxs("div", { className: "widget-error-message", children: ["Failed to load chat configuration: ", configError.message] }) }));
|
|
33571
|
+
}
|
|
33572
|
+
return (jsx(ChatConfigContext.Provider, { value: config, children: jsx(ChatServerContext.Provider, { value: chatServer, children: jsx(ChatWidgetUI, __assign({}, props, { config: rawConfig })) }) }));
|
|
33573
|
+
};
|
|
33574
|
+
/**
|
|
33575
|
+
* Inner ChatWidget component that renders the actual UI.
|
|
33576
|
+
* Exported for use by StaticChatWidgetContainer to avoid infinite loops.
|
|
33577
|
+
*/
|
|
33578
|
+
var ChatWidgetUI = function (props) {
|
|
33579
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4, _5, _6, _7, _8;
|
|
33580
|
+
var innerDispatch = useChatDispatch();
|
|
33581
|
+
var dispatch = useChatServerDispatch();
|
|
33582
|
+
// From Redux
|
|
33583
|
+
var chatState = useSelector(function (state) { return state; });
|
|
33584
|
+
// Refresh modalReference
|
|
33585
|
+
var modalRef = useRef({});
|
|
33586
|
+
var mode = (_a = props.mode) !== null && _a !== void 0 ? _a : "normal";
|
|
33587
|
+
var dockedMode = mode === "docked";
|
|
33588
|
+
var staticMode = mode === "static";
|
|
33589
|
+
// Preview mode can be enabled via `preview` prop (recommended) or legacy `mode="preview"`
|
|
33590
|
+
var previewMode = props.preview === true || mode === "preview";
|
|
33591
|
+
var modeClass = "widget-container--".concat(mode);
|
|
33592
|
+
var canRefresh = (_c = (_b = props.config.header) === null || _b === void 0 ? void 0 : _b.actions) === null || _c === void 0 ? void 0 : _c.refresh;
|
|
33593
|
+
// can't minimize in docked mode, static mode, or preview mode.
|
|
33594
|
+
var canMinimize = !dockedMode && !staticMode && !previewMode && ((_e = (_d = props.config.header) === null || _d === void 0 ? void 0 : _d.actions) === null || _e === void 0 ? void 0 : _e.minimize);
|
|
33595
|
+
log("docked: ".concat(dockedMode, " static: ").concat(staticMode, " preview: ").concat(previewMode, " minimized: ").concat((_g = (_f = props.config.header) === null || _f === void 0 ? void 0 : _f.actions) === null || _g === void 0 ? void 0 : _g.minimize));
|
|
33596
|
+
var canCancel;
|
|
33597
|
+
// To preserve legacy behavior, cancel needs a little more checks
|
|
33598
|
+
if (typeof ((_j = (_h = props.config.header) === null || _h === void 0 ? void 0 : _h.actions) === null || _j === void 0 ? void 0 : _j.cancel) === "boolean") {
|
|
33599
|
+
canCancel = !dockedMode && !staticMode && !previewMode && ((_l = (_k = props.config.header) === null || _k === void 0 ? void 0 : _k.actions) === null || _l === void 0 ? void 0 : _l.cancel);
|
|
33600
|
+
}
|
|
33601
|
+
else {
|
|
33602
|
+
canCancel = !dockedMode && !staticMode && !previewMode;
|
|
33603
|
+
}
|
|
33604
|
+
// For backward compatibility. Note: the action will create the actual "visuals" object" (this is a copy).
|
|
33605
|
+
if (!chatState.visuals) {
|
|
33606
|
+
chatState.visuals = {};
|
|
33607
|
+
}
|
|
33608
|
+
// Our state - pull from storage
|
|
33609
|
+
var _9 = useState((!canMinimize && !canCancel) ||
|
|
33610
|
+
// !!get("visible") ||
|
|
33611
|
+
chatState.visuals.visible ||
|
|
33612
|
+
(((_m = props.config) === null || _m === void 0 ? void 0 : _m.autoOpenOnWidth) &&
|
|
33613
|
+
window.matchMedia("(min-width: ".concat((_o = props.config) === null || _o === void 0 ? void 0 : _o.autoOpenOnWidth, ")")).matches)), visible = _9[0], setVisibleState = _9[1];
|
|
33614
|
+
var _10 = useState(false); _10[0]; var setTypingState = _10[1]; // false initially - state kept for potential external observers
|
|
33615
|
+
// Ref to track typing state for use in timeout callbacks
|
|
33616
|
+
var typingRef = useRef(false);
|
|
33617
|
+
// Timeout ref for debouncing "stop typing" events
|
|
33618
|
+
var stopTypingTimeoutRef = useRef(null);
|
|
33619
|
+
var chatServer = useContext(ChatServerContext);
|
|
33620
|
+
var patternsConfig = (_q = (_p = props.config) === null || _p === void 0 ? void 0 : _p.autoOpenOnPattern) === null || _q === void 0 ? void 0 : _q.patterns;
|
|
33621
|
+
var currentUrl = window.location.href;
|
|
33622
|
+
var patternExist = patternsConfig && patternsConfig.length > 0;
|
|
33623
|
+
var patternMatches = patternsConfig === null || patternsConfig === void 0 ? void 0 : patternsConfig.some(function (pattern) { return currentUrl.includes(pattern); });
|
|
33624
|
+
var configWidth = (_s = (_r = props.config) === null || _r === void 0 ? void 0 : _r.autoOpenOnPattern) === null || _s === void 0 ? void 0 : _s.minimumWidth;
|
|
33625
|
+
// eslint-disable-next-line no-restricted-globals
|
|
33626
|
+
var currentWidth = screen.width;
|
|
33627
|
+
var setVisible = useCallback(function (newVisible) {
|
|
33628
|
+
if (staticMode || previewMode) {
|
|
33629
|
+
return;
|
|
33630
|
+
}
|
|
33631
|
+
log("setVisible: ".concat(newVisible));
|
|
33632
|
+
setVisibleState(newVisible);
|
|
33633
|
+
innerDispatch(setVisualStatus({
|
|
33634
|
+
visible: newVisible,
|
|
33635
|
+
}));
|
|
33636
|
+
}, [innerDispatch, staticMode, previewMode]);
|
|
33637
|
+
useEffect(function () {
|
|
33638
|
+
var _a, _b;
|
|
33639
|
+
var handleKeyDown = function (event) {
|
|
33640
|
+
var body = document.getElementsByTagName("body")[0];
|
|
33641
|
+
body.tabIndex = -1;
|
|
33642
|
+
if (event.key === "Escape") {
|
|
33643
|
+
body.focus();
|
|
33644
|
+
}
|
|
33645
|
+
};
|
|
33646
|
+
document.addEventListener("keydown", handleKeyDown);
|
|
33647
|
+
if (checkSessionExpiration((chatState === null || chatState === void 0 ? void 0 : chatState.sessionExpiration) || ((_a = props.config) === null || _a === void 0 ? void 0 : _a.sessionExpiration), (_b = chatState === null || chatState === void 0 ? void 0 : chatState.chats[chatState.chats.length - 1]) === null || _b === void 0 ? void 0 : _b.timestamp, chatState === null || chatState === void 0 ? void 0 : chatState.lastTimestamp)) {
|
|
33648
|
+
innerDispatch(setSessionId(undefined));
|
|
33649
|
+
innerDispatch(reset());
|
|
33650
|
+
}
|
|
33651
|
+
return function () {
|
|
33652
|
+
document.removeEventListener("keydown", handleKeyDown);
|
|
33653
|
+
// Cleanup typing timeout on unmount
|
|
33654
|
+
if (stopTypingTimeoutRef.current) {
|
|
33655
|
+
clearTimeout(stopTypingTimeoutRef.current);
|
|
33656
|
+
}
|
|
33657
|
+
};
|
|
33658
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
33659
|
+
}, []);
|
|
33660
|
+
var _11 = useState(!document.hidden), isTabVisible = _11[0], setIsTabVisible = _11[1];
|
|
33661
|
+
useEffect(function () {
|
|
33662
|
+
var handleVisibilityChange = function () {
|
|
33663
|
+
setIsTabVisible(!document.hidden);
|
|
33664
|
+
};
|
|
33665
|
+
document.addEventListener("visibilitychange", handleVisibilityChange);
|
|
33666
|
+
return function () {
|
|
33667
|
+
document.removeEventListener("visibilitychange", handleVisibilityChange);
|
|
33668
|
+
};
|
|
33669
|
+
}, []);
|
|
33670
|
+
useEffect(function () {
|
|
33671
|
+
// Too early?
|
|
33672
|
+
if (!chatServer) {
|
|
33673
|
+
log("Tab visibility changed but no chatServer yet");
|
|
33674
|
+
return;
|
|
33675
|
+
}
|
|
33676
|
+
if (!isTabVisible) {
|
|
33677
|
+
log("Tab is HIDDEN - calling sleep()");
|
|
33678
|
+
chatServer.sleep();
|
|
33679
|
+
}
|
|
33680
|
+
else {
|
|
33681
|
+
log("Tab is VISIBLE - calling wakeup()");
|
|
33682
|
+
chatServer.wakeup();
|
|
33683
|
+
}
|
|
33684
|
+
}, [chatServer, innerDispatch, isTabVisible]);
|
|
33685
|
+
// Handle beforeunload to notify router when user is leaving
|
|
33686
|
+
useEffect(function () {
|
|
33687
|
+
if (!chatServer) {
|
|
33688
|
+
return undefined;
|
|
33689
|
+
}
|
|
33690
|
+
var handleBeforeUnload = function () {
|
|
33691
|
+
log("beforeunload - notifying router of user disconnecting");
|
|
33692
|
+
if (chatServer.notifyDisconnecting) {
|
|
33693
|
+
chatServer.notifyDisconnecting();
|
|
33694
|
+
}
|
|
33695
|
+
};
|
|
33696
|
+
window.addEventListener("beforeunload", handleBeforeUnload);
|
|
33697
|
+
return function () {
|
|
33698
|
+
window.removeEventListener("beforeunload", handleBeforeUnload);
|
|
33699
|
+
};
|
|
33700
|
+
}, [chatServer]);
|
|
33701
|
+
useEffect(function () {
|
|
33702
|
+
// For reopen widget after move on same window
|
|
33703
|
+
// if (get("opened")) {
|
|
33704
|
+
// setVisible(true);
|
|
33705
|
+
// }
|
|
33706
|
+
if (chatState.visuals.opened) {
|
|
33707
|
+
setVisible(true);
|
|
33708
|
+
}
|
|
33709
|
+
else {
|
|
33710
|
+
if (mode === "normal") {
|
|
33711
|
+
setVisible(false);
|
|
33712
|
+
}
|
|
33713
|
+
}
|
|
33714
|
+
if (patternExist && patternMatches) {
|
|
33715
|
+
setVisible(true);
|
|
33716
|
+
}
|
|
33717
|
+
if (currentWidth < +configWidth) {
|
|
33718
|
+
setVisible(false);
|
|
33719
|
+
}
|
|
33720
|
+
}, [
|
|
33721
|
+
currentWidth,
|
|
33722
|
+
patternExist,
|
|
33723
|
+
patternMatches,
|
|
33724
|
+
configWidth,
|
|
33725
|
+
setVisible,
|
|
33726
|
+
chatState.visuals.opened,
|
|
33727
|
+
mode,
|
|
33728
|
+
]);
|
|
33729
|
+
var stopTyping = useCallback(function () {
|
|
33730
|
+
if (!typingRef.current)
|
|
33731
|
+
return;
|
|
33732
|
+
// Clear the timeout if it exists
|
|
33733
|
+
if (stopTypingTimeoutRef.current) {
|
|
33734
|
+
clearTimeout(stopTypingTimeoutRef.current);
|
|
33735
|
+
stopTypingTimeoutRef.current = null;
|
|
33736
|
+
}
|
|
33737
|
+
dispatch(sendTyping(false));
|
|
33738
|
+
setTypingState(false);
|
|
33739
|
+
typingRef.current = false;
|
|
33740
|
+
}, [dispatch]);
|
|
33741
|
+
var handleOnChange = useCallback(function () {
|
|
33742
|
+
// Send "typing" event only on first keystroke
|
|
33743
|
+
if (!typingRef.current) {
|
|
33744
|
+
dispatch(sendTyping(true));
|
|
33745
|
+
setTypingState(true);
|
|
33746
|
+
typingRef.current = true;
|
|
33747
|
+
}
|
|
33748
|
+
// Clear any existing timeout
|
|
33749
|
+
if (stopTypingTimeoutRef.current) {
|
|
33750
|
+
clearTimeout(stopTypingTimeoutRef.current);
|
|
33751
|
+
}
|
|
33752
|
+
// Set a new timeout to send "stop typing" after inactivity
|
|
33753
|
+
stopTypingTimeoutRef.current = window.setTimeout(function () {
|
|
33754
|
+
stopTyping();
|
|
33755
|
+
}, TYPING_INDICATOR_DEBOUNCE_MS);
|
|
33756
|
+
}, [dispatch, stopTyping]);
|
|
33757
|
+
function handleSendMessage(msg) {
|
|
33758
|
+
// Don't allow sending messages in preview mode
|
|
33759
|
+
if (previewMode) {
|
|
33760
|
+
return;
|
|
33761
|
+
}
|
|
33762
|
+
dispatch(sendMessage(msg));
|
|
33763
|
+
}
|
|
33764
|
+
function handleWriteMessage(msg) {
|
|
33765
|
+
// Don't allow writing messages in preview mode
|
|
33766
|
+
if (previewMode) {
|
|
33767
|
+
return;
|
|
33768
|
+
}
|
|
33769
|
+
innerDispatch(writeMessage(msg.msg, msg.user));
|
|
33770
|
+
}
|
|
33771
|
+
var handleOpenUrl = useOpenUrlCallback();
|
|
33772
|
+
function handleOnSubmit(rawInput) {
|
|
33773
|
+
// Don't allow any actions in preview mode
|
|
33774
|
+
if (previewMode) {
|
|
33775
|
+
return;
|
|
33776
|
+
}
|
|
33777
|
+
// Don't allow visitor to send msg if not chatting
|
|
33778
|
+
if (chatState.accountStatus === "offline" && !chatState.isChatting)
|
|
33779
|
+
return;
|
|
33780
|
+
// Don't send empty messages
|
|
33781
|
+
if (!rawInput)
|
|
33782
|
+
return;
|
|
33783
|
+
// Immediately stop typing
|
|
33784
|
+
stopTyping();
|
|
33785
|
+
chatServer.flush();
|
|
33786
|
+
dispatch(executeAction(rawInput));
|
|
33787
|
+
}
|
|
33788
|
+
function handleFileUpload(event) {
|
|
33789
|
+
var _a;
|
|
33790
|
+
event.preventDefault();
|
|
33791
|
+
// Don't allow file uploads in preview mode
|
|
33792
|
+
if (previewMode) {
|
|
33793
|
+
return;
|
|
33794
|
+
}
|
|
33795
|
+
// Only send the first file dropped on input
|
|
33796
|
+
var file = (_a = event === null || event === void 0 ? void 0 : event.dataTransfer) === null || _a === void 0 ? void 0 : _a.files[0];
|
|
33797
|
+
if (!file) {
|
|
33798
|
+
return;
|
|
33799
|
+
}
|
|
33800
|
+
dispatch(sendFile(file));
|
|
33801
|
+
}
|
|
33802
|
+
function getVisibilityClass() {
|
|
33803
|
+
return visible ? "visible" : "";
|
|
33804
|
+
}
|
|
33805
|
+
function openRestartConfirmationModal() {
|
|
33806
|
+
// Interesting, this call the modalRef of the restart modal
|
|
33807
|
+
modalRef.current.style.display = "block";
|
|
33808
|
+
}
|
|
33809
|
+
function closeRestartConfirmationModal() {
|
|
33810
|
+
modalRef.current.style.display = "none";
|
|
33811
|
+
}
|
|
33812
|
+
function handleReset() {
|
|
33813
|
+
innerDispatch(reset());
|
|
33814
|
+
}
|
|
33815
|
+
function handleRestartClick() {
|
|
33816
|
+
if (config.header.actions.refreshShowConfirmation) {
|
|
33817
|
+
// show the modal
|
|
33818
|
+
openRestartConfirmationModal();
|
|
33819
|
+
// we will close when
|
|
33820
|
+
}
|
|
33821
|
+
else {
|
|
33822
|
+
handleReset();
|
|
33823
|
+
}
|
|
33824
|
+
}
|
|
33825
|
+
function handleRestartModalCloseClick() {
|
|
33826
|
+
closeRestartConfirmationModal();
|
|
33827
|
+
}
|
|
33828
|
+
/** Called when minimize button is clicked */
|
|
33829
|
+
function handleMinimizeClick() {
|
|
33830
|
+
innerDispatch(setVisualStatus({
|
|
33831
|
+
opened: false,
|
|
33832
|
+
hasInteracted: true,
|
|
33833
|
+
}));
|
|
33834
|
+
setVisible(false);
|
|
33835
|
+
}
|
|
33836
|
+
/** Called when cancel is clicked */
|
|
33837
|
+
function handleCancelClick() {
|
|
33838
|
+
// First reset to clear all state
|
|
33839
|
+
innerDispatch(reset());
|
|
33840
|
+
// Then set hasInteracted to prevent CTA from showing after cancel
|
|
33841
|
+
innerDispatch(setVisualStatus({
|
|
33842
|
+
opened: false,
|
|
33843
|
+
hasInteracted: true,
|
|
33844
|
+
}));
|
|
33845
|
+
setVisible(false);
|
|
33846
|
+
}
|
|
33847
|
+
function chatButtonOnClick() {
|
|
33848
|
+
innerDispatch(setVisualStatus({
|
|
33849
|
+
opened: true,
|
|
33850
|
+
hasInteracted: true,
|
|
33851
|
+
}));
|
|
33852
|
+
setVisible(true);
|
|
33853
|
+
setTimeout(function () {
|
|
33854
|
+
document.getElementById("chatWidgetInput").focus();
|
|
33855
|
+
}, 100);
|
|
33856
|
+
}
|
|
33857
|
+
function handleCtaDismiss() {
|
|
33858
|
+
innerDispatch(setVisualStatus({
|
|
33859
|
+
hasInteracted: true,
|
|
33860
|
+
}));
|
|
33861
|
+
}
|
|
33862
|
+
function handleWsButtonPress(buttonId) {
|
|
33863
|
+
var _a, _b;
|
|
33864
|
+
log("WS Button pressed: ".concat(buttonId));
|
|
33865
|
+
// If the button has spinning behavior, update state to show spinner
|
|
33866
|
+
if (((_a = chatState.wsButton) === null || _a === void 0 ? void 0 : _a.pressBehavior) === "spinning") {
|
|
33867
|
+
// Update the button state to show it's pressed
|
|
33868
|
+
innerDispatch({
|
|
33869
|
+
type: "ws_button_display",
|
|
33870
|
+
detail: __assign(__assign({}, chatState.wsButton), { isPressed: true, timestamp: +new Date() })
|
|
33871
|
+
});
|
|
33872
|
+
}
|
|
33873
|
+
// Send the button pressed event to the server
|
|
33874
|
+
if (chatServer && chatServer.sendButtonPressed) {
|
|
33875
|
+
chatServer.sendButtonPressed(buttonId).catch(function (error) {
|
|
33876
|
+
err("Failed to send button press: ".concat(error));
|
|
33877
|
+
// Reset button state on error
|
|
33878
|
+
if (chatState.wsButton) {
|
|
33879
|
+
innerDispatch({
|
|
33880
|
+
type: "ws_button_display",
|
|
33881
|
+
detail: __assign(__assign({}, chatState.wsButton), { isPressed: false, timestamp: +new Date() })
|
|
33882
|
+
});
|
|
33883
|
+
}
|
|
33884
|
+
});
|
|
33885
|
+
}
|
|
33886
|
+
// If the button has disabled behavior, animate out then dismiss
|
|
33887
|
+
if (((_b = chatState.wsButton) === null || _b === void 0 ? void 0 : _b.pressBehavior) === "disabled") {
|
|
33888
|
+
// First set dismissing state to trigger animation
|
|
33889
|
+
innerDispatch({
|
|
33890
|
+
type: "ws_button_display",
|
|
33891
|
+
detail: __assign(__assign({}, chatState.wsButton), { isDismissing: true, timestamp: +new Date() })
|
|
33892
|
+
});
|
|
33893
|
+
// Then actually dismiss after animation completes
|
|
33894
|
+
setTimeout(function () {
|
|
33895
|
+
innerDispatch({
|
|
33896
|
+
type: "ws_button_dismiss",
|
|
33897
|
+
detail: {
|
|
33898
|
+
id: buttonId,
|
|
33899
|
+
timestamp: +new Date()
|
|
33900
|
+
}
|
|
33901
|
+
});
|
|
33902
|
+
}, WS_BUTTON_DISMISS_ANIMATION_DURATION);
|
|
33903
|
+
}
|
|
33904
|
+
}
|
|
33905
|
+
var isOffline = chatState.accountStatus === "offline" && !chatState.isChatting;
|
|
33906
|
+
var messages = chatState && chatState.chats;
|
|
33907
|
+
log("Rendering - accountStatus: \"".concat(chatState.accountStatus, "\", connectionStatus: \"").concat(chatState.connection.connectionStatus, "\""));
|
|
33908
|
+
var config = props.config, onConnectionStatusChange = props.onConnectionStatusChange;
|
|
33909
|
+
// Disable greeting in preview mode
|
|
33910
|
+
useGreeting(!isOffline && !props.preChatFormEnabled && visible && !previewMode);
|
|
33911
|
+
var connectionStatus = chatState.connection.connectionStatus;
|
|
33912
|
+
useEffect(function () {
|
|
33913
|
+
if (onConnectionStatusChange) {
|
|
33914
|
+
onConnectionStatusChange(connectionStatus);
|
|
33915
|
+
}
|
|
33916
|
+
}, [connectionStatus, onConnectionStatusChange]);
|
|
33917
|
+
useExternalScript((_t = props.config) === null || _t === void 0 ? void 0 : _t.middlewareUrl);
|
|
33918
|
+
// This is a pseudo agent. It represent's the widget (shown in the header avatar for instance)
|
|
33919
|
+
var widgetAgent = ((_u = chatState.agents["agent:robot"]) === null || _u === void 0 ? void 0 : _u.user) ||
|
|
33920
|
+
(config === null || config === void 0 ? void 0 : config.agent) || {
|
|
33921
|
+
nick: "agent:robot",
|
|
33922
|
+
avatarPath: config.avatarUrl,
|
|
33923
|
+
display_name: "Agent",
|
|
33924
|
+
};
|
|
33925
|
+
return (jsxs(Fragment, { children: [jsxs("div", { className: "widget-container ".concat(modeClass, " ").concat(getVisibilityClass()), children: [jsx(WidgetStylesheet, { theme: config === null || config === void 0 ? void 0 : config.theme }), jsx(ChatHeader, { accountStatus: chatState.accountStatus, refreshOnClick: handleRestartClick, minimizeOnClick: handleMinimizeClick, cancelOnClick: handleCancelClick, agent: widgetAgent, canRefresh: canRefresh, canMinimize: canMinimize, canCancel: canCancel, config: config === null || config === void 0 ? void 0 : config.header, menuConfig: config.menu, onSubmit: handleOnSubmit }), jsx(MessageList, { visible: visible, queuePosition: chatState.queuePosition, isChatting: chatState.isChatting, isOffline: isOffline, messages: messages, agents: chatState.agents, agent: config === null || config === void 0 ? void 0 : config.agent, lastRatingRequestTimestamp: chatState.lastRatingRequestTimestamp, hasRating: chatState.hasRating, visitorId: chatState.visitorId, hasWsButton: !!chatState.wsButton, messageMiddleware: props.messageMiddleware, textTypingStatusEnabled: (_w = (_v = props.config) === null || _v === void 0 ? void 0 : _v.typingStatus) === null || _w === void 0 ? void 0 : _w.textTypingStatusEnabled, disableAutoScroll: props.disableAutoScroll, onSend: handleSendMessage, onWrite: handleWriteMessage, onOpenUrl: handleOpenUrl, minimizeOnClick: handleMinimizeClick }), jsx("div", { className: "xa-spinner-container ".concat(visible && connectionStatus === "pending" ? "visible" : ""), children: jsx("div", { className: "xa-spinner" }) }), connectionStatus === "offline" && jsx(ServerOffline, {}), chatState.wsButton && visible && (jsx(WsButton, { button: chatState.wsButton, onPress: handleWsButtonPress })), jsx(ChatFooter, { isAdmin: config === null || config === void 0 ? void 0 : config.isAdmin, isChatting: chatState.isChatting, placeholder: (_x = config === null || config === void 0 ? void 0 : config.input) === null || _x === void 0 ? void 0 : _x.placeholder, sendButtonIcon: (_z = (_y = config === null || config === void 0 ? void 0 : config.footer) === null || _y === void 0 ? void 0 : _y.sendButton) === null || _z === void 0 ? void 0 : _z.icon, sendButtonIconHover: (_1 = (_0 = config === null || config === void 0 ? void 0 : config.footer) === null || _0 === void 0 ? void 0 : _0.sendButton) === null || _1 === void 0 ? void 0 : _1.iconHover, sendButtonIconDisabled: (_3 = (_2 = config === null || config === void 0 ? void 0 : config.footer) === null || _2 === void 0 ? void 0 : _2.sendButton) === null || _3 === void 0 ? void 0 : _3.iconDisabled, visible: visible, hasWsButton: !!chatState.wsButton, menuConfig: (_4 = props.config) === null || _4 === void 0 ? void 0 : _4.menu, footerConfig: (_5 = props.config) === null || _5 === void 0 ? void 0 : _5.footer, inputConfig: (_6 = props.config) === null || _6 === void 0 ? void 0 : _6.input, disabled: previewMode, onChange: handleOnChange, onSubmit: handleOnSubmit, onFileUpload: handleFileUpload }), jsx("div", { className: "restartModal", ref: modalRef, onClick: handleRestartModalCloseClick, children: jsx(ModalContent, { onClose: handleRestartModalCloseClick, onReset: handleReset }) })] }), jsx(ChatButton, { addClass: getVisibilityClass(), onClick: chatButtonOnClick, config: config === null || config === void 0 ? void 0 : config.cta, imageUrl: (_7 = config === null || config === void 0 ? void 0 : config.chatButton) === null || _7 === void 0 ? void 0 : _7.imageUrl, visible: visible, hasInteracted: (_8 = chatState.visuals) === null || _8 === void 0 ? void 0 : _8.hasInteracted, onCtaDismiss: handleCtaDismiss }), jsx(ErrorOverlay, { enableErrorOverlay: config === null || config === void 0 ? void 0 : config.enableErrorOverlay })] }));
|
|
33926
|
+
};
|
|
33927
|
+
/**
|
|
33928
|
+
* Top-level wrapper that dispatches between preview mode and connected mode.
|
|
33929
|
+
* This separation ensures React hooks rules are not violated.
|
|
33930
|
+
*/
|
|
33931
|
+
var ChatWidgetWrapper = function (props) {
|
|
33932
|
+
var _a;
|
|
33933
|
+
var rawMode = (_a = props.mode) !== null && _a !== void 0 ? _a : "normal";
|
|
33934
|
+
// Support both `preview` prop and legacy `mode="preview"`
|
|
33935
|
+
var isPreviewMode = props.preview === true || rawMode === "preview";
|
|
33936
|
+
// For visual layout, use "static" when mode is "preview" (legacy), otherwise use the actual mode
|
|
33937
|
+
var visualMode = rawMode === "preview" ? "static" : rawMode;
|
|
33938
|
+
if (isPreviewMode) {
|
|
33939
|
+
return jsx(ChatWidgetPreview, __assign({}, props, { mode: visualMode }));
|
|
33940
|
+
}
|
|
33941
|
+
return jsx(ChatWidgetConnected, __assign({}, props));
|
|
33942
|
+
};
|
|
33943
|
+
|
|
33717
33944
|
function tryParseJson(str) {
|
|
33718
33945
|
try {
|
|
33719
33946
|
if (str) {
|
|
@@ -33743,55 +33970,6 @@ var BrowserStateStorage = /** @class */ (function () {
|
|
|
33743
33970
|
return BrowserStateStorage;
|
|
33744
33971
|
}());
|
|
33745
33972
|
|
|
33746
|
-
/**
|
|
33747
|
-
* Id the visitor (cookies, browser fingerprint, etc)
|
|
33748
|
-
*
|
|
33749
|
-
* @export
|
|
33750
|
-
* @returns {string}
|
|
33751
|
-
*/
|
|
33752
|
-
function visitorFingerprint() {
|
|
33753
|
-
return uuid_1();
|
|
33754
|
-
}
|
|
33755
|
-
|
|
33756
|
-
var DEFAULT_VISITOR = {
|
|
33757
|
-
displayName: "Visitor",
|
|
33758
|
-
nick: "visitor:",
|
|
33759
|
-
typing: false
|
|
33760
|
-
};
|
|
33761
|
-
function createDefaultState(state, options) {
|
|
33762
|
-
var _a;
|
|
33763
|
-
if (!state) {
|
|
33764
|
-
state = {};
|
|
33765
|
-
}
|
|
33766
|
-
state.userId = state.userId ? state.userId : visitorFingerprint();
|
|
33767
|
-
state.visitorId = state.userId;
|
|
33768
|
-
// Determine if debug mode should be enabled
|
|
33769
|
-
var debugMode = false;
|
|
33770
|
-
if (typeof window !== 'undefined') {
|
|
33771
|
-
var localStorageSetting = (_a = window.localStorage) === null || _a === void 0 ? void 0 : _a.getItem('xaErrorOverlay');
|
|
33772
|
-
if (localStorageSetting === 'enabled') {
|
|
33773
|
-
debugMode = true;
|
|
33774
|
-
}
|
|
33775
|
-
else if (localStorageSetting === 'disabled') {
|
|
33776
|
-
debugMode = false;
|
|
33777
|
-
}
|
|
33778
|
-
else if (options === null || options === void 0 ? void 0 : options.enableErrorOverlay) {
|
|
33779
|
-
// Use config option if no localStorage override
|
|
33780
|
-
debugMode = true;
|
|
33781
|
-
}
|
|
33782
|
-
else if (typeof globalThis.__DEV__ !== 'undefined' && globalThis.__DEV__) {
|
|
33783
|
-
// For React Native, default to true in development mode
|
|
33784
|
-
debugMode = true;
|
|
33785
|
-
}
|
|
33786
|
-
}
|
|
33787
|
-
return __assign({ connection: {
|
|
33788
|
-
connectionStatus: "offline",
|
|
33789
|
-
token: null,
|
|
33790
|
-
greetingRequested: false
|
|
33791
|
-
}, accountStatus: "offline", departments: {}, visitor: DEFAULT_VISITOR, agents: {}, chats: [], lastTimestamp: 0, lastRatingRequestTimestamp: 0, hasRating: false, isChatting: false, queuePosition: 0, failureMsg: null, visitorId: visitorFingerprint(), chips: [], sessionExpiration: "24h", visuals: {}, debugMode: debugMode }, state);
|
|
33792
|
-
}
|
|
33793
|
-
var DEFAULT_STATE = createDefaultState();
|
|
33794
|
-
|
|
33795
33973
|
/**
|
|
33796
33974
|
* Polyfill for Browser Local Storage
|
|
33797
33975
|
*
|
|
@@ -34207,7 +34385,18 @@ function generateKey(connection, sessionId) {
|
|
|
34207
34385
|
}
|
|
34208
34386
|
}
|
|
34209
34387
|
|
|
34210
|
-
|
|
34388
|
+
/**
|
|
34389
|
+
* Preview mode container - skips server config and store creation.
|
|
34390
|
+
*/
|
|
34391
|
+
var ChatWidgetPreviewContainer = function (props) {
|
|
34392
|
+
var messageMiddleware = useStandardMiddleware();
|
|
34393
|
+
var widgetProps = __assign(__assign({}, props), { messageMiddleware: messageMiddleware });
|
|
34394
|
+
return jsx(ChatWidgetWrapper, __assign({}, widgetProps));
|
|
34395
|
+
};
|
|
34396
|
+
/**
|
|
34397
|
+
* Connected mode container - creates store and connects to server.
|
|
34398
|
+
*/
|
|
34399
|
+
var ChatWidgetConnectedContainer = function (props) {
|
|
34211
34400
|
var _a, _b, _c, _d, _e, _f;
|
|
34212
34401
|
var messageMiddleware = useStandardMiddleware();
|
|
34213
34402
|
var connection = useServerConfig(props.config);
|
|
@@ -34229,55 +34418,18 @@ var ChatWidgetContainer = function (props) {
|
|
|
34229
34418
|
});
|
|
34230
34419
|
return (jsx(Provider, { store: chatStore, children: jsx(ChatWidgetWrapper, __assign({}, widgetProps)) }));
|
|
34231
34420
|
};
|
|
34232
|
-
|
|
34233
|
-
|
|
34234
|
-
|
|
34235
|
-
|
|
34236
|
-
|
|
34237
|
-
|
|
34238
|
-
|
|
34239
|
-
|
|
34240
|
-
|
|
34241
|
-
|
|
34242
|
-
|
|
34243
|
-
|
|
34244
|
-
var store = configureStore({
|
|
34245
|
-
reducer: reducer,
|
|
34246
|
-
middleware: function (getDefaultMiddleware) {
|
|
34247
|
-
return getDefaultMiddleware({
|
|
34248
|
-
thunk: true, // Thunk is included by default, this is just for explicitness
|
|
34249
|
-
});
|
|
34250
|
-
},
|
|
34251
|
-
devTools: "production" !== 'production', // Redux DevTools in non-production environments
|
|
34252
|
-
});
|
|
34253
|
-
return store;
|
|
34254
|
-
}
|
|
34255
|
-
|
|
34256
|
-
var StaticChatWidgetContainer = function (props) {
|
|
34257
|
-
var state = props.state;
|
|
34258
|
-
var store = useMemo(function () {
|
|
34259
|
-
return createStaticStore(state);
|
|
34260
|
-
}, [state]);
|
|
34261
|
-
var config = useMemo(function () {
|
|
34262
|
-
return __assign(__assign({}, props.config), { connection: {
|
|
34263
|
-
serverUrl: "",
|
|
34264
|
-
type: "local",
|
|
34265
|
-
} });
|
|
34266
|
-
}, [props.config]);
|
|
34267
|
-
return (jsx(Provider, { store: store, children: jsx(ChatWidgetWrapper, __assign({}, props, { config: config })) }));
|
|
34268
|
-
};
|
|
34269
|
-
|
|
34270
|
-
function createStateFromMessages(messages) {
|
|
34271
|
-
var def = createDefaultState();
|
|
34272
|
-
return __assign(__assign({}, def), { connection: __assign(__assign({}, def.connection), { connectionStatus: "online" }), accountStatus: "online", chats: __spreadArray$1([], messages, true), isChatting: true, visuals: {} });
|
|
34273
|
-
}
|
|
34274
|
-
|
|
34275
|
-
var StaticMessagesChatWidgetContainer = function (props) {
|
|
34276
|
-
var messages = props.messages;
|
|
34277
|
-
var state = useMemo(function () {
|
|
34278
|
-
return createStateFromMessages(messages);
|
|
34279
|
-
}, [messages]);
|
|
34280
|
-
return jsx(StaticChatWidgetContainer, { state: state, mode: props.mode, config: props.config });
|
|
34421
|
+
/**
|
|
34422
|
+
* Top-level container that dispatches between preview and connected modes.
|
|
34423
|
+
*/
|
|
34424
|
+
var ChatWidgetContainer = function (props) {
|
|
34425
|
+
var _a;
|
|
34426
|
+
var rawMode = (_a = props.mode) !== null && _a !== void 0 ? _a : "normal";
|
|
34427
|
+
// Support both `preview` prop and legacy `mode="preview"`
|
|
34428
|
+
var isPreviewMode = props.preview === true || rawMode === "preview";
|
|
34429
|
+
if (isPreviewMode) {
|
|
34430
|
+
return jsx(ChatWidgetPreviewContainer, __assign({}, props));
|
|
34431
|
+
}
|
|
34432
|
+
return jsx(ChatWidgetConnectedContainer, __assign({}, props));
|
|
34281
34433
|
};
|
|
34282
34434
|
|
|
34283
34435
|
export { ActionButton, Avatar, CardMiddleware, Carousel, CarouselItem, ChatWidgetContainer as Chat, ChatButton, ChatCard, ChatChip, ChatChips, ChatHeader, ChatMenu, ChatMessage, ChatMessageBubble, ChatMessagePart, ChatWidgetWrapper as ChatWidget, CtaBubble, CtaBubbleContainer, List, ListItem, ListMiddleware, MessageList, MiddlewareContextFactory, StaticChatWidgetContainer, StaticMessagesChatWidgetContainer, joinMiddlewares, responseToMessage, useLateMiddleware, useStandardMiddleware };
|