@botonic/react
Version:
Build Chatbots using React
271 lines • 12.4 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.WebchatApp = void 0;
const tslib_1 = require("tslib");
const jsx_runtime_1 = require("react/jsx-runtime");
const core_1 = require("@botonic/core");
const legacy_types_1 = require("@botonic/core/lib/esm/models/legacy-types");
const lodash_merge_1 = tslib_1.__importDefault(require("lodash.merge"));
const react_1 = tslib_1.__importStar(require("react"));
const react_dom_1 = require("react-dom");
const constants_1 = require("./constants");
const msg_to_botonic_1 = require("./msg-to-botonic");
const dom_1 = require("./util/dom");
const webchat_1 = require("./webchat/webchat");
class WebchatApp {
constructor({ theme = {}, persistentMenu, coverComponent, blockInputs, enableEmojiPicker, enableAttachments, enableUserInput, enableAnimations, hostId, shadowDOM, defaultDelay, defaultTyping, storage, storageKey, onInit, onOpen, onClose, onMessage, onConnectionChange, appId, visibility, server, }) {
this.theme = theme;
this.persistentMenu = persistentMenu;
this.coverComponent = coverComponent;
this.blockInputs = blockInputs;
this.enableEmojiPicker = enableEmojiPicker;
this.enableAttachments = enableAttachments;
this.enableUserInput = enableUserInput;
this.enableAnimations = enableAnimations;
this.shadowDOM = Boolean(typeof shadowDOM === 'function' ? shadowDOM() : shadowDOM);
if (this.shadowDOM && !(0, dom_1.isShadowDOMSupported)()) {
console.warn('[botonic] ShadowDOM not supported on this browser');
this.shadowDOM = false;
}
this.hostId = hostId || constants_1.WEBCHAT.DEFAULTS.HOST_ID;
this.defaultDelay = defaultDelay;
this.defaultTyping = defaultTyping;
this.storage = storage === undefined ? localStorage : storage;
this.storageKey = storageKey || constants_1.WEBCHAT.DEFAULTS.STORAGE_KEY;
this.onInit = onInit;
this.onOpen = onOpen;
this.onClose = onClose;
this.onMessage = onMessage;
this.onConnectionChange = onConnectionChange;
this.visibility = visibility;
this.server = server;
this.webchatRef = (0, react_1.createRef)();
this.appId = appId;
}
createRootElement(host) {
// Create root element <div id='root'> if not exists
// Create shadowDOM to root element if needed
if (host) {
if (host.id && this.hostId) {
if (host.id != this.hostId) {
console.warn(`[botonic] Host ID "${host.id}" don't match 'hostId' option: ${this.hostId}. Using value: ${host.id}.`);
this.hostId = host.id;
}
}
else if (host.id)
this.hostId = host.id;
else if (this.hostId)
host.id = this.hostId;
}
else {
host = document.getElementById(this.hostId);
}
if (!host) {
host = document.createElement('div');
host.id = this.hostId;
if (document.body.firstChild)
document.body.insertBefore(host, document.body.firstChild);
else
document.body.appendChild(host);
}
this.host = this.shadowDOM ? host.attachShadow({ mode: 'open' }) : host;
}
getReactMountNode(node) {
if (!node)
node = this.host;
return node.shadowRoot ? node.shadowRoot : node;
}
onInitWebchat(...args) {
this.onInit && this.onInit(this, ...args);
}
onOpenWebchat(...args) {
this.onOpen && this.onOpen(this, ...args);
}
onCloseWebchat(...args) {
this.onClose && this.onClose(this, ...args);
}
async onUserInput({ user, input }) {
this.onMessage &&
this.onMessage(this, { from: constants_1.SENDERS.user, message: input });
return this.hubtypeService.postMessage(user, input);
}
async onConnectionRegained() {
return this.hubtypeService.onConnectionRegained();
}
onStateChange({ session: { user }, messagesJSON }) {
const lastMessage = messagesJSON[messagesJSON.length - 1];
const lastMessageId = lastMessage && lastMessage.id;
const lastMessageUpdateDate = this.getLastMessageUpdate();
if (this.hubtypeService) {
this.hubtypeService.lastMessageId = lastMessageId;
this.hubtypeService.lastMessageUpdateDate = lastMessageUpdateDate;
}
else if (!this.hubtypeService && user) {
this.hubtypeService = new core_1.HubtypeService({
appId: this.appId,
user,
lastMessageId,
lastMessageUpdateDate,
onEvent: event => this.onServiceEvent(event),
unsentInputs: () => this.webchatRef.current
.getMessages()
.filter(msg => msg.ack === 0 && msg.unsentInput),
server: this.server,
});
}
}
onServiceEvent(event) {
if (event.action === 'connectionChange') {
this.onConnectionChange && this.onConnectionChange(this, event.online);
this.webchatRef.current.setOnline(event.online);
}
else if (event.action === 'update_message_info')
this.updateMessageInfo(event.message.id, event.message);
else if (event.message.type === 'update_webchat_settings')
this.updateWebchatSettings(event.message.data);
else if (event.message.type === 'sender_action')
this.setTyping(event.message.data === 'typing_on');
else {
this.onMessage &&
this.onMessage(this, { from: constants_1.SENDERS.bot, message: event.message });
this.addBotMessage(event.message);
}
}
updateUser(user) {
this.webchatRef.current.updateUser(user);
}
addBotMessage(message) {
this.webchatRef.current.addBotResponse({
response: (0, msg_to_botonic_1.msgToBotonic)(message, (this.theme.message && this.theme.message.customTypes) ||
this.theme.customMessageTypes),
});
}
addBotText(text) {
this.addBotMessage({ type: legacy_types_1.INPUT.TEXT, data: text });
}
addUserMessage(message) {
this.webchatRef.current.addUserMessage(message);
}
addUserText(text) {
this.webchatRef.current.addUserMessage({ type: legacy_types_1.INPUT.TEXT, data: text });
}
addUserPayload(payload) {
this.webchatRef.current.addUserMessage({ type: legacy_types_1.INPUT.POSTBACK, payload });
}
setTyping(typing) {
this.webchatRef.current.setTyping(typing);
}
open() {
this.webchatRef.current.openWebchat();
}
close() {
this.webchatRef.current.closeWebchat();
}
toggle() {
this.webchatRef.current.toggleWebchat();
}
openCoverComponent() {
this.webchatRef.current.openCoverComponent();
}
closeCoverComponent() {
this.webchatRef.current.closeCoverComponent();
}
renderCustomComponent(_customComponent) {
this.webchatRef.current.renderCustomComponent(_customComponent);
}
unmountCustomComponent() {
this.webchatRef.current.unmountCustomComponent();
}
toggleCoverComponent() {
this.webchatRef.current.toggleCoverComponent();
}
getMessages() {
return this.webchatRef.current.getMessages();
}
clearMessages() {
this.webchatRef.current.clearMessages();
}
async getVisibility() {
return this.resolveWebchatVisibility({
appId: this.appId,
visibility: this.visibility,
});
}
getLastMessageUpdate() {
return this.webchatRef.current.getLastMessageUpdate();
}
updateMessageInfo(msgId, messageInfo) {
return this.webchatRef.current.updateMessageInfo(msgId, messageInfo);
}
updateWebchatSettings(settings) {
return this.webchatRef.current.updateWebchatSettings(settings);
}
// eslint-disable-next-line complexity
getComponent(host, optionsAtRuntime = {}) {
let { theme = {}, persistentMenu, coverComponent, blockInputs, enableAttachments, enableUserInput, enableAnimations, enableEmojiPicker, defaultDelay, defaultTyping, storage, storageKey, onInit, onOpen, onClose, onMessage, onConnectionChange, appId, visibility, server, hostId } = optionsAtRuntime, webchatOptions = tslib_1.__rest(optionsAtRuntime, ["theme", "persistentMenu", "coverComponent", "blockInputs", "enableAttachments", "enableUserInput", "enableAnimations", "enableEmojiPicker", "defaultDelay", "defaultTyping", "storage", "storageKey", "onInit", "onOpen", "onClose", "onMessage", "onConnectionChange", "appId", "visibility", "server", "hostId"]);
theme = (0, lodash_merge_1.default)(this.theme, theme);
persistentMenu = persistentMenu || this.persistentMenu;
coverComponent = coverComponent || this.coverComponent;
blockInputs = blockInputs || this.blockInputs;
enableEmojiPicker = enableEmojiPicker || this.enableEmojiPicker;
enableAttachments = enableAttachments || this.enableAttachments;
enableUserInput = enableUserInput || this.enableUserInput;
enableAnimations = enableAnimations || this.enableAnimations;
defaultDelay = defaultDelay || this.defaultDelay;
defaultTyping = defaultTyping || this.defaultTyping;
server = server || this.server;
this.storage = storage || this.storage;
this.storageKey = storageKey || this.storageKey;
this.onInit = onInit || this.onInit;
this.onOpen = onOpen || this.onOpen;
this.onClose = onClose || this.onClose;
this.onMessage = onMessage || this.onMessage;
this.onConnectionChange = onConnectionChange || this.onConnectionChange;
this.visibility = visibility || this.visibility;
this.appId = appId || this.appId;
this.hostId = hostId || this.hostId;
this.createRootElement(host);
return ((0, jsx_runtime_1.jsx)(webchat_1.Webchat, Object.assign({}, webchatOptions, { ref: this.webchatRef, host: this.host, shadowDOM: this.shadowDOM, theme: theme, persistentMenu: persistentMenu, coverComponent: coverComponent, blockInputs: blockInputs, enableEmojiPicker: enableEmojiPicker, enableAttachments: enableAttachments, enableUserInput: enableUserInput, enableAnimations: enableAnimations, storage: this.storage, storageKey: this.storageKey, defaultDelay: defaultDelay, defaultTyping: defaultTyping, onInit: (...args) => this.onInitWebchat(...args), onOpen: (...args) => this.onOpenWebchat(...args), onClose: (...args) => this.onCloseWebchat(...args), onUserInput: (...args) => this.onUserInput(...args), onStateChange: webchatState => this.onStateChange(webchatState), server: server })));
}
async isWebchatVisible({ appId }) {
try {
const { status } = await core_1.HubtypeService.getWebchatVisibility({
appId,
});
return status === 200;
}
catch (e) {
return false;
}
}
isOnline() {
return this.webchatRef.current.isOnline();
}
async resolveWebchatVisibility(optionsAtRuntime) {
let { appId, visibility } = optionsAtRuntime;
visibility = visibility || this.visibility;
if (visibility === undefined || visibility === true)
return true;
if (typeof visibility === 'function' && visibility())
return true;
if (visibility === 'dynamic' && (await this.isWebchatVisible({ appId })))
return true;
return false;
}
destroy() {
if (this.hubtypeService)
this.hubtypeService.destroyPusher();
(0, react_dom_1.unmountComponentAtNode)(this.host);
if (this.storage)
this.storage.removeItem(this.storageKey);
}
async render(dest, optionsAtRuntime = {}) {
(0, dom_1.onDOMLoaded)(async () => {
const isVisible = await this.resolveWebchatVisibility(optionsAtRuntime);
if (isVisible)
(0, react_dom_1.render)(this.getComponent(dest, optionsAtRuntime), this.getReactMountNode(dest));
});
}
}
exports.WebchatApp = WebchatApp;
//# sourceMappingURL=webchat-app.js.map