@gameon/web
Version:
Chat clients for web
899 lines (890 loc) • 37.9 kB
JavaScript
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
import { onChatCardContext, } from '@gameon/on-ui-components/chat/card/context';
import { onChatCarouselContext, } from '@gameon/on-ui-components/chat/carousel/context';
import { onChatInputContext, } from '@gameon/on-ui-components/chat/input/context';
import { onChatMessageContext, } from '@gameon/on-ui-components/chat/message/context';
import '@gameon/on-ui-components/chat/widget';
import '@gameon/on-ui-components/chat/window';
import '@gameon/on-ui-components/chat/notification';
import { ContextProvider } from '@lit-labs/context';
import { css, html, LitElement, nothing } from 'lit';
import { customElement, property, query, state } from 'lit/decorators.js';
import { classMap } from 'lit/directives/class-map.js';
import { v4 as uuidv4 } from 'uuid';
import { notificationsContext } from '../notifications/notifications.context';
import { Breakpoint, getCurrentBreakpoint } from './breakpoints';
import { prodConfig as firebaseProdConfig, stgConfig as firebaseStgConfig, } from './firebase/firebase-config';
import { FirebaseInstance } from './firebase/firebase-instance';
import '@lottiefiles/lottie-player';
import '../notifications/notifications';
import '@gameon/on-ui-components/base/button';
const USER_STORAGE_KEY = 'ON_CHAT_BOT_CLIENT_USER_ID';
const CONVERSATION_STORAGE_KEY = 'ON_CHAT_BOT_CLIENT_CONVERSATION_ID';
const STG_WEB_CHANNEL_API_URL = 'https://web-channel.services.stg.tuul.com';
const PROD_WEB_CHANNEL_API_URL = 'https://web-channel.services.tuul.com';
const DEFAULT_HISTORY_LIMIT = 100;
const OPENED_DESKTOP_STORAGE_KEY = 'ON_CHAT_BOT_CLIENT_HAS_OPENED_DESKTOP';
const OPENED_MOBILE_STORAGE_KEY = 'ON_CHAT_BOT_CLIENT_HAS_OPENED_MOBILE';
const SURFACE_BACKDROP_Z_INDEX = 999;
const SURFACE_INPUT_Z_INDEX = 2000;
const SURFACE_WINDOW_CLOSE_BUTTON_Z_INDEX = 1001;
const SURFACE_WINDOW_Z_INDEX = 1000;
export var Environment;
(function (Environment) {
Environment["PRODUCTION"] = "PRODUCTION";
Environment["STAGING"] = "STAGING";
Environment["LOCAL"] = "LOCAL";
})(Environment || (Environment = {}));
export var DisplayMode;
(function (DisplayMode) {
DisplayMode["FULL_SCREEN"] = "FULL_SCREEN";
DisplayMode["SURFACE"] = "SURFACE";
DisplayMode["WIDGET"] = "WIDGET";
DisplayMode["WIDGET_WITHOUT_BUTTON"] = "WIDGET_WITHOUT_BUTTON";
})(DisplayMode || (DisplayMode = {}));
export var OnSearchParams;
(function (OnSearchParams) {
OnSearchParams["INITIAL_PROMPT"] = "on_initial_prompt";
OnSearchParams["SHOULD_AUTO_OPEN"] = "on_should_auto_open";
OnSearchParams["SHOULD_AUTO_OPEN_MOBILE"] = "on_should_auto_open_mobile";
})(OnSearchParams || (OnSearchParams = {}));
export var WidgetVisibility;
(function (WidgetVisibility) {
WidgetVisibility["HIDDEN"] = "hidden";
WidgetVisibility["VISIBLE"] = "visible";
})(WidgetVisibility || (WidgetVisibility = {}));
let OnChatBotClient = class OnChatBotClient extends LitElement {
constructor() {
super(...arguments);
this.clientId = '';
this.debug = false;
this.messageHistoryLimit = DEFAULT_HISTORY_LIMIT;
this.displayMode = DisplayMode.FULL_SCREEN;
this.env = Environment.PRODUCTION;
this.isSurfaceChatOpen = false;
this.persistMessagesAcrossSessions = false;
this.shouldAutoOpen = false;
this.shouldAutoOpenMobile = false;
this.customStyles = new Map();
this.messages = [];
this.speakers = [];
this.surfaceChatInputValue = '';
this.userId = '';
this.usersTyping = new Set();
this.webChannelParticipants = [];
this.lastSeenMessageProvider = new ContextProvider(this, notificationsContext, { lastSeenMessageTimestamp: undefined, unreadMessages: [] });
this.onChatCardContextProvider = new ContextProvider(this, onChatCardContext, { linkTarget: '_blank' });
this.onChatCarouselContextProvider = new ContextProvider(this, onChatCarouselContext, { renderButtons: true });
this.onChatInputContextProvider = new ContextProvider(this, onChatInputContext, {
enableVoice: false,
placeholder: 'Aa',
sendIcon: 'send',
voiceIcon: 'microphone-01',
});
this.onChatMessageContextProvider = new ContextProvider(this, onChatMessageContext, { stackQuickReplies: true });
}
get webChannelApiBaseUrl() {
switch (this.env) {
case Environment.LOCAL:
return '';
case Environment.STAGING:
return STG_WEB_CHANNEL_API_URL;
}
return PROD_WEB_CHANNEL_API_URL;
}
get firebaseConfig() {
switch (this.env) {
case Environment.LOCAL:
case Environment.STAGING:
return firebaseStgConfig;
}
return firebaseProdConfig;
}
open() {
if (this.onChatWidgetEl) {
this.onChatWidgetEl.isOpen = true;
this.connectToFirestore();
this.resetLastSeenMessage();
}
}
close() {
if (this.onChatWidgetEl) {
this.onChatWidgetEl.isOpen = false;
}
}
toggle() {
if (this.onChatWidgetEl && this.onChatWidgetEl.isOpen) {
this.close();
}
else {
this.open();
}
}
getConversationId(clientId, userId) {
const store = this.persistMessagesAcrossSessions
? window.localStorage
: window.sessionStorage;
let conversationId = store.getItem(`${CONVERSATION_STORAGE_KEY}_${clientId}_${userId}`);
// if there is no conversation id in storage, generate a new one and store it
if (!conversationId) {
conversationId = uuidv4();
this.setConversationId(conversationId, clientId, userId);
}
return conversationId;
}
setConversationId(conversationId, clientId, userId) {
const store = this.persistMessagesAcrossSessions
? window.localStorage
: window.sessionStorage;
store.setItem(`${CONVERSATION_STORAGE_KEY}_${clientId}_${userId}`, conversationId);
}
getWebChannelBotId() {
var _a, _b;
return ((_b = (_a = this.webChannelParticipants.find((p) => p.type === 'BOT')) === null || _a === void 0 ? void 0 : _a.userId) !== null && _b !== void 0 ? _b : '');
}
willUpdate(changedProperties) {
// Compute speakers
if (changedProperties.has('botAvatarUrl') ||
changedProperties.has('webChannelParticipants')) {
this.speakers = [];
// for each participant, add a speaker
this.webChannelParticipants.forEach((participant) => {
switch (participant.type) {
case 'BOT':
this.speakers.push({
avatarUrl: this.botAvatarUrl,
id: participant.userId,
});
break;
case 'USER':
this.speakers.push({ id: participant.userId });
break;
}
});
}
// Load bot details
if (changedProperties.has('clientId') && this.clientId) {
this.loadBotConfig(this.clientId).then((config) => {
this.configureClient(config);
if (this.displayMode === DisplayMode.FULL_SCREEN ||
this.displayMode === DisplayMode.SURFACE ||
this.shouldAutoOpen ||
this.shouldAutoOpenMobile) {
this.connectToFirestore();
}
});
}
}
getBotMessages() {
return this.messages.filter((message) => message.speakerId === this.getWebChannelBotId());
}
resetLastSeenMessage() {
const lastBotMessage = this.getBotMessages().at(-1);
this.lastSeenMessageProvider.setValue({
lastSeenMessageTimestamp: lastBotMessage === null || lastBotMessage === void 0 ? void 0 : lastBotMessage.timestamp,
unreadMessages: [],
});
}
firstUpdated() {
const storedUserId = this.fetchStoredUserId();
this.userId = storedUserId || uuidv4();
this.storeUserId(this.userId);
this.addEventListener('on-chat-widget-open', this.connectToFirestore.bind(this), { once: true });
const params = new URLSearchParams(window.location.search);
if (!this.initialPrompt) {
const initialPromptParam = params.get(OnSearchParams.INITIAL_PROMPT);
this.initialPrompt = initialPromptParam !== null && initialPromptParam !== void 0 ? initialPromptParam : undefined;
}
window.addEventListener('on-chat-widget-open', () => {
this.resetLastSeenMessage();
});
}
handleLottieLoad(event) {
// Update the lottie-player aspect-ratio style property dynamically; Needed to tell Safari how to handle resizing the player based on height.
const player = event.currentTarget;
const svgElement = player.shadowRoot.querySelector('svg');
if (svgElement) {
const aspectRatio = svgElement.viewBox.baseVal.width / svgElement.viewBox.baseVal.height;
player.style.aspectRatio = `${aspectRatio}`;
}
}
async configureClient(config) {
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;
this.botAvatarUrl = config.avatar;
this.botId = this.clientId;
this.botName = config.title;
this.startingContent = config.startingContent;
this.widgetVisibility = config.widgetVisibility;
this.customStyles = this.computeCustomStyles(config);
if ((_b = (_a = config.renderSettings) === null || _a === void 0 ? void 0 : _a.compatibility) === null || _b === void 0 ? void 0 : _b['link-target-mode']) {
this.onChatCardContextProvider.setValue({
linkTarget: config.renderSettings.compatibility['link-target-mode'],
});
}
if (((_d = (_c = config.renderSettings) === null || _c === void 0 ? void 0 : _c.compatibility) === null || _d === void 0 ? void 0 : _d['render-carousel-buttons']) !==
undefined) {
this.onChatCarouselContextProvider.setValue({
renderButtons: config.renderSettings.compatibility['render-carousel-buttons'],
});
}
if (((_e = config.renderSettings) === null || _e === void 0 ? void 0 : _e.compatibility['chat-input-enable-voice']) ||
((_g = (_f = config.renderSettings) === null || _f === void 0 ? void 0 : _f.compatibility) === null || _g === void 0 ? void 0 : _g['chat-input-placeholder']) ||
((_h = config.renderSettings) === null || _h === void 0 ? void 0 : _h.compatibility['chat-input-send-icon']) ||
((_j = config.renderSettings) === null || _j === void 0 ? void 0 : _j.compatibility['chat-input-voice-icon'])) {
this.onChatInputContextProvider.setValue({
enableVoice: (_k = config.renderSettings.compatibility['chat-input-enable-voice']) !== null && _k !== void 0 ? _k : false,
placeholder: (_l = config.renderSettings.compatibility['chat-input-placeholder']) !== null && _l !== void 0 ? _l : 'Aa',
sendIcon: (_m = config.renderSettings.compatibility['chat-input-send-icon']) !== null && _m !== void 0 ? _m : 'send',
voiceIcon: (_o = config.renderSettings.compatibility['chat-input-voice-icon']) !== null && _o !== void 0 ? _o : 'microphone-01',
});
}
if (((_q = (_p = config.renderSettings) === null || _p === void 0 ? void 0 : _p.compatibility) === null || _q === void 0 ? void 0 : _q['stack-quick-replies']) !==
undefined) {
this.onChatMessageContextProvider.setValue({
stackQuickReplies: (_r = config.renderSettings) === null || _r === void 0 ? void 0 : _r.compatibility['stack-quick-replies'],
});
}
if ((_t = (_s = config.renderSettings) === null || _s === void 0 ? void 0 : _s.compatibility) === null || _t === void 0 ? void 0 : _t['custom-close-button-image']) {
this.chatCloseImageUrl =
config.renderSettings.compatibility['custom-close-button-image'];
}
if ((_v = (_u = config.renderSettings) === null || _u === void 0 ? void 0 : _u.compatibility) === null || _v === void 0 ? void 0 : _v['custom-open-button-image']) {
this.chatOpenImageUrl =
config.renderSettings.compatibility['custom-open-button-image'];
}
if ((_x = (_w = config.renderSettings) === null || _w === void 0 ? void 0 : _w.compatibility) === null || _x === void 0 ? void 0 : _x['custom-stylesheets']) {
const customStylesheetUrls = (_z = (_y = config.renderSettings) === null || _y === void 0 ? void 0 : _y.compatibility) === null || _z === void 0 ? void 0 : _z['custom-stylesheets'];
customStylesheetUrls.forEach((stylesheetUrl) => {
const link = document.createElement('link');
link.type = 'text/css';
link.rel = 'stylesheet';
link.href = stylesheetUrl;
document.head.appendChild(link);
});
}
// Auto open the widget
this.updateComplete.then(() => {
const params = new URLSearchParams(window.location.search);
const shouldAutoOpenParam = params.has(OnSearchParams.SHOULD_AUTO_OPEN);
const shouldAutoOpenMobileParam = params.has(OnSearchParams.SHOULD_AUTO_OPEN_MOBILE);
if (this.onChatWidgetEl) {
if (getCurrentBreakpoint() > Breakpoint.SMALL) {
this.onChatWidgetEl.isOpen =
(shouldAutoOpenParam || this.shouldAutoOpen) &&
!this.hasAutoOpenedThisSession(OPENED_DESKTOP_STORAGE_KEY);
}
else {
this.onChatWidgetEl.isOpen =
(shouldAutoOpenMobileParam || this.shouldAutoOpenMobile) &&
!this.hasAutoOpenedThisSession(OPENED_MOBILE_STORAGE_KEY);
}
if (this.onChatWidgetEl.isOpen === true) {
this.connectToFirestore();
}
}
});
}
updateMessages(documents) {
if (this.debug) {
console.log(' updateMessages() start');
}
// Gather all message events, with a valid content.
const messages = documents.filter((doc) => doc.eventData &&
doc.eventData.eventType === 'message' &&
doc.channelData &&
doc.channelData.content.length > 0);
// Gather all typing events.
const typingEvents = documents.filter((doc) => doc.eventData &&
(doc.eventData.eventType === 'typing_start' ||
doc.eventData.eventType === 'typing_end'));
// Compute the users that are currently typing.
this.usersTyping = typingEvents.reduce((usersTyping, currentEvent) => {
if (currentEvent.eventData.eventType === 'typing_start') {
usersTyping.add(currentEvent.channelData.user.id);
}
if (currentEvent.eventData.eventType === 'typing_end') {
usersTyping.delete(currentEvent.channelData.user.id);
}
return usersTyping;
}, new Set());
if (this.debug) {
console.log(' Messages filtered: ', messages);
console.log(' Typing events: ', typingEvents);
console.log(' Users typing: ', this.usersTyping);
}
// Find optimistic message.
const optimisticMessages = this.messages.filter((message) => message.isOptimistic);
if (this.debug) {
console.log(' Optimistic messages: ', optimisticMessages);
}
this.messages = messages.map((message) => ({
contents: message.channelData.content,
speakerId: message.channelData.user.id,
timestamp: message.timestamp,
}));
if (this.debug) {
console.log(' this.messages set: ', this.messages);
}
// If optimistic messages were found, add them back unless there's a
// message in the conversation with a later timestamp.
if (optimisticMessages.length > 0) {
const lastMessage = this.messages[this.messages.length - 1];
optimisticMessages.forEach((optimisticMessage) => {
if (!lastMessage ||
lastMessage.timestamp < optimisticMessage.timestamp) {
if (this.debug) {
console.log(' adding back optimistic message: ', optimisticMessage);
}
this.messages.push(optimisticMessage);
}
});
}
// Set the initial message timestamp to be the earliest message.
if (this.initialMessage) {
const firstMessage = messages[0];
if (firstMessage) {
this.initialMessage.timestamp = firstMessage.timestamp - 1;
}
}
// Insert the initial message again, and add user typing messages.
this.messages = [
...(this.initialMessage ? [this.initialMessage] : []),
...this.messages,
];
if (this.debug) {
console.log(' final this.messages state:', this.messages);
console.log(' updateMessages() end');
}
}
computeCustomStyles(config) {
var _a, _b, _c, _d, _e;
const customStyles = new Map();
if (!config.renderSettings) {
return customStyles;
}
// For backwards compaitibility, search for specific customizations by name
const colorPrimary = (_a = config.colors) === null || _a === void 0 ? void 0 : _a.primary;
const colorTitleFont = (_b = config.colors) === null || _b === void 0 ? void 0 : _b.titleFont;
const attachmentFit = (_c = config.renderSettings.attachments) === null || _c === void 0 ? void 0 : _c['--attachment-fit'];
const primaryButtonText = (_d = config.renderSettings.colors) === null || _d === void 0 ? void 0 : _d['--primary-button-text'];
const primaryMessageBg = (_e = config.renderSettings.colors) === null || _e === void 0 ? void 0 : _e['--primary-message-bg'];
if (colorPrimary) {
customStyles.set('--on-chat-widget-primary-color', colorPrimary);
customStyles.set('--on-linear-progress-active-indicator-color', colorPrimary);
}
if (colorTitleFont) {
customStyles.set('--on-chat-widget-text-on-primary-color', colorTitleFont);
}
if (attachmentFit) {
customStyles.set('--on-chat-card-image-fit', attachmentFit);
}
if (primaryButtonText) {
customStyles.set('--on-chat-input-button-color', primaryButtonText);
}
if (primaryMessageBg) {
customStyles.set('--on-chat-conversation-primary-background-color', primaryMessageBg);
}
// Add arbitrary customizations in the config
if (config.renderSettings.customStyles) {
Object.entries(config.renderSettings.customStyles).forEach((keyValuePair) => customStyles.set(keyValuePair[0], keyValuePair[1]));
}
return customStyles;
}
fetchStoredUserId() {
return window.localStorage.getItem(USER_STORAGE_KEY);
}
storeUserId(userId) {
window.localStorage.setItem(USER_STORAGE_KEY, userId);
}
async loadBotConfig(clientId) {
const response = await fetch(`${this.webChannelApiBaseUrl}/v1/config/${clientId}`);
if (response.ok) {
return await response.json();
}
else {
throw new Error(`A bot config failed to load for client ID: ${clientId}`);
}
}
pushNotifications() {
var _a;
if (this.debug) {
console.log('pushNotifications() start');
}
if ((_a = this.onChatWidgetEl) === null || _a === void 0 ? void 0 : _a.isOpen) {
this.resetLastSeenMessage();
}
else if (this.lastSeenMessageProvider.value.lastSeenMessageTimestamp) {
const botMessages = this.getBotMessages();
const lastBotMessage = botMessages.at(-1);
if (lastBotMessage &&
lastBotMessage.timestamp >
this.lastSeenMessageProvider.value.lastSeenMessageTimestamp) {
const unreadMessages = botMessages.filter((message) => {
var _a;
return message.timestamp >
((_a = this.lastSeenMessageProvider.value.lastSeenMessageTimestamp) !== null && _a !== void 0 ? _a : 0) &&
!message.contents.find((content) => content.text ===
'<on-chat-typing-indicator></on-chat-typing-indicator>');
});
this.lastSeenMessageProvider.setValue({
lastSeenMessageTimestamp: this.lastSeenMessageProvider.value.lastSeenMessageTimestamp,
unreadMessages: [...unreadMessages],
});
}
}
if (this.debug) {
console.log(' lastSeenMessageProvider.value: ', this.lastSeenMessageProvider.value);
console.log('pushNotifications() end');
}
}
async initializeConversation(userId, clientId, conversationId, baseURL) {
const response = await fetch(`${baseURL}/v1/initialize`, {
body: JSON.stringify({
userId: userId,
clientId: clientId,
conversationId: conversationId,
}),
headers: {
'Content-Type': 'application/json',
},
method: 'POST',
});
const result = await response.json();
this.setConversationId(result.conversation.id, clientId, userId);
return result;
}
async initializeFirestoreConversation(userId, clientId, conversationId, baseURL, startingContent) {
if (this.debug) {
console.log('initializeFirestoreConversation() start');
}
const resp = await this.initializeConversation(userId, clientId, conversationId, baseURL);
this.webChannelUserId = resp.conversation.userId;
this.webChannelParticipants = resp.conversation.participants;
this.initialMessage = {
contents: startingContent,
speakerId: this.getWebChannelBotId(),
timestamp: Date.now(),
};
const messageInitData = {
app: resp.conversation.app,
channel: resp.conversation.channel,
conversationId: resp.conversation.id,
};
let fb;
fb = new FirebaseInstance(this.firebaseConfig);
if (this.debug) {
console.log(' FirebaseInstance initialized: ', fb);
}
fb.listenToConvo(messageInitData, this.messageHistoryLimit, (snapshot) => {
if (this.debug) {
console.log('FirebaseInstance.listenToConvo() onSuccess() start');
console.log(' Got a new snapshot: ', snapshot);
}
const messagesData = snapshot.docs.map((doc) => doc.data()).reverse();
if (this.debug) {
console.log(' Snapshot docs processed: ', messagesData);
}
this.updateMessages(messagesData);
this.pushNotifications();
if (this.debug) {
console.log('FirebaseInstance.listenToConvo() onSuccess() end');
}
}, (error) => {
console.error('Firestore error', error);
});
if (this.initialPrompt) {
this.sendMessage(this.initialPrompt);
}
if (this.debug) {
console.log('initializeFirestoreConversation() end');
}
}
async sendMessage(text) {
var _a;
if (!this.clientId || !text.length) {
return;
}
const payload = JSON.stringify({
message: { text },
clientId: this.clientId,
userId: this.userId,
conversationId: this.getConversationId(this.clientId, this.userId),
});
const sentMessageResponse = await fetch(`${this.webChannelApiBaseUrl}/v1/message`, {
body: payload,
headers: {
'Content-Type': 'application/json',
},
method: 'POST',
});
const sentMessageMeta = await sentMessageResponse.json();
const message = {
contents: [{ text }],
speakerId: (_a = this.webChannelUserId) !== null && _a !== void 0 ? _a : '',
timestamp: sentMessageMeta.timestamp,
isOptimistic: true,
};
this.messages = [...this.messages, message];
// Fix the initial message timestamp if the sent message is behind the
// initial message.
if (this.initialMessage &&
this.initialMessage.timestamp > sentMessageMeta.timestamp) {
this.initialMessage.timestamp = sentMessageMeta.timestamp - 1;
}
this.dispatchEvent(new CustomEvent('on-client-send-message', {
bubbles: true,
composed: true,
detail: {
message: text,
},
}));
}
handleSurfaceChatCloseClick() {
this.isSurfaceChatOpen = false;
document.body.style.overflow = 'visible';
}
handleChatInputSubmit(e) {
if (!this.userId) {
return;
}
this.sendMessage(e.detail.value);
// Reset the input box and scroll to bottom
if (this.onChatWindowEl) {
this.onChatWindowEl.inputValue = '';
this.onChatWindowEl.scrollToBottom();
}
// Reset the input value
if (this.displayMode === DisplayMode.SURFACE) {
this.surfaceChatInputValue = '';
this.isSurfaceChatOpen = true;
document.body.style.overflow = 'hidden';
}
}
hasAutoOpenedThisSession(key) {
if (!window.sessionStorage.getItem(key)) {
// Set the session storage
window.sessionStorage.setItem(key, 'true');
return false;
}
// It has been opened this seesion so don't open it again
return true;
}
async connectToFirestore() {
var _a;
if (!this.webChannelUserId) {
if (this.debug) {
console.log('Connecting to Firestore');
}
this.initializeFirestoreConversation(this.userId, this.clientId, this.getConversationId(this.clientId, this.userId), this.webChannelApiBaseUrl, (_a = this.startingContent) !== null && _a !== void 0 ? _a : []);
}
}
renderChatWindow(shouldHideDisplayInputBar = false) {
var _a;
return html `
<on-chat-window
.conversationMessages="${this.messages}"
.conversationPrimarySpeakerId="${(_a = this.webChannelUserId) !== null && _a !== void 0 ? _a : ''}"
.conversationSpeakers="${this.speakers}"
?shouldDisplayLoadingIndicator="${this.usersTyping.size > 0}"
?shouldHideDisplayInputBar="${shouldHideDisplayInputBar}"
-chat-input-submit="${this.handleChatInputSubmit}"
-chat-message-quick-reply-click="${this.handleChatInputSubmit}"
></on-chat-window>
<style>
:host {
${Array.from(this.customStyles.entries()).map((keyValuePair) => `${keyValuePair[0]}: ${keyValuePair[1]};`)};
}
</style>
<on-button
class="surface-chat-window-close-button"
.icon="${'x'}"
.iconPlacement="${'only'}"
="${this.handleSurfaceChatCloseClick}"
></on-button>
`;
}
renderSurface() {
return html `
<div class="surface-backdrop"></div>
${this.renderChatWindow(true)}
<on-chat-input
class="surface-chat-input"
.value="${this.surfaceChatInputValue}"
-chat-input-change="${({ detail, }) => (this.surfaceChatInputValue = detail.value)}"
-chat-input-submit="${this.handleChatInputSubmit}"
></on-chat-input>
`;
}
renderChatNotifications() {
var _a;
if (((_a = this.onChatWidgetEl) === null || _a === void 0 ? void 0 : _a.isOpen) || !this.lastSeenMessageProvider.value)
return nothing;
const handleNotificationOpenWidget = () => {
if (this.onChatWidgetEl) {
this.onChatWidgetEl.isOpen = true;
this.resetLastSeenMessage();
}
};
const primarySpeaker = this.speakers.find((speaker) => speaker.id === this.getWebChannelBotId());
return html `
<on-chat-bot-notifications
.speaker=${primarySpeaker}
-notification-reset=${this.resetLastSeenMessage}
-notification-open-message=${handleNotificationOpenWidget}
></on-chat-bot-notifications>
`;
}
renderCustomButton(type, src) {
const slot = type === 'OPEN' ? 'open-chat-button' : 'close-chat-button';
const classes = classMap({
'chat-button-image': true,
'open-chat-button': type === 'OPEN',
'close-chat-button': type === 'CLOSE',
});
const isLottieAnimation = src.endsWith('.json');
return isLottieAnimation
? html `
<lottie-player
slot="${slot}"
class="${classes}"
autoplay
loop
mode="normal"
src="${src}"
="${this.handleLottieLoad}"
>
</lottie-player>
`
: html ` <img slot="${slot}" class="${classes}" src="${src}" /> `;
}
render() {
if (!this.botId) {
return;
}
switch (this.displayMode) {
case DisplayMode.WIDGET:
case DisplayMode.WIDGET_WITHOUT_BUTTON:
return this.widgetVisibility !== WidgetVisibility.HIDDEN
? html `
${this.renderChatNotifications()}
<on-chat-widget
.avatarUrl="${this.botAvatarUrl}"
.shouldHideWidgetButton="${this.displayMode ===
DisplayMode.WIDGET_WITHOUT_BUTTON}"
.windowTitle="${this.botName}"
>
${this.renderChatWindow()}
${this.chatOpenImageUrl
? this.renderCustomButton('OPEN', this.chatOpenImageUrl)
: nothing}
${this.chatCloseImageUrl
? this.renderCustomButton('CLOSE', this.chatCloseImageUrl)
: nothing}
</on-chat-widget>
`
: nothing;
case DisplayMode.SURFACE:
return this.renderSurface();
default:
return this.renderChatWindow();
}
}
};
OnChatBotClient.styles = css `
:host {
display: block;
}
:host([display-mode='FULL_SCREEN']) on-chat-window {
height: 100%;
}
:host([display-mode='WIDGET']) on-chat-window,
:host([display-mode='WIDGET_WITHOUT_BUTTON']) on-chat-window {
width: 100%;
}
:host([display-mode='SURFACE']) on-chat-window {
--on-chat-bubble-background-color: transparent;
--on-chat-bubble-border: none;
--on-chat-bubble-max-width: 80%;
--on-chat-conversation-primary-background-color: transparent;
--on-chat-conversation-primary-bubble-border: none;
--on-chat-conversation-primary-color: var(
--on-chat-surface-primary-color,
var(--on-chat-widget-primary-color, black)
);
bottom: 8rem;
left: 50%;
opacity: 0;
pointer-events: 'none';
position: fixed;
top: 0;
transition: 300ms opacity ease-in-out;
transform: translateX(-50%);
width: 80%;
z-index: ${SURFACE_WINDOW_Z_INDEX};
mask-image: linear-gradient(transparent 0, #000 20%);
}
:host([is-surface-chat-open]) .surface-backdrop,
:host([is-surface-chat-open]) on-chat-window,
:host([is-surface-chat-open]) .surface-chat-window-close-button {
opacity: 1;
pointer-events: 'auto';
}
.chat-button-image.open-chat-button {
height: var(
--on-chat-widget-button-open-size,
var(--on-chat-widget-button-size, 4rem)
);
}
.chat-button-image.close-chat-button {
height: var(
--on-chat-widget-button-close-size,
var(--on-chat-widget-button-size, 4rem)
);
}
.surface-backdrop {
background-color: var(
--on-chat-surface-backdrop-color,
rgba(0, 0, 0, 0.75)
);
backdrop-filter: blur(50px);
height: 100%;
left: 0;
opacity: 0;
pointer-events: 'none';
position: fixed;
top: 0;
transition: 300ms opacity ease-in-out;
width: 100%;
z-index: ${SURFACE_BACKDROP_Z_INDEX};
}
.surface-chat-input {
--on-chat-input-background-color: transparent;
--on-chat-input-border-width: 0;
background: linear-gradient(white, white) padding-box,
linear-gradient(
to right,
var(
--on-chat-surface-input-border-color-a,
var(--on-chat-input-border-color, #000)
),
var(
--on-chat-surface-input-border-color-b,
var(--on-chat-input-border-color, #000)
)
)
border-box;
border: 8px solid transparent;
border-radius: var(--on-chat-input-border-radius, 8px);
bottom: 2rem;
left: 50%;
max-width: 420px;
padding: 8px;
position: fixed;
transform: translateX(-50%);
width: 80%;
z-index: ${SURFACE_INPUT_Z_INDEX};
}
.surface-chat-window-close-button {
opacity: 0;
pointer-events: 'none';
position: fixed;
right: 2rem;
top: 2rem;
transition: 300ms opacity ease-in-out;
z-index: ${SURFACE_WINDOW_CLOSE_BUTTON_Z_INDEX};
}
`;
__decorate([
query('on-chat-window')
], OnChatBotClient.prototype, "onChatWindowEl", void 0);
__decorate([
query('on-chat-widget')
], OnChatBotClient.prototype, "onChatWidgetEl", void 0);
__decorate([
property({ attribute: 'chat-close-image-url' })
], OnChatBotClient.prototype, "chatCloseImageUrl", void 0);
__decorate([
property({ attribute: 'chat-open-image-url' })
], OnChatBotClient.prototype, "chatOpenImageUrl", void 0);
__decorate([
property({ attribute: 'client-id' })
], OnChatBotClient.prototype, "clientId", void 0);
__decorate([
property({ type: Boolean })
], OnChatBotClient.prototype, "debug", void 0);
__decorate([
property({ attribute: 'message-history-limit', type: Number })
], OnChatBotClient.prototype, "messageHistoryLimit", void 0);
__decorate([
property({ attribute: 'display-mode', reflect: true })
], OnChatBotClient.prototype, "displayMode", void 0);
__decorate([
property()
], OnChatBotClient.prototype, "env", void 0);
__decorate([
property({ attribute: 'initial-prompt' })
], OnChatBotClient.prototype, "initialPrompt", void 0);
__decorate([
property({ attribute: 'is-surface-chat-open', reflect: true, type: Boolean })
], OnChatBotClient.prototype, "isSurfaceChatOpen", void 0);
__decorate([
property({ attribute: 'persist-messages-across-sessions', type: Boolean })
], OnChatBotClient.prototype, "persistMessagesAcrossSessions", void 0);
__decorate([
property({ attribute: 'should-auto-open', type: Boolean })
], OnChatBotClient.prototype, "shouldAutoOpen", void 0);
__decorate([
property({ attribute: 'should-auto-open-mobile', type: Boolean })
], OnChatBotClient.prototype, "shouldAutoOpenMobile", void 0);
__decorate([
state()
], OnChatBotClient.prototype, "botAvatarUrl", void 0);
__decorate([
state()
], OnChatBotClient.prototype, "botId", void 0);
__decorate([
state()
], OnChatBotClient.prototype, "botName", void 0);
__decorate([
state()
], OnChatBotClient.prototype, "customStyles", void 0);
__decorate([
state()
], OnChatBotClient.prototype, "initialMessage", void 0);
__decorate([
state()
], OnChatBotClient.prototype, "messages", void 0);
__decorate([
state()
], OnChatBotClient.prototype, "speakers", void 0);
__decorate([
state()
], OnChatBotClient.prototype, "startingContent", void 0);
__decorate([
state()
], OnChatBotClient.prototype, "surfaceChatInputValue", void 0);
__decorate([
state()
], OnChatBotClient.prototype, "userId", void 0);
__decorate([
state()
], OnChatBotClient.prototype, "usersTyping", void 0);
__decorate([
state()
], OnChatBotClient.prototype, "webChannelParticipants", void 0);
__decorate([
state()
], OnChatBotClient.prototype, "webChannelUserId", void 0);
__decorate([
state()
], OnChatBotClient.prototype, "widgetVisibility", void 0);
OnChatBotClient = __decorate([
customElement('on-chat-bot-client')
], OnChatBotClient);
export { OnChatBotClient };
//# sourceMappingURL=bot-client.js.map