UNPKG

@botonic/react

Version:

Build Chatbots using React

297 lines 13.3 kB
import { __awaiter, __rest } from "tslib"; import { jsx as _jsx } from "react/jsx-runtime"; import { HubtypeService, INPUT } from '@botonic/core'; import merge from 'lodash.merge'; import React, { createRef } from 'react'; import { render, unmountComponentAtNode } from 'react-dom'; import { WEBCHAT } from './constants'; import { SENDERS } from './index-types'; import { msgToBotonic } from './msg-to-botonic'; import { isShadowDOMSupported, onDOMLoaded } from './util/dom'; import { Webchat } from './webchat/webchat'; export class WebchatApp { constructor({ theme = {}, persistentMenu, coverComponent, blockInputs, enableEmojiPicker, enableAttachments, enableUserInput, enableAnimations, hostId, shadowDOM, defaultDelay, defaultTyping, storage, storageKey, onInit, onOpen, onClose, onMessage, onTrackEvent, 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 && !isShadowDOMSupported()) { console.warn('[botonic] ShadowDOM not supported on this browser'); this.shadowDOM = false; } this.hostId = hostId || WEBCHAT.DEFAULTS.HOST_ID; this.defaultDelay = defaultDelay; this.defaultTyping = defaultTyping; this.storage = storage === undefined ? localStorage : storage; this.storageKey = storageKey || WEBCHAT.DEFAULTS.STORAGE_KEY; this.onInit = onInit; this.onOpen = onOpen; this.onClose = onClose; this.onMessage = onMessage; this.onTrackEvent = onTrackEvent; this.onConnectionChange = onConnectionChange; this.visibility = visibility; this.server = server; this.webchatRef = 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); } onUserInput({ user, input }) { return __awaiter(this, void 0, void 0, function* () { this.onMessage && this.onMessage(this, { sentBy: SENDERS.user, message: input, isUnread: false, }); return this.hubtypeService.postMessage(user, input); }); } onConnectionRegained() { return __awaiter(this, void 0, void 0, function* () { 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 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) { var _a, _b; 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 (((_a = event.message) === null || _a === void 0 ? void 0 : _a.type) === 'update_webchat_settings') { this.updateWebchatSettings(event.message.data); } else if (((_b = event.message) === null || _b === void 0 ? void 0 : _b.type) === 'sender_action') { this.setTyping(event.message.data === 'typing_on'); } else { this.onMessage && this.onMessage(this, { sentBy: SENDERS.bot, message: event.message }); this.addBotMessage(event.message); } } updateUser(user) { this.webchatRef.current.updateUser(user); } addBotMessage(message) { var _a, _b; message.ack = 0; message.isUnread = true; message.sentBy = (_a = message.sent_by) === null || _a === void 0 ? void 0 : _a.split('message_sent_by_')[1]; delete message.sent_by; const response = msgToBotonic(message, ((_b = this.theme.message) === null || _b === void 0 ? void 0 : _b.customTypes) || this.theme.customMessageTypes); this.webchatRef.current.addBotResponse({ response, }); } addBotText(text) { this.addBotMessage({ type: INPUT.TEXT, data: text }); } addUserMessage(message) { this.webchatRef.current.addUserMessage(message); } addUserText(text) { this.addUserMessage({ type: INPUT.TEXT, data: text }); } addUserPayload(payload) { this.addUserMessage({ type: INPUT.POSTBACK, payload }); } setTyping(typing) { this.webchatRef.current.setTyping(typing); } open() { this.webchatRef.current.openWebchat(); } close() { this.webchatRef.current.closeWebchat(); } closeWebview() { this.webchatRef.current.closeWebview(); } 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(); } getVisibility() { return __awaiter(this, void 0, void 0, function* () { 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, onTrackEvent, appId, visibility, server, hostId } = optionsAtRuntime, webchatOptions = __rest(optionsAtRuntime, ["theme", "persistentMenu", "coverComponent", "blockInputs", "enableAttachments", "enableUserInput", "enableAnimations", "enableEmojiPicker", "defaultDelay", "defaultTyping", "storage", "storageKey", "onInit", "onOpen", "onClose", "onMessage", "onConnectionChange", "onTrackEvent", "appId", "visibility", "server", "hostId"]); theme = merge(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.onTrackEvent = onTrackEvent || this.onTrackEvent; this.onConnectionChange = onConnectionChange || this.onConnectionChange; this.visibility = visibility || this.visibility; this.appId = appId || this.appId; this.hostId = hostId || this.hostId; this.createRootElement(host); return (_jsx(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), onTrackEvent: (...args) => this.onTrackEvent(...args), server: server }))); } isWebchatVisible({ appId }) { return __awaiter(this, void 0, void 0, function* () { try { const { status } = yield HubtypeService.getWebchatVisibility({ appId, }); return status === 200; } catch (e) { return false; } }); } isOnline() { return this.webchatRef.current.isOnline(); } resolveWebchatVisibility(optionsAtRuntime) { return __awaiter(this, void 0, void 0, function* () { 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' && (yield this.isWebchatVisible({ appId }))) return true; return false; }); } destroy() { if (this.hubtypeService) this.hubtypeService.destroyPusher(); unmountComponentAtNode(this.host); if (this.storage) this.storage.removeItem(this.storageKey); } render(dest, optionsAtRuntime = {}) { return __awaiter(this, void 0, void 0, function* () { onDOMLoaded(() => __awaiter(this, void 0, void 0, function* () { const isVisible = yield this.resolveWebchatVisibility(optionsAtRuntime); if (isVisible) render(this.getComponent(dest, optionsAtRuntime), this.getReactMountNode(dest)); })); }); } } //# sourceMappingURL=webchat-app.js.map