@xapp/chat-widget 1.82.1 → 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/index.es.js +650 -517
- package/dist/index.es.js.map +1 -1
- package/dist/index.js +1088 -955
- package/dist/index.js.map +1 -1
- package/dist/xapp-chat-widget.js +2 -2
- package/dist/xapp-chat-widget.js.map +1 -1
- package/package.json +6 -6
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';
|
|
@@ -9050,7 +9050,7 @@ var ChatMessage = function (props) {
|
|
|
9050
9050
|
var agentInfo = (_a = props.agents) === null || _a === void 0 ? void 0 : _a[props.message.user.nick];
|
|
9051
9051
|
var hideUserInfo = (agentInfo === null || agentInfo === void 0 ? void 0 : agentInfo.hideUserInfo) || false;
|
|
9052
9052
|
function renderByType() {
|
|
9053
|
-
var _a, _b, _c, _d;
|
|
9053
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
|
|
9054
9054
|
var msg = props.message.msg;
|
|
9055
9055
|
switch (props.message.type) {
|
|
9056
9056
|
// TODO: props actually requires it to be "chat.msg". Fix prop typing?
|
|
@@ -9059,15 +9059,15 @@ var ChatMessage = function (props) {
|
|
|
9059
9059
|
// OR card OR list only. Avatar with text bubble.
|
|
9060
9060
|
var avaKey = avaKeys.find(function (key) { return !!msg[key]; });
|
|
9061
9061
|
return (jsxs(Fragment, { children: [msg.text &&
|
|
9062
|
-
jsx(ChatMessagePart, { showAvatar: avaKey === "text", user: user, avatarPosition: (_a = chatConfig.env.theme.messages) === null ||
|
|
9063
|
-
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) {
|
|
9064
9064
|
if (display.type === "ScheduleButton") {
|
|
9065
9065
|
return (jsx(ChatScheduleWidget, { minimizeOnClick: props.minimizeOnClick, display: display }));
|
|
9066
9066
|
}
|
|
9067
9067
|
var Middleware = middleware;
|
|
9068
9068
|
return (jsx(Middleware, { msg: display, ctx: props.middlewareContext }, index));
|
|
9069
9069
|
}), msg.permissionRequest && ctx &&
|
|
9070
|
-
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 }) })] }));
|
|
9071
9071
|
}
|
|
9072
9072
|
return (jsx(Fragment, {}));
|
|
9073
9073
|
}
|
|
@@ -9174,10 +9174,12 @@ function useChatServerVisitorId() {
|
|
|
9174
9174
|
}
|
|
9175
9175
|
//send whenever server settings or visitor id changes
|
|
9176
9176
|
function useGreeting(active) {
|
|
9177
|
+
var _a, _b;
|
|
9177
9178
|
var curr = useChatServerVisitorId();
|
|
9178
9179
|
var snapshotRef = useRef(null);
|
|
9179
9180
|
var ctx = useContext(ChatConfigContext);
|
|
9180
|
-
|
|
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;
|
|
9181
9183
|
var sessionId = useSelector(function (state) { return state.sessionId; });
|
|
9182
9184
|
useEffect(function () {
|
|
9183
9185
|
if (active) {
|
|
@@ -9576,7 +9578,7 @@ var Suggestions = function (props) {
|
|
|
9576
9578
|
|
|
9577
9579
|
var ChatFooter = function (props) {
|
|
9578
9580
|
var _a, _b, _c;
|
|
9579
|
-
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;
|
|
9580
9582
|
var innerDispatch = useChatDispatch();
|
|
9581
9583
|
var _d = useState(false), drawerOpen = _d[0], setDrawerState = _d[1]; // false initially
|
|
9582
9584
|
var _e = useState(), suggestionSearch = _e[0], setSuggestionSearch = _e[1];
|
|
@@ -9634,7 +9636,7 @@ var ChatFooter = function (props) {
|
|
|
9634
9636
|
setEnableInput(status);
|
|
9635
9637
|
};
|
|
9636
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 ?
|
|
9637
|
-
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,
|
|
9638
9640
|
// onFocus={this.inputOnFocus}
|
|
9639
9641
|
onFileUpload: props.onFileUpload }) }), brandingEnabled && brandingText && jsx(ChatBranding, { text: brandingText })] }));
|
|
9640
9642
|
};
|
|
@@ -32158,425 +32160,61 @@ var ModalContent = function (_a) {
|
|
|
32158
32160
|
};
|
|
32159
32161
|
|
|
32160
32162
|
/**
|
|
32161
|
-
*
|
|
32162
|
-
*
|
|
32163
|
+
* Id the visitor (cookies, browser fingerprint, etc)
|
|
32164
|
+
*
|
|
32165
|
+
* @export
|
|
32166
|
+
* @returns {string}
|
|
32163
32167
|
*/
|
|
32164
|
-
|
|
32165
|
-
|
|
32166
|
-
|
|
32167
|
-
|
|
32168
|
-
|
|
32169
|
-
|
|
32170
|
-
|
|
32171
|
-
|
|
32172
|
-
var cancelled = false;
|
|
32173
|
-
if (props.getConfig) {
|
|
32174
|
-
setConfigLoading(true);
|
|
32175
|
-
setConfigError(undefined);
|
|
32176
|
-
props
|
|
32177
|
-
.getConfig()
|
|
32178
|
-
.then(function (config) {
|
|
32179
|
-
if (!cancelled) {
|
|
32180
|
-
setRawConfig(config);
|
|
32181
|
-
setConfigLoading(false);
|
|
32182
|
-
log("[ChatWidget] Config loaded from getConfig callback");
|
|
32183
|
-
}
|
|
32184
|
-
})
|
|
32185
|
-
.catch(function (error) {
|
|
32186
|
-
if (!cancelled) {
|
|
32187
|
-
setConfigError(error);
|
|
32188
|
-
setConfigLoading(false);
|
|
32189
|
-
err("[ChatWidget] Failed to load config: ".concat(error.message));
|
|
32190
|
-
}
|
|
32191
|
-
});
|
|
32192
|
-
}
|
|
32193
|
-
else if (props.config) {
|
|
32194
|
-
// If no callback, use the config prop directly
|
|
32195
|
-
setRawConfig(props.config);
|
|
32196
|
-
setConfigLoading(false);
|
|
32197
|
-
}
|
|
32198
|
-
return function () {
|
|
32199
|
-
cancelled = true;
|
|
32200
|
-
};
|
|
32201
|
-
// Only depend on getConfig and config - not the entire props object to avoid infinite loops
|
|
32202
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
32203
|
-
}, [props.getConfig, props.config]);
|
|
32204
|
-
var connection = useConnectionInfo(rawConfig);
|
|
32205
|
-
var config = useMemo(function () {
|
|
32206
|
-
var _a;
|
|
32207
|
-
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 }));
|
|
32208
|
-
}, [connection, rawConfig]);
|
|
32209
|
-
var token = useSelector(function (state) { return state.connection.token; });
|
|
32210
|
-
var options = useMemo(function () {
|
|
32211
|
-
var configurableMessages = getConfigurableMessages();
|
|
32212
|
-
if ((rawConfig === null || rawConfig === void 0 ? void 0 : rawConfig.configurableMessages) &&
|
|
32213
|
-
Array.isArray(rawConfig.configurableMessages.items) &&
|
|
32214
|
-
rawConfig.configurableMessages.items.length > 0) {
|
|
32215
|
-
configurableMessages = rawConfig.configurableMessages;
|
|
32216
|
-
}
|
|
32217
|
-
return {
|
|
32218
|
-
token: token,
|
|
32219
|
-
bot: {
|
|
32220
|
-
nick: "Bot",
|
|
32221
|
-
displayName: rawConfig === null || rawConfig === void 0 ? void 0 : rawConfig.botName,
|
|
32222
|
-
avatarPath: rawConfig === null || rawConfig === void 0 ? void 0 : rawConfig.avatarUrl,
|
|
32223
|
-
},
|
|
32224
|
-
configurableMessages: configurableMessages,
|
|
32225
|
-
hooks: rawConfig === null || rawConfig === void 0 ? void 0 : rawConfig.hooks,
|
|
32226
|
-
env: rawConfig,
|
|
32227
|
-
};
|
|
32228
|
-
}, [
|
|
32229
|
-
token,
|
|
32230
|
-
rawConfig === null || rawConfig === void 0 ? void 0 : rawConfig.botName,
|
|
32231
|
-
rawConfig === null || rawConfig === void 0 ? void 0 : rawConfig.avatarUrl,
|
|
32232
|
-
rawConfig === null || rawConfig === void 0 ? void 0 : rawConfig.configurableMessages,
|
|
32233
|
-
rawConfig === null || rawConfig === void 0 ? void 0 : rawConfig.hooks,
|
|
32234
|
-
]);
|
|
32235
|
-
// Only create chat server when config is ready (not loading and no error)
|
|
32236
|
-
var chatServer = useChatServer(configLoading || configError ? null : connection, configLoading || configError ? null : options);
|
|
32237
|
-
// Determine mode class for loading/error states
|
|
32238
|
-
var mode = (_a = props.mode) !== null && _a !== void 0 ? _a : "normal";
|
|
32239
|
-
var modeClass = "widget-container--".concat(mode);
|
|
32240
|
-
// Show loading state while config is being fetched
|
|
32241
|
-
if (configLoading) {
|
|
32242
|
-
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" }) }) }));
|
|
32243
|
-
}
|
|
32244
|
-
// Show error state if config failed to load
|
|
32245
|
-
if (configError) {
|
|
32246
|
-
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] }) }));
|
|
32247
|
-
}
|
|
32248
|
-
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
|
|
32249
32176
|
};
|
|
32250
|
-
|
|
32251
|
-
var _a
|
|
32252
|
-
|
|
32253
|
-
|
|
32254
|
-
// From Redux
|
|
32255
|
-
var chatState = useSelector(function (state) { return state; });
|
|
32256
|
-
// Refresh modalReference
|
|
32257
|
-
var modalRef = useRef({});
|
|
32258
|
-
var mode = (_a = props.mode) !== null && _a !== void 0 ? _a : "normal";
|
|
32259
|
-
var dockedMode = mode === "docked";
|
|
32260
|
-
var staticMode = mode === "static";
|
|
32261
|
-
var modeClass = "widget-container--".concat(mode);
|
|
32262
|
-
var canRefresh = (_c = (_b = props.config.header) === null || _b === void 0 ? void 0 : _b.actions) === null || _c === void 0 ? void 0 : _c.refresh;
|
|
32263
|
-
// can't minimize in docked mode or static mode.
|
|
32264
|
-
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);
|
|
32265
|
-
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));
|
|
32266
|
-
var canCancel;
|
|
32267
|
-
// To preserve legacy behavior, cancel needs a little more checks
|
|
32268
|
-
if (typeof ((_j = (_h = props.config.header) === null || _h === void 0 ? void 0 : _h.actions) === null || _j === void 0 ? void 0 : _j.cancel) === "boolean") {
|
|
32269
|
-
canCancel = !dockedMode && !staticMode && ((_l = (_k = props.config.header) === null || _k === void 0 ? void 0 : _k.actions) === null || _l === void 0 ? void 0 : _l.cancel);
|
|
32270
|
-
}
|
|
32271
|
-
else {
|
|
32272
|
-
canCancel = !dockedMode && !staticMode;
|
|
32273
|
-
}
|
|
32274
|
-
// For backward compatibility. Note: the action will create the actual "visuals" object" (this is a copy).
|
|
32275
|
-
if (!chatState.visuals) {
|
|
32276
|
-
chatState.visuals = {};
|
|
32177
|
+
function createDefaultState(state, options) {
|
|
32178
|
+
var _a;
|
|
32179
|
+
if (!state) {
|
|
32180
|
+
state = {};
|
|
32277
32181
|
}
|
|
32278
|
-
|
|
32279
|
-
|
|
32280
|
-
|
|
32281
|
-
|
|
32282
|
-
|
|
32283
|
-
|
|
32284
|
-
|
|
32285
|
-
|
|
32286
|
-
var typingRef = useRef(false);
|
|
32287
|
-
// Timeout ref for debouncing "stop typing" events
|
|
32288
|
-
var stopTypingTimeoutRef = useRef(null);
|
|
32289
|
-
var chatServer = useContext(ChatServerContext);
|
|
32290
|
-
var patternsConfig = (_q = (_p = props.config) === null || _p === void 0 ? void 0 : _p.autoOpenOnPattern) === null || _q === void 0 ? void 0 : _q.patterns;
|
|
32291
|
-
var currentUrl = window.location.href;
|
|
32292
|
-
var patternExist = patternsConfig && patternsConfig.length > 0;
|
|
32293
|
-
var patternMatches = patternsConfig === null || patternsConfig === void 0 ? void 0 : patternsConfig.some(function (pattern) { return currentUrl.includes(pattern); });
|
|
32294
|
-
var configWidth = (_s = (_r = props.config) === null || _r === void 0 ? void 0 : _r.autoOpenOnPattern) === null || _s === void 0 ? void 0 : _s.minimumWidth;
|
|
32295
|
-
// eslint-disable-next-line no-restricted-globals
|
|
32296
|
-
var currentWidth = screen.width;
|
|
32297
|
-
var setVisible = useCallback(function (newVisible) {
|
|
32298
|
-
if (staticMode) {
|
|
32299
|
-
return;
|
|
32300
|
-
}
|
|
32301
|
-
log("setVisible: ".concat(newVisible));
|
|
32302
|
-
setVisibleState(newVisible);
|
|
32303
|
-
innerDispatch(setVisualStatus({
|
|
32304
|
-
visible: newVisible,
|
|
32305
|
-
}));
|
|
32306
|
-
}, [innerDispatch, staticMode]);
|
|
32307
|
-
useEffect(function () {
|
|
32308
|
-
var _a, _b;
|
|
32309
|
-
var handleKeyDown = function (event) {
|
|
32310
|
-
var body = document.getElementsByTagName("body")[0];
|
|
32311
|
-
body.tabIndex = -1;
|
|
32312
|
-
if (event.key === "Escape") {
|
|
32313
|
-
body.focus();
|
|
32314
|
-
}
|
|
32315
|
-
};
|
|
32316
|
-
document.addEventListener("keydown", handleKeyDown);
|
|
32317
|
-
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)) {
|
|
32318
|
-
innerDispatch(setSessionId(undefined));
|
|
32319
|
-
innerDispatch(reset());
|
|
32320
|
-
}
|
|
32321
|
-
return function () {
|
|
32322
|
-
document.removeEventListener("keydown", handleKeyDown);
|
|
32323
|
-
// Cleanup typing timeout on unmount
|
|
32324
|
-
if (stopTypingTimeoutRef.current) {
|
|
32325
|
-
clearTimeout(stopTypingTimeoutRef.current);
|
|
32326
|
-
}
|
|
32327
|
-
};
|
|
32328
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
32329
|
-
}, []);
|
|
32330
|
-
var _10 = useState(!document.hidden), isTabVisible = _10[0], setIsTabVisible = _10[1];
|
|
32331
|
-
useEffect(function () {
|
|
32332
|
-
var handleVisibilityChange = function () {
|
|
32333
|
-
setIsTabVisible(!document.hidden);
|
|
32334
|
-
};
|
|
32335
|
-
document.addEventListener("visibilitychange", handleVisibilityChange);
|
|
32336
|
-
return function () {
|
|
32337
|
-
document.removeEventListener("visibilitychange", handleVisibilityChange);
|
|
32338
|
-
};
|
|
32339
|
-
}, []);
|
|
32340
|
-
useEffect(function () {
|
|
32341
|
-
// Too early?
|
|
32342
|
-
if (!chatServer) {
|
|
32343
|
-
log("Tab visibility changed but no chatServer yet");
|
|
32344
|
-
return;
|
|
32345
|
-
}
|
|
32346
|
-
if (!isTabVisible) {
|
|
32347
|
-
log("Tab is HIDDEN - calling sleep()");
|
|
32348
|
-
chatServer.sleep();
|
|
32349
|
-
}
|
|
32350
|
-
else {
|
|
32351
|
-
log("Tab is VISIBLE - calling wakeup()");
|
|
32352
|
-
chatServer.wakeup();
|
|
32353
|
-
}
|
|
32354
|
-
}, [chatServer, innerDispatch, isTabVisible]);
|
|
32355
|
-
// Handle beforeunload to notify router when user is leaving
|
|
32356
|
-
useEffect(function () {
|
|
32357
|
-
if (!chatServer) {
|
|
32358
|
-
return undefined;
|
|
32359
|
-
}
|
|
32360
|
-
var handleBeforeUnload = function () {
|
|
32361
|
-
log("beforeunload - notifying router of user disconnecting");
|
|
32362
|
-
if (chatServer.notifyDisconnecting) {
|
|
32363
|
-
chatServer.notifyDisconnecting();
|
|
32364
|
-
}
|
|
32365
|
-
};
|
|
32366
|
-
window.addEventListener("beforeunload", handleBeforeUnload);
|
|
32367
|
-
return function () {
|
|
32368
|
-
window.removeEventListener("beforeunload", handleBeforeUnload);
|
|
32369
|
-
};
|
|
32370
|
-
}, [chatServer]);
|
|
32371
|
-
useEffect(function () {
|
|
32372
|
-
// For reopen widget after move on same window
|
|
32373
|
-
// if (get("opened")) {
|
|
32374
|
-
// setVisible(true);
|
|
32375
|
-
// }
|
|
32376
|
-
if (chatState.visuals.opened) {
|
|
32377
|
-
setVisible(true);
|
|
32378
|
-
}
|
|
32379
|
-
else {
|
|
32380
|
-
if (mode === "normal") {
|
|
32381
|
-
setVisible(false);
|
|
32382
|
-
}
|
|
32383
|
-
}
|
|
32384
|
-
if (patternExist && patternMatches) {
|
|
32385
|
-
setVisible(true);
|
|
32386
|
-
}
|
|
32387
|
-
if (currentWidth < +configWidth) {
|
|
32388
|
-
setVisible(false);
|
|
32389
|
-
}
|
|
32390
|
-
}, [
|
|
32391
|
-
currentWidth,
|
|
32392
|
-
patternExist,
|
|
32393
|
-
patternMatches,
|
|
32394
|
-
configWidth,
|
|
32395
|
-
setVisible,
|
|
32396
|
-
chatState.visuals.opened,
|
|
32397
|
-
mode,
|
|
32398
|
-
]);
|
|
32399
|
-
var stopTyping = useCallback(function () {
|
|
32400
|
-
if (!typingRef.current)
|
|
32401
|
-
return;
|
|
32402
|
-
// Clear the timeout if it exists
|
|
32403
|
-
if (stopTypingTimeoutRef.current) {
|
|
32404
|
-
clearTimeout(stopTypingTimeoutRef.current);
|
|
32405
|
-
stopTypingTimeoutRef.current = null;
|
|
32406
|
-
}
|
|
32407
|
-
dispatch(sendTyping(false));
|
|
32408
|
-
setTypingState(false);
|
|
32409
|
-
typingRef.current = false;
|
|
32410
|
-
}, [dispatch]);
|
|
32411
|
-
var handleOnChange = useCallback(function () {
|
|
32412
|
-
// Send "typing" event only on first keystroke
|
|
32413
|
-
if (!typingRef.current) {
|
|
32414
|
-
dispatch(sendTyping(true));
|
|
32415
|
-
setTypingState(true);
|
|
32416
|
-
typingRef.current = true;
|
|
32417
|
-
}
|
|
32418
|
-
// Clear any existing timeout
|
|
32419
|
-
if (stopTypingTimeoutRef.current) {
|
|
32420
|
-
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;
|
|
32421
32190
|
}
|
|
32422
|
-
|
|
32423
|
-
|
|
32424
|
-
stopTyping();
|
|
32425
|
-
}, TYPING_INDICATOR_DEBOUNCE_MS);
|
|
32426
|
-
}, [dispatch, stopTyping]);
|
|
32427
|
-
function handleSendMessage(msg) {
|
|
32428
|
-
dispatch(sendMessage(msg));
|
|
32429
|
-
}
|
|
32430
|
-
function handleWriteMessage(msg) {
|
|
32431
|
-
innerDispatch(writeMessage(msg.msg, msg.user));
|
|
32432
|
-
}
|
|
32433
|
-
var handleOpenUrl = useOpenUrlCallback();
|
|
32434
|
-
function handleOnSubmit(rawInput) {
|
|
32435
|
-
// Don't allow visitor to send msg if not chatting
|
|
32436
|
-
if (chatState.accountStatus === "offline" && !chatState.isChatting)
|
|
32437
|
-
return;
|
|
32438
|
-
// Don't send empty messages
|
|
32439
|
-
if (!rawInput)
|
|
32440
|
-
return;
|
|
32441
|
-
// Immediately stop typing
|
|
32442
|
-
stopTyping();
|
|
32443
|
-
chatServer.flush();
|
|
32444
|
-
dispatch(executeAction(rawInput));
|
|
32445
|
-
}
|
|
32446
|
-
function handleFileUpload(event) {
|
|
32447
|
-
var _a;
|
|
32448
|
-
event.preventDefault();
|
|
32449
|
-
// Only send the first file dropped on input
|
|
32450
|
-
var file = (_a = event === null || event === void 0 ? void 0 : event.dataTransfer) === null || _a === void 0 ? void 0 : _a.files[0];
|
|
32451
|
-
if (!file) {
|
|
32452
|
-
return;
|
|
32191
|
+
else if (localStorageSetting === 'disabled') {
|
|
32192
|
+
debugMode = false;
|
|
32453
32193
|
}
|
|
32454
|
-
|
|
32455
|
-
|
|
32456
|
-
|
|
32457
|
-
return visible ? "visible" : "";
|
|
32458
|
-
}
|
|
32459
|
-
function openRestartConfirmationModal() {
|
|
32460
|
-
// Interesting, this call the modalRef of the restart modal
|
|
32461
|
-
modalRef.current.style.display = "block";
|
|
32462
|
-
}
|
|
32463
|
-
function closeRestartConfirmationModal() {
|
|
32464
|
-
modalRef.current.style.display = "none";
|
|
32465
|
-
}
|
|
32466
|
-
function handleReset() {
|
|
32467
|
-
innerDispatch(reset());
|
|
32468
|
-
}
|
|
32469
|
-
function handleRestartClick() {
|
|
32470
|
-
if (config.header.actions.refreshShowConfirmation) {
|
|
32471
|
-
// show the modal
|
|
32472
|
-
openRestartConfirmationModal();
|
|
32473
|
-
// 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;
|
|
32474
32197
|
}
|
|
32475
|
-
else {
|
|
32476
|
-
|
|
32198
|
+
else if (typeof globalThis.__DEV__ !== 'undefined' && globalThis.__DEV__) {
|
|
32199
|
+
// For React Native, default to true in development mode
|
|
32200
|
+
debugMode = true;
|
|
32477
32201
|
}
|
|
32478
32202
|
}
|
|
32479
|
-
|
|
32480
|
-
|
|
32481
|
-
|
|
32482
|
-
|
|
32483
|
-
|
|
32484
|
-
|
|
32485
|
-
|
|
32486
|
-
|
|
32487
|
-
|
|
32488
|
-
|
|
32489
|
-
}
|
|
32490
|
-
|
|
32491
|
-
function handleCancelClick() {
|
|
32492
|
-
// First reset to clear all state
|
|
32493
|
-
innerDispatch(reset());
|
|
32494
|
-
// Then set hasInteracted to prevent CTA from showing after cancel
|
|
32495
|
-
innerDispatch(setVisualStatus({
|
|
32496
|
-
opened: false,
|
|
32497
|
-
hasInteracted: true,
|
|
32498
|
-
}));
|
|
32499
|
-
setVisible(false);
|
|
32500
|
-
}
|
|
32501
|
-
function chatButtonOnClick() {
|
|
32502
|
-
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,
|
|
32503
32215
|
opened: true,
|
|
32504
|
-
|
|
32505
|
-
|
|
32506
|
-
setVisible(true);
|
|
32507
|
-
setTimeout(function () {
|
|
32508
|
-
document.getElementById("chatWidgetInput").focus();
|
|
32509
|
-
}, 100);
|
|
32510
|
-
}
|
|
32511
|
-
function handleCtaDismiss() {
|
|
32512
|
-
innerDispatch(setVisualStatus({
|
|
32513
|
-
hasInteracted: true,
|
|
32514
|
-
}));
|
|
32515
|
-
}
|
|
32516
|
-
function handleWsButtonPress(buttonId) {
|
|
32517
|
-
var _a, _b;
|
|
32518
|
-
log("WS Button pressed: ".concat(buttonId));
|
|
32519
|
-
// If the button has spinning behavior, update state to show spinner
|
|
32520
|
-
if (((_a = chatState.wsButton) === null || _a === void 0 ? void 0 : _a.pressBehavior) === "spinning") {
|
|
32521
|
-
// Update the button state to show it's pressed
|
|
32522
|
-
innerDispatch({
|
|
32523
|
-
type: "ws_button_display",
|
|
32524
|
-
detail: __assign(__assign({}, chatState.wsButton), { isPressed: true, timestamp: +new Date() })
|
|
32525
|
-
});
|
|
32526
|
-
}
|
|
32527
|
-
// Send the button pressed event to the server
|
|
32528
|
-
if (chatServer && chatServer.sendButtonPressed) {
|
|
32529
|
-
chatServer.sendButtonPressed(buttonId).catch(function (error) {
|
|
32530
|
-
err("Failed to send button press: ".concat(error));
|
|
32531
|
-
// Reset button state on error
|
|
32532
|
-
if (chatState.wsButton) {
|
|
32533
|
-
innerDispatch({
|
|
32534
|
-
type: "ws_button_display",
|
|
32535
|
-
detail: __assign(__assign({}, chatState.wsButton), { isPressed: false, timestamp: +new Date() })
|
|
32536
|
-
});
|
|
32537
|
-
}
|
|
32538
|
-
});
|
|
32539
|
-
}
|
|
32540
|
-
// If the button has disabled behavior, animate out then dismiss
|
|
32541
|
-
if (((_b = chatState.wsButton) === null || _b === void 0 ? void 0 : _b.pressBehavior) === "disabled") {
|
|
32542
|
-
// First set dismissing state to trigger animation
|
|
32543
|
-
innerDispatch({
|
|
32544
|
-
type: "ws_button_display",
|
|
32545
|
-
detail: __assign(__assign({}, chatState.wsButton), { isDismissing: true, timestamp: +new Date() })
|
|
32546
|
-
});
|
|
32547
|
-
// Then actually dismiss after animation completes
|
|
32548
|
-
setTimeout(function () {
|
|
32549
|
-
innerDispatch({
|
|
32550
|
-
type: "ws_button_dismiss",
|
|
32551
|
-
detail: {
|
|
32552
|
-
id: buttonId,
|
|
32553
|
-
timestamp: +new Date()
|
|
32554
|
-
}
|
|
32555
|
-
});
|
|
32556
|
-
}, WS_BUTTON_DISMISS_ANIMATION_DURATION);
|
|
32557
|
-
}
|
|
32558
|
-
}
|
|
32559
|
-
var isOffline = chatState.accountStatus === "offline" && !chatState.isChatting;
|
|
32560
|
-
var messages = chatState && chatState.chats;
|
|
32561
|
-
log("Rendering - accountStatus: \"".concat(chatState.accountStatus, "\", connectionStatus: \"").concat(chatState.connection.connectionStatus, "\""));
|
|
32562
|
-
var config = props.config, onConnectionStatusChange = props.onConnectionStatusChange;
|
|
32563
|
-
useGreeting(!isOffline && !props.preChatFormEnabled && visible);
|
|
32564
|
-
var connectionStatus = chatState.connection.connectionStatus;
|
|
32565
|
-
useEffect(function () {
|
|
32566
|
-
if (onConnectionStatusChange) {
|
|
32567
|
-
onConnectionStatusChange(connectionStatus);
|
|
32568
|
-
}
|
|
32569
|
-
}, [connectionStatus, onConnectionStatusChange]);
|
|
32570
|
-
useExternalScript((_t = props.config) === null || _t === void 0 ? void 0 : _t.middlewareUrl);
|
|
32571
|
-
// This is a pseudo agent. It represent's the widget (shown in the header avatar for instance)
|
|
32572
|
-
var widgetAgent = ((_u = chatState.agents["agent:robot"]) === null || _u === void 0 ? void 0 : _u.user) ||
|
|
32573
|
-
(config === null || config === void 0 ? void 0 : config.agent) || {
|
|
32574
|
-
nick: "agent:robot",
|
|
32575
|
-
avatarPath: config.avatarUrl,
|
|
32576
|
-
display_name: "Agent",
|
|
32577
|
-
};
|
|
32578
|
-
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: 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 })] }));
|
|
32579
|
-
};
|
|
32216
|
+
} });
|
|
32217
|
+
}
|
|
32580
32218
|
|
|
32581
32219
|
// src/utils/formatProdErrorMessage.ts
|
|
32582
32220
|
function formatProdErrorMessage$1(code) {
|
|
@@ -33733,6 +33371,576 @@ function formatProdErrorMessage(code) {
|
|
|
33733
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. `;
|
|
33734
33372
|
}
|
|
33735
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
|
+
|
|
33736
33944
|
function tryParseJson(str) {
|
|
33737
33945
|
try {
|
|
33738
33946
|
if (str) {
|
|
@@ -33762,55 +33970,6 @@ var BrowserStateStorage = /** @class */ (function () {
|
|
|
33762
33970
|
return BrowserStateStorage;
|
|
33763
33971
|
}());
|
|
33764
33972
|
|
|
33765
|
-
/**
|
|
33766
|
-
* Id the visitor (cookies, browser fingerprint, etc)
|
|
33767
|
-
*
|
|
33768
|
-
* @export
|
|
33769
|
-
* @returns {string}
|
|
33770
|
-
*/
|
|
33771
|
-
function visitorFingerprint() {
|
|
33772
|
-
return uuid_1();
|
|
33773
|
-
}
|
|
33774
|
-
|
|
33775
|
-
var DEFAULT_VISITOR = {
|
|
33776
|
-
displayName: "Visitor",
|
|
33777
|
-
nick: "visitor:",
|
|
33778
|
-
typing: false
|
|
33779
|
-
};
|
|
33780
|
-
function createDefaultState(state, options) {
|
|
33781
|
-
var _a;
|
|
33782
|
-
if (!state) {
|
|
33783
|
-
state = {};
|
|
33784
|
-
}
|
|
33785
|
-
state.userId = state.userId ? state.userId : visitorFingerprint();
|
|
33786
|
-
state.visitorId = state.userId;
|
|
33787
|
-
// Determine if debug mode should be enabled
|
|
33788
|
-
var debugMode = false;
|
|
33789
|
-
if (typeof window !== 'undefined') {
|
|
33790
|
-
var localStorageSetting = (_a = window.localStorage) === null || _a === void 0 ? void 0 : _a.getItem('xaErrorOverlay');
|
|
33791
|
-
if (localStorageSetting === 'enabled') {
|
|
33792
|
-
debugMode = true;
|
|
33793
|
-
}
|
|
33794
|
-
else if (localStorageSetting === 'disabled') {
|
|
33795
|
-
debugMode = false;
|
|
33796
|
-
}
|
|
33797
|
-
else if (options === null || options === void 0 ? void 0 : options.enableErrorOverlay) {
|
|
33798
|
-
// Use config option if no localStorage override
|
|
33799
|
-
debugMode = true;
|
|
33800
|
-
}
|
|
33801
|
-
else if (typeof globalThis.__DEV__ !== 'undefined' && globalThis.__DEV__) {
|
|
33802
|
-
// For React Native, default to true in development mode
|
|
33803
|
-
debugMode = true;
|
|
33804
|
-
}
|
|
33805
|
-
}
|
|
33806
|
-
return __assign({ connection: {
|
|
33807
|
-
connectionStatus: "offline",
|
|
33808
|
-
token: null,
|
|
33809
|
-
greetingRequested: false
|
|
33810
|
-
}, 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);
|
|
33811
|
-
}
|
|
33812
|
-
var DEFAULT_STATE = createDefaultState();
|
|
33813
|
-
|
|
33814
33973
|
/**
|
|
33815
33974
|
* Polyfill for Browser Local Storage
|
|
33816
33975
|
*
|
|
@@ -34226,7 +34385,18 @@ function generateKey(connection, sessionId) {
|
|
|
34226
34385
|
}
|
|
34227
34386
|
}
|
|
34228
34387
|
|
|
34229
|
-
|
|
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) {
|
|
34230
34400
|
var _a, _b, _c, _d, _e, _f;
|
|
34231
34401
|
var messageMiddleware = useStandardMiddleware();
|
|
34232
34402
|
var connection = useServerConfig(props.config);
|
|
@@ -34248,55 +34418,18 @@ var ChatWidgetContainer = function (props) {
|
|
|
34248
34418
|
});
|
|
34249
34419
|
return (jsx(Provider, { store: chatStore, children: jsx(ChatWidgetWrapper, __assign({}, widgetProps)) }));
|
|
34250
34420
|
};
|
|
34251
|
-
|
|
34252
|
-
|
|
34253
|
-
|
|
34254
|
-
|
|
34255
|
-
|
|
34256
|
-
|
|
34257
|
-
|
|
34258
|
-
|
|
34259
|
-
|
|
34260
|
-
|
|
34261
|
-
|
|
34262
|
-
|
|
34263
|
-
var store = configureStore({
|
|
34264
|
-
reducer: reducer,
|
|
34265
|
-
middleware: function (getDefaultMiddleware) {
|
|
34266
|
-
return getDefaultMiddleware({
|
|
34267
|
-
thunk: true, // Thunk is included by default, this is just for explicitness
|
|
34268
|
-
});
|
|
34269
|
-
},
|
|
34270
|
-
devTools: "production" !== 'production', // Redux DevTools in non-production environments
|
|
34271
|
-
});
|
|
34272
|
-
return store;
|
|
34273
|
-
}
|
|
34274
|
-
|
|
34275
|
-
var StaticChatWidgetContainer = function (props) {
|
|
34276
|
-
var state = props.state;
|
|
34277
|
-
var store = useMemo(function () {
|
|
34278
|
-
return createStaticStore(state);
|
|
34279
|
-
}, [state]);
|
|
34280
|
-
var config = useMemo(function () {
|
|
34281
|
-
return __assign(__assign({}, props.config), { connection: {
|
|
34282
|
-
serverUrl: "",
|
|
34283
|
-
type: "local",
|
|
34284
|
-
} });
|
|
34285
|
-
}, [props.config]);
|
|
34286
|
-
return (jsx(Provider, { store: store, children: jsx(ChatWidgetWrapper, __assign({}, props, { config: config, disableAutoScroll: props.disableAutoScroll })) }));
|
|
34287
|
-
};
|
|
34288
|
-
|
|
34289
|
-
function createStateFromMessages(messages) {
|
|
34290
|
-
var def = createDefaultState();
|
|
34291
|
-
return __assign(__assign({}, def), { connection: __assign(__assign({}, def.connection), { connectionStatus: "online" }), accountStatus: "online", chats: __spreadArray$1([], messages, true), isChatting: true, visuals: {} });
|
|
34292
|
-
}
|
|
34293
|
-
|
|
34294
|
-
var StaticMessagesChatWidgetContainer = function (props) {
|
|
34295
|
-
var messages = props.messages;
|
|
34296
|
-
var state = useMemo(function () {
|
|
34297
|
-
return createStateFromMessages(messages);
|
|
34298
|
-
}, [messages]);
|
|
34299
|
-
return jsx(StaticChatWidgetContainer, { state: state, mode: props.mode, config: props.config, disableAutoScroll: props.disableAutoScroll });
|
|
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));
|
|
34300
34433
|
};
|
|
34301
34434
|
|
|
34302
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 };
|