@botonic/react
Version:
Build Chatbots using React
626 lines • 30.8 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Webchat = exports.getParsedAction = void 0;
const tslib_1 = require("tslib");
const jsx_runtime_1 = require("react/jsx-runtime");
const core_1 = require("@botonic/core");
const lodash_merge_1 = tslib_1.__importDefault(require("lodash.merge"));
const react_1 = tslib_1.__importStar(require("react"));
const react_textarea_autosize_1 = tslib_1.__importDefault(require("react-textarea-autosize"));
const styled_components_1 = tslib_1.__importStar(require("styled-components"));
const use_async_effect_1 = require("use-async-effect");
const uuid_1 = require("uuid");
const components_1 = require("../components");
const handoff_1 = require("../components/handoff");
const webchat_settings_1 = require("../components/webchat-settings");
const constants_1 = require("../constants");
const contexts_1 = require("../contexts");
const message_utils_1 = require("../message-utils");
const msg_to_botonic_1 = require("../msg-to-botonic");
const dom_1 = require("../util/dom");
const environment_1 = require("../util/environment");
const regexs_1 = require("../util/regexs");
const webchat_1 = require("../util/webchat");
const attachment_1 = require("./components/attachment");
const emoji_picker_1 = require("./components/emoji-picker");
const persistent_menu_1 = require("./components/persistent-menu");
const send_button_1 = require("./components/send-button");
const typing_indicator_1 = require("./components/typing-indicator");
const device_adapter_1 = require("./devices/device-adapter");
const header_1 = require("./header");
const hooks_1 = require("./hooks");
const message_list_1 = require("./message-list");
const replies_1 = require("./replies");
const trigger_button_1 = require("./trigger-button");
const use_storage_state_hook_1 = require("./use-storage-state-hook");
const webview_1 = require("./webview");
const getParsedAction = botonicAction => {
const splittedAction = botonicAction.split('create_case:');
if (splittedAction.length <= 1)
return undefined;
return JSON.parse(splittedAction[1]);
};
exports.getParsedAction = getParsedAction;
const StyledWebchat = styled_components_1.default.div `
position: fixed;
right: 20px;
bottom: 20px;
width: ${props => props.width}px;
height: ${props => props.height}px;
margin: auto;
background-color: ${constants_1.COLORS.SOLID_WHITE};
border-radius: 10px;
box-shadow: ${constants_1.COLORS.SOLID_BLACK_ALPHA_0_2} 0px 0px 12px;
display: flex;
flex-direction: column;
`;
const UserInputContainer = styled_components_1.default.div `
min-height: 52px;
position: relative;
display: flex;
align-items: center;
justify-content: flex-start;
gap: 16px;
padding: 0px 16px;
z-index: 1;
border-top: 1px solid ${constants_1.COLORS.SOLID_BLACK_ALPHA_0_5};
`;
const TextAreaContainer = styled_components_1.default.div `
display: flex;
flex: 1 1 auto;
align-items: center;
`;
const ErrorMessageContainer = styled_components_1.default.div `
position: relative;
display: flex;
z-index: 1;
justify-content: center;
width: 100%;
`;
const ErrorMessage = styled_components_1.default.div `
position: absolute;
top: 10px;
font-size: 14px;
line-height: 20px;
padding: 4px 11px;
display: flex;
background-color: ${constants_1.COLORS.ERROR_RED};
color: ${constants_1.COLORS.CONCRETE_WHITE};
border-radius: 5px;
align-items: center;
justify-content: center;
font-family: ${constants_1.WEBCHAT.DEFAULTS.FONT_FAMILY};
`;
const DarkBackgroundMenu = styled_components_1.default.div `
background: ${constants_1.COLORS.SOLID_BLACK};
opacity: 0.3;
z-index: 1;
right: 0;
bottom: 0;
border-radius: 10px;
position: absolute;
width: 100%;
height: 100%;
`;
// eslint-disable-next-line complexity, react/display-name
exports.Webchat = (0, react_1.forwardRef)((props, ref) => {
const { webchatState, addMessage, addMessageComponent, updateMessage, updateReplies, updateLatestInput, updateTyping, updateWebview, updateSession, updateLastRoutePath, updateHandoff, updateTheme, updateDevSettings, toggleWebchat, toggleEmojiPicker, togglePersistentMenu, toggleCoverComponent, doRenderCustomComponent, setError, setOnline, clearMessages, openWebviewT, updateLastMessageDate, setCurrentAttachment,
// eslint-disable-next-line react-hooks/rules-of-hooks
} = props.webchatHooks || (0, hooks_1.useWebchat)();
const firstUpdate = (0, react_1.useRef)(true);
const isOnline = () => webchatState.online;
const currentDateString = () => new Date().toISOString();
const theme = (0, lodash_merge_1.default)(webchatState.theme, props.theme);
const { initialSession, initialDevSettings, onStateChange } = props;
const getThemeProperty = (0, webchat_1._getThemeProperty)(theme);
const [customComponent, setCustomComponent] = (0, react_1.useState)(null);
const storage = props.storage;
const storageKey = typeof props.storageKey === 'function'
? props.storageKey()
: props.storageKey;
const [botonicState, saveState] = (0, use_storage_state_hook_1.useStorageState)(storage, storageKey);
const host = props.host || document.body;
const deviceAdapter = new device_adapter_1.DeviceAdapter();
const saveWebchatState = webchatState => {
storage &&
saveState(JSON.parse((0, regexs_1.stringifyWithRegexs)({
messages: webchatState.messagesJSON,
session: webchatState.session,
lastRoutePath: webchatState.lastRoutePath,
devSettings: webchatState.devSettings,
lastMessageUpdate: webchatState.lastMessageUpdate,
themeUpdates: webchatState.themeUpdates,
})));
};
const handleAttachment = event => {
if (!(0, message_utils_1.isAllowedSize)(event.target.files[0].size)) {
throw new Error(`The file is too large. A maximum of ${constants_1.MAX_ALLOWED_SIZE_MB}MB is allowed.`);
}
setCurrentAttachment({
fileName: event.target.files[0].name,
file: event.target.files[0],
attachmentType: (0, message_utils_1.getMediaType)(event.target.files[0].type),
});
};
(0, react_1.useEffect)(() => {
if (webchatState.currentAttachment)
sendAttachment(webchatState.currentAttachment);
}, [webchatState.currentAttachment]);
const sendUserInput = async (input) => {
props.onUserInput &&
props.onUserInput({
user: webchatState.session.user,
input: input,
session: webchatState.session,
lastRoutePath: webchatState.lastRoutePath,
});
};
const sendChatEvent = async (chatEvent) => {
const chatEventInput = {
id: (0, uuid_1.v4)(),
type: core_1.INPUT.CHAT_EVENT,
data: chatEvent,
};
props.onUserInput &&
props.onUserInput({
user: webchatState.session.user,
input: chatEventInput,
session: webchatState.session,
lastRoutePath: webchatState.lastRoutePath,
});
};
// Load styles stored in window._botonicInsertStyles by Webpack
(0, hooks_1.useComponentWillMount)(() => {
if (window._botonicInsertStyles && window._botonicInsertStyles.length) {
for (const botonicStyle of window._botonicInsertStyles) {
// Injecting styles at head is needed even if we use shadowDOM
// as some dependencies like simplebar rely on creating ephemeral elements
// on document.body and assume styles will be available globally
document.head.appendChild(botonicStyle);
// injecting styles in host node too so that shadowDOM works
if (props.shadowDOM)
host.appendChild(botonicStyle.cloneNode(true));
}
delete window._botonicInsertStyles;
}
if (props.shadowDOM) {
// emoji-picker-react injects styles in head, so we need to
// re-inject them in our host node to make it work with shadowDOM
for (const style of document.querySelectorAll('style')) {
if (style.textContent &&
style.textContent.includes('emoji-picker-react'))
host.appendChild(style.cloneNode(true));
}
}
});
// Load initial state from storage
(0, react_1.useEffect)(() => {
let { messages, session, lastRoutePath, devSettings, lastMessageUpdate, themeUpdates, } = botonicState || {};
session = (0, webchat_1.initSession)(session);
updateSession(session);
if ((0, webchat_1.shouldKeepSessionOnReload)({ initialDevSettings, devSettings })) {
if (messages) {
messages.forEach(m => {
addMessage(m);
const newComponent = (0, msg_to_botonic_1.msgToBotonic)(Object.assign(Object.assign({}, m), { delay: 0, typing: 0 }), (props.theme.message && props.theme.message.customTypes) ||
props.theme.customMessageTypes);
if (newComponent)
addMessageComponent(newComponent);
});
}
if (initialSession)
updateSession((0, lodash_merge_1.default)(initialSession, session));
if (lastRoutePath)
updateLastRoutePath(lastRoutePath);
}
else
updateSession((0, lodash_merge_1.default)(initialSession, session));
if (devSettings)
updateDevSettings(devSettings);
else if (initialDevSettings)
updateDevSettings(initialDevSettings);
if (lastMessageUpdate)
updateLastMessageDate(lastMessageUpdate);
if (themeUpdates !== undefined)
updateTheme((0, lodash_merge_1.default)(props.theme, themeUpdates), themeUpdates);
if (props.onInit)
setTimeout(() => props.onInit(), 100);
}, []);
(0, react_1.useEffect)(() => {
if (!webchatState.isWebchatOpen)
return;
deviceAdapter.init(host);
(0, dom_1.scrollToBottom)({ behavior: 'auto', host });
}, [webchatState.isWebchatOpen]);
(0, react_1.useEffect)(() => {
if (onStateChange && typeof onStateChange === 'function')
onStateChange(webchatState);
saveWebchatState(webchatState);
}, [
webchatState.messagesJSON,
webchatState.session,
webchatState.lastRoutePath,
webchatState.devSettings,
webchatState.lastMessageUpdate,
]);
(0, use_async_effect_1.useAsyncEffect)(async () => {
if (!webchatState.online) {
setError({
message: (0, webchat_1.getServerErrorMessage)(props.server),
});
}
else {
if (!firstUpdate.current) {
setError(undefined);
}
}
}, [webchatState.online]);
(0, hooks_1.useTyping)({ webchatState, updateTyping, updateMessage, host });
(0, react_1.useEffect)(() => {
updateTheme((0, lodash_merge_1.default)(props.theme, theme, webchatState.themeUpdates));
}, [props.theme, webchatState.themeUpdates]);
const openWebview = (webviewComponent, params) => updateWebview(webviewComponent, params);
const handleSelectedEmoji = event => {
textArea.current.value += event.emoji;
textArea.current.focus();
};
const closeWebview = options => {
updateWebview();
if (userInputEnabled) {
textArea.current.focus();
}
if (options && options.payload) {
sendPayload(options.payload);
}
else if (options && options.path) {
let params = '';
if (options.params)
params = (0, core_1.params2queryString)(options.params);
sendPayload(`__PATH_PAYLOAD__${options.path}?${params}`);
}
};
const handleMenu = () => {
togglePersistentMenu(!webchatState.isPersistentMenuOpen);
};
const handleEmojiClick = () => {
toggleEmojiPicker(!webchatState.isEmojiPickerOpen);
};
const persistentMenuOptions = getThemeProperty(constants_1.WEBCHAT.CUSTOM_PROPERTIES.persistentMenu, props.persistentMenu);
const darkBackgroundMenu = getThemeProperty(constants_1.WEBCHAT.CUSTOM_PROPERTIES.darkBackgroundMenu, false);
const getBlockInputs = (rule, inputData) => {
const processedInput = rule.preprocess
? rule.preprocess(inputData)
: inputData;
return rule.match.some(regex => {
if (typeof regex === 'string')
regex = (0, regexs_1.deserializeRegex)(regex);
return regex.test(processedInput);
});
};
const checkBlockInput = input => {
// if is a text we check if it is a serialized RE
const blockInputs = getThemeProperty(constants_1.WEBCHAT.CUSTOM_PROPERTIES.blockInputs, props.blockInputs);
if (!Array.isArray(blockInputs))
return false;
for (const rule of blockInputs) {
if (getBlockInputs(rule, input.data)) {
addMessageComponent((0, jsx_runtime_1.jsx)(components_1.Text, Object.assign({ id: input.id, from: constants_1.SENDERS.user, blob: false, style: {
backgroundColor: constants_1.COLORS.SCORPION_GRAY,
borderColor: constants_1.COLORS.SCORPION_GRAY,
padding: '8px 12px',
} }, { children: rule.message })));
updateReplies(false);
return true;
}
}
return false;
};
const closeMenu = () => {
togglePersistentMenu(false);
};
const persistentMenu = () => {
return ((0, jsx_runtime_1.jsx)(persistent_menu_1.OpenedPersistentMenu, { onClick: closeMenu, options: persistentMenuOptions, borderRadius: webchatState.theme.style.borderRadius || '10px' }));
};
const getCoverComponent = () => {
return getThemeProperty(constants_1.WEBCHAT.CUSTOM_PROPERTIES.coverComponent, props.coverComponent &&
(props.coverComponent.component || props.coverComponent));
};
const CoverComponent = getCoverComponent();
const closeCoverComponent = () => {
toggleCoverComponent(false);
};
(0, react_1.useEffect)(() => {
if (!CoverComponent)
return;
if (!botonicState ||
(botonicState.messages && botonicState.messages.length == 0))
toggleCoverComponent(true);
}, []);
const coverComponent = () => {
const coverComponentProps = getThemeProperty(constants_1.WEBCHAT.CUSTOM_PROPERTIES.coverComponentProps, props.coverComponent && props.coverComponent.props);
if (CoverComponent && webchatState.isCoverComponentOpen)
return ((0, jsx_runtime_1.jsx)(CoverComponent, Object.assign({ closeComponent: closeCoverComponent }, coverComponentProps)));
return null;
};
const messageComponentFromInput = input => {
let messageComponent = null;
if ((0, message_utils_1.isText)(input)) {
messageComponent = ((0, jsx_runtime_1.jsx)(components_1.Text, Object.assign({ id: input.id, payload: input.payload, from: constants_1.SENDERS.user }, { children: input.data })));
}
else if ((0, message_utils_1.isMedia)(input)) {
const temporaryDisplayUrl = URL.createObjectURL(input.data);
const mediaProps = {
id: input.id,
from: constants_1.SENDERS.user,
src: temporaryDisplayUrl,
};
if ((0, message_utils_1.isImage)(input)) {
mediaProps.input = input;
messageComponent = (0, jsx_runtime_1.jsx)(components_1.Image, Object.assign({}, mediaProps));
}
else if ((0, message_utils_1.isAudio)(input))
messageComponent = (0, jsx_runtime_1.jsx)(components_1.Audio, Object.assign({}, mediaProps));
else if ((0, message_utils_1.isVideo)(input))
messageComponent = (0, jsx_runtime_1.jsx)(components_1.Video, Object.assign({}, mediaProps));
else if ((0, message_utils_1.isDocument)(input))
messageComponent = (0, jsx_runtime_1.jsx)(components_1.Document, Object.assign({}, mediaProps));
}
return messageComponent;
};
const sendInput = async (input) => {
if (!input || Object.keys(input).length == 0)
return;
if ((0, message_utils_1.isText)(input) && (!input.data || !input.data.trim()))
return; // in case trim() doesn't work in a browser we can use !/\S/.test(input.data)
if ((0, message_utils_1.isText)(input) && checkBlockInput(input))
return;
if (!input.id)
input.id = (0, uuid_1.v4)();
const messageComponent = messageComponentFromInput(input);
if (messageComponent)
addMessageComponent(messageComponent);
if ((0, message_utils_1.isMedia)(input))
input.data = await (0, message_utils_1.readDataURL)(input.data);
sendUserInput(input);
updateLatestInput(input);
isOnline() && updateLastMessageDate(currentDateString());
updateReplies(false);
togglePersistentMenu(false);
toggleEmojiPicker(false);
};
/* This is the public API this component exposes to its parents
https://stackoverflow.com/questions/37949981/call-child-method-from-parent
*/
const updateSessionWithUser = userToUpdate => updateSession((0, lodash_merge_1.default)(webchatState.session, { user: userToUpdate }));
(0, react_1.useImperativeHandle)(ref, () => ({
addBotResponse: ({ response, session, lastRoutePath }) => {
updateTyping(false);
if (Array.isArray(response))
response.map(r => addMessageComponent(r));
else if (response)
addMessageComponent(response);
if (session) {
updateSession((0, lodash_merge_1.default)(session, { user: webchatState.session.user }));
const action = session._botonic_action || '';
const handoff = action.startsWith('create_case');
if (handoff && environment_1.isDev)
addMessageComponent((0, jsx_runtime_1.jsx)(handoff_1.Handoff, {}));
updateHandoff(handoff);
}
if (lastRoutePath)
updateLastRoutePath(lastRoutePath);
updateLastMessageDate(currentDateString());
},
setTyping: typing => updateTyping(typing),
addUserMessage: message => sendInput(message),
updateUser: updateSessionWithUser,
openWebchat: () => toggleWebchat(true),
closeWebchat: () => toggleWebchat(false),
toggleWebchat: () => toggleWebchat(!webchatState.isWebchatOpen),
openCoverComponent: () => toggleCoverComponent(true),
closeCoverComponent: () => toggleCoverComponent(false),
renderCustomComponent: _customComponent => {
setCustomComponent(_customComponent);
doRenderCustomComponent(true);
},
unmountCustomComponent: () => doRenderCustomComponent(false),
toggleCoverComponent: () => toggleCoverComponent(!webchatState.isCoverComponentOpen),
openWebviewApi: component => openWebviewT(component),
setError,
setOnline,
getMessages: () => webchatState.messagesJSON,
isOnline,
clearMessages: () => {
clearMessages();
updateReplies(false);
},
getLastMessageUpdate: () => webchatState.lastMessageUpdate,
updateMessageInfo: (msgId, messageInfo) => {
const messageToUpdate = webchatState.messagesJSON.filter(m => m.id == msgId)[0];
const updatedMsg = (0, lodash_merge_1.default)(messageToUpdate, messageInfo);
if (updatedMsg.ack === 1)
delete updatedMsg.unsentInput;
updateMessage(updatedMsg);
},
updateWebchatSettings: settings => {
const themeUpdates = (0, webchat_settings_1.normalizeWebchatSettings)(settings);
updateTheme((0, lodash_merge_1.default)(webchatState.theme, themeUpdates), themeUpdates);
},
}));
const resolveCase = () => {
updateHandoff(false);
updateSession(Object.assign(Object.assign({}, webchatState.session), { _botonic_action: null }));
};
const prevSession = (0, hooks_1.usePrevious)(webchatState.session);
(0, react_1.useEffect)(() => {
// Resume conversation after handoff
if (prevSession &&
prevSession._botonic_action &&
!webchatState.session._botonic_action) {
const action = (0, exports.getParsedAction)(prevSession._botonic_action);
if (action && action.on_finish)
sendPayload(action.on_finish);
}
}, [webchatState.session._botonic_action]);
const sendText = async (text, payload) => {
if (!text)
return;
const input = { type: core_1.INPUT.TEXT, data: text, payload };
await sendInput(input);
};
const sendPayload = async (payload) => {
if (!payload)
return;
const input = { type: core_1.INPUT.POSTBACK, payload };
await sendInput(input);
};
const sendAttachment = async (attachment) => {
if (attachment.file) {
const attachmentType = (0, message_utils_1.getMediaType)(attachment.file.type);
if (!attachmentType)
return;
const input = {
type: attachmentType,
data: attachment.file,
};
await sendInput(input);
setCurrentAttachment(undefined);
}
};
const sendTextAreaText = () => {
sendText(textArea.current.value);
textArea.current.value = '';
};
let isTyping = false;
let typingTimeout = null;
function clearTimeoutWithReset(reset) {
const waitTime = 20 * 1000;
if (typingTimeout)
clearTimeout(typingTimeout);
if (reset)
typingTimeout = setTimeout(stopTyping, waitTime);
}
function startTyping() {
isTyping = true;
sendChatEvent('typing_on');
}
function stopTyping() {
clearTimeoutWithReset(false);
isTyping = false;
sendChatEvent('typing_off');
}
const onKeyDown = event => {
if (event.keyCode === 13 && event.shiftKey === false) {
event.preventDefault();
sendTextAreaText();
stopTyping();
}
};
const onKeyUp = () => {
if (textArea.current.value === '') {
stopTyping();
return;
}
if (!isTyping) {
startTyping();
}
clearTimeoutWithReset(true);
};
const webviewRequestContext = {
getString: stringId => props.getString(stringId, webchatState.session),
setLocale: locale => props.getString(locale, webchatState.session),
session: webchatState.session || {},
params: webchatState.webviewParams || {},
closeWebview: closeWebview,
defaultDelay: props.defaultDelay || 0,
defaultTyping: props.defaultTyping || 0,
};
(0, react_1.useEffect)(() => {
if (firstUpdate.current) {
firstUpdate.current = false;
return;
}
if (webchatState.isWebchatOpen && props.onOpen)
props.onOpen();
if (!webchatState.isWebchatOpen && props.onClose && !firstUpdate.current) {
props.onClose();
toggleEmojiPicker(false);
togglePersistentMenu(false);
}
}, [webchatState.isWebchatOpen]);
const webchatMessageList = () => ((0, jsx_runtime_1.jsx)(message_list_1.WebchatMessageList, Object.assign({ style: { flex: 1 } }, { children: webchatState.typing && (0, jsx_runtime_1.jsx)(typing_indicator_1.TypingIndicator, {}) })));
const webchatReplies = () => (0, jsx_runtime_1.jsx)(replies_1.WebchatReplies, { replies: webchatState.replies });
const isUserInputEnabled = () => {
const isUserInputEnabled = getThemeProperty(constants_1.WEBCHAT.CUSTOM_PROPERTIES.enableUserInput, props.enableUserInput !== undefined ? props.enableUserInput : true);
return isUserInputEnabled && !webchatState.isCoverComponentOpen;
};
const userInputEnabled = isUserInputEnabled();
const textArea = (0, react_1.useRef)(null);
const userInputArea = () => {
return (userInputEnabled && ((0, jsx_runtime_1.jsxs)(UserInputContainer, Object.assign({ style: Object.assign({}, getThemeProperty(constants_1.WEBCHAT.CUSTOM_PROPERTIES.userInputStyle)), className: 'user-input-container' }, { children: [webchatState.isEmojiPickerOpen && ((0, jsx_runtime_1.jsx)(emoji_picker_1.OpenedEmojiPicker, { height: webchatState.theme.style.height, onEmojiClick: handleSelectedEmoji, onClick: handleEmojiClick })), (0, jsx_runtime_1.jsx)(persistent_menu_1.PersistentMenu, { onClick: handleMenu, persistentMenu: props.persistentMenu }), (0, jsx_runtime_1.jsx)(TextAreaContainer, { children: (0, jsx_runtime_1.jsx)(react_textarea_autosize_1.default, { inputRef: textArea, name: 'text', onFocus: () => deviceAdapter.onFocus(host), onBlur: () => deviceAdapter.onBlur(), maxRows: 4, wrap: 'soft', maxLength: '1000', placeholder: getThemeProperty(constants_1.WEBCHAT.CUSTOM_PROPERTIES.textPlaceholder, constants_1.WEBCHAT.DEFAULTS.PLACEHOLDER), autoFocus: true, onKeyDown: e => onKeyDown(e), onKeyUp: onKeyUp, style: Object.assign({ display: 'flex', fontSize: deviceAdapter.fontSize(14), width: '100%', border: 'none', resize: 'none', overflow: 'auto', outline: 'none', flex: '1 1 auto', padding: 10, paddingLeft: persistentMenuOptions ? 0 : 10, fontFamily: 'inherit' }, getThemeProperty(constants_1.WEBCHAT.CUSTOM_PROPERTIES.userInputBoxStyle)) }) }), (0, jsx_runtime_1.jsx)(emoji_picker_1.EmojiPicker, { enableEmojiPicker: props.enableEmojiPicker, onClick: handleEmojiClick }), (0, jsx_runtime_1.jsx)(attachment_1.Attachment, { enableAttachments: props.enableAttachments, onChange: handleAttachment, accept: (0, message_utils_1.getFullMimeWhitelist)().join(',') }), (0, jsx_runtime_1.jsx)(send_button_1.SendButton, { onClick: sendTextAreaText })] }))));
};
const webchatWebview = () => ((0, jsx_runtime_1.jsx)(contexts_1.RequestContext.Provider, Object.assign({ value: webviewRequestContext }, { children: (0, jsx_runtime_1.jsx)(webview_1.WebviewContainer, { style: Object.assign(Object.assign({}, getThemeProperty(constants_1.WEBCHAT.CUSTOM_PROPERTIES.webviewStyle)), mobileStyle), webview: webchatState.webview }) })));
let mobileStyle = {};
if ((0, core_1.isMobile)(getThemeProperty(constants_1.WEBCHAT.CUSTOM_PROPERTIES.mobileBreakpoint))) {
mobileStyle = getThemeProperty(constants_1.WEBCHAT.CUSTOM_PROPERTIES.mobileStyle) || {
width: '100%',
height: '100%',
right: 0,
bottom: 0,
borderRadius: 0,
};
}
(0, react_1.useEffect)(() => {
// Prod mode
saveWebchatState(webchatState);
(0, dom_1.scrollToBottom)({ host });
}, [webchatState.themeUpdates]);
// Only needed for dev/serve mode
const updateWebchatDevSettings = settings => {
// eslint-disable-next-line react-hooks/rules-of-hooks
(0, react_1.useEffect)(() => {
const themeUpdates = (0, webchat_settings_1.normalizeWebchatSettings)(settings);
updateTheme((0, lodash_merge_1.default)(webchatState.theme, themeUpdates), themeUpdates);
}, [webchatState.messagesJSON]);
};
const DarkenBackground = ({ component }) => {
return ((0, jsx_runtime_1.jsxs)("div", { children: [darkBackgroundMenu && ((0, jsx_runtime_1.jsx)(DarkBackgroundMenu, { style: {
borderRadius: webchatState.theme.style.borderRadius,
} })), component] }));
};
const _renderCustomComponent = () => {
if (!customComponent)
return (0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, {});
else
return customComponent;
};
const WebchatComponent = ((0, jsx_runtime_1.jsxs)(contexts_1.WebchatContext.Provider, Object.assign({ value: {
addMessage,
getThemeProperty,
openWebview,
resolveCase,
sendAttachment,
sendInput,
sendPayload,
sendText,
toggleWebchat,
updateLatestInput,
updateMessage,
updateReplies,
updateUser: updateSessionWithUser,
updateWebchatDevSettings: updateWebchatDevSettings,
webchatState,
} }, { children: [!webchatState.isWebchatOpen && (0, jsx_runtime_1.jsx)(trigger_button_1.TriggerButton, {}), webchatState.isWebchatOpen && ((0, jsx_runtime_1.jsxs)(StyledWebchat
// TODO: Distinguis between multiple instances of webchat, e.g. `${uniqueId}-botonic-webchat`
, Object.assign({
// TODO: Distinguis between multiple instances of webchat, e.g. `${uniqueId}-botonic-webchat`
role: constants_1.ROLES.WEBCHAT, id: constants_1.WEBCHAT.DEFAULTS.ID, width: webchatState.width, height: webchatState.height, style: Object.assign(Object.assign({}, webchatState.theme.style), mobileStyle) }, { children: [(0, jsx_runtime_1.jsx)(header_1.StyledWebchatHeader, { onCloseClick: () => {
toggleWebchat(false);
} }), webchatState.error.message && ((0, jsx_runtime_1.jsx)(ErrorMessageContainer, { children: (0, jsx_runtime_1.jsx)(ErrorMessage, { children: webchatState.error.message }) })), webchatMessageList(), webchatState.replies &&
Object.keys(webchatState.replies).length > 0 &&
webchatReplies(), webchatState.isPersistentMenuOpen && ((0, jsx_runtime_1.jsx)(DarkenBackground, { component: persistentMenu() })), !webchatState.handoff && userInputArea(), webchatState.webview && webchatWebview(), webchatState.isCoverComponentOpen && coverComponent(), webchatState.isCustomComponentRendered &&
customComponent &&
_renderCustomComponent()] })))] })));
return props.shadowDOM ? ((0, jsx_runtime_1.jsx)(styled_components_1.StyleSheetManager, Object.assign({ target: host }, { children: WebchatComponent }))) : (WebchatComponent);
});
//# sourceMappingURL=webchat.js.map