Posted on May 23, 2021

Advertisement

Hi Trailblazers, In this blog post we are going learn, How to Use Lightning Web Components in Einstein Bot.

Sometimes, We have a requirement to show a Lightning Component inside Einstein Bot’s Chat window.

In this blog, I’m going to Show a simple Calculator Component inside Einstein Bot.

Before we start, Let’s have a look at the demo itself.

For a quick demo, All you need to do.

Click on the right bottom button “Chat with an Expert”

After Greeting Messages, answer quick questions.

And Type: Calculator

Now It’ll Show you Calculator Component.

Let’s Start 🙂

Some days ago, I posted a Blog.

Use Images And Videos In Einstein Bot

In this Blog, I was showing you, How to show Images and Videos in Einstein Bot.

Before reading this blog, I’d like you to visit to Use Images And Videos In Einstein Bot

Walkthrow 🙂

1. First we’ll create a Calculator Component to use in Einstein Bot.

2. We’ll create a Component for Embedded Service Deployments.

3. After that, We’ll add component in Embedded Chat.

4. In last, We’ll update and create some dialogue in Einstein Bot.

Let’s create 🙂

MyCalculator.html

<template>
<div class="slds-box">
    <img src={SfLogo} width="50%">
    <div class="slds-box">
<div>LWC Calculator </div>
<lightning-input type="number" name="input1" label="Enter 1st number" onchange={inputChange}></lightning-input>
<lightning-input type="number" name="input2" label="Enter 2nd number" onchange={inputChange}></lightning-input>
<div>
<lightning-button-group>
<lightning-button name="add" label="Add" onclick={calculate}></lightning-button>
<lightning-button name="subtract" label="Subtract" onclick={calculate}></lightning-button>
<lightning-button name="multiply" label="Multiply" onclick={calculate}></lightning-button>
<lightning-button name="divide" label="Divide" onclick={calculate}></lightning-button>
</lightning-button-group>
</div>
<br/>
{outputNumber}
</div>
<div class="slds-box">
<lightning-input type="checkbox" label="Show Previous Result" name="checkbox1" onchange={calculate}>
</lightning-input>
<template if:true={showOldResult}>
<ul>
<template for:each={allOutputResult} for:item="item">
<li key={item}>{item}</li>
</template>
</ul>
</template>
</div>
</div>
</template>

myCalculator.js

import { LightningElement, track } from 'lwc';
import heySfLogo from '@salesforce/resourceUrl/heySfLogo';
export default class MyCalculator extends LightningElement {
@track outputNumber;
@track allOutputResult = [];
@track showOldResult = false;
input1;
input2;
@track SfLogo;
SfLogo = heySfLogo ;
inputChange(event)
{

if(event.target.name === 'input1')
{
// eslint-disable-next-line radix
this.input1 = parseInt(event.target.value );
}
else if(event.target.name === 'input2')
{
// eslint-disable-next-line radix
this.input2 = parseInt(event.target.value) ;
}
}
calculate(event)
{
if(event.target.name === 'add')
{
this.outputNumber = `${this.input1} + ${this.input2} = ${(this.input1 + this.input2)}` ;
this.allOutputResult.push(this.outputNumber);
}
if(event.target.name === 'subtract')
{
this.outputNumber = `${this.input1} - ${this.input2} = ${(this.input1 - this.input2)}` ;
this.allOutputResult.push(this.outputNumber);
}
if(event.target.name === 'multiply')
{
this.outputNumber = `${this.input1} x ${this.input2} = ${(this.input1 * this.input2)}` ;
this.allOutputResult.push(this.outputNumber);
}
if(event.target.name === 'divide')
{
this.outputNumber = `${this.input1} / ${this.input2} = ${(this.input1 / this.input2)}` ;
this.allOutputResult.push(this.outputNumber);
}
if(event.target.name === 'checkbox1')
{
    if(this.showOldResult === false)
    {
        this.showOldResult = true;
    }
    else if(this.showOldResult === true)
    {
        this.showOldResult = false;
    }
   
        
}
}
}

myCalculator.js-meta.xml

<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
    <apiVersion>47.0</apiVersion>
    <isExposed>true</isExposed>
    <targets>
        <target>lightning__HomePage</target>
    </targets>
</LightningComponentBundle>

Deploy this Component to Salesforce Org.

For calling Calculator Component:

        <template if:true={isLwc}>
            <c-my-calculator></c-my-calculator>
        </template>

Complete code for Chat Component:

chatMessage.html

<template>
    <template if:false={isAgent}>
        <div class="chatMessage chasitor">
            <lightning-formatted-rich-text value={messageContent.value}>   
            </lightning-formatted-rich-text>
        </div>
    </template>
    <template if:true={isAgent}>
        <template if:true={isPlainText}>
            <div class="chatMessage agent plainText">
                <lightning-formatted-rich-text value={content}>
                </lightning-formatted-rich-text>
            </div>
        </template>

        <template if:true={isRichText}>
            <div class="chatMessage agent richText">
                <lightning-formatted-rich-text value={content}>
                </lightning-formatted-rich-text>
            </div>
        </template>

        <template if:true={isYoutube}>
            <div class="chatMessage agent youtube">
                <iframe src={content} allowfullscreen>
                </iframe>
            </div>
        </template>

        <template if:true={isImage}>
            <div class="chatMessage agent image">
                <img src={content} />
            </div>
        </template>

        <template if:true={isLwc}>
            <c-my-calculator></c-my-calculator>
        </template>

        <template if:true={isNavigate}>
            <div class="chatMessage agent plainText">
                <lightning-formatted-rich-text value={content}>
                </lightning-formatted-rich-text>
            </div>
        </template>
        
        <template if:true={isUrl}>
            <template if:true={hasOGPInfo}>
                <div class="chatMessage agent url">
                    <a href={content} target="_blank"></a>
                    <img src={ogpMeta.image} onerror={fallback} />
                    <div class="ogpInfo">
                        <div class="title">{ogpMeta.title}</div>
                        <div class="description">{ogpMeta.description}</div>
                        <div class="site_name">{ogpMeta.site_name}</div>
                    </div>
                </div>
            </template>
            <template if:false={hasOGPInfo}>
                <div class="chatMessage agent plainText">
                    <lightning-formatted-rich-text value={content}>
                    </lightning-formatted-rich-text>
                </div>
            </template>
        </template>
    </template>
</template>

chatMessage.js

import BaseChatMessage from 'lightningsnapin/baseChatMessage';
import { track } from 'lwc';
import { loadStyle } from 'lightning/platformResourceLoader';
import chatMessageStyle from '@salesforce/resourceUrl/chatMessageStyle';

const DEFAULT_MESSAGE_PREFIX = 'PLAIN_TEXT';
const RICHTEXT_MESSAGE_PREFIX = 'RICH_TEXT';
const YOUTUBE_MESSAGE_PREFIX = 'YOUTUBE';
const IMAGE_MESSAGE_PREFIX = 'IMAGE';
const LWC_MESSAGE_PREFIX = 'COMPONENT';
const URL_MESSAGE_PREFIX = 'URL';
const NAVIGATE_MESSAGE_PREFIX = 'NAVIGATE';
const SUPPORTED_MESSAGE_PREFIX = [DEFAULT_MESSAGE_PREFIX, RICHTEXT_MESSAGE_PREFIX, YOUTUBE_MESSAGE_PREFIX, IMAGE_MESSAGE_PREFIX, LWC_MESSAGE_PREFIX, URL_MESSAGE_PREFIX, NAVIGATE_MESSAGE_PREFIX];
const OPENGRAPH_API_KEY = 'YOUR_OPENGRAPH_API_KEY';

/**
 * Displays a chat message using the inherited api messageContent and is styled based on the inherited api userType and messageContent api objects passed in from BaseChatMessage.
 */
export default class ChatMessageDefaultUI extends BaseChatMessage {
    messageType = DEFAULT_MESSAGE_PREFIX;
    @track content = '';
    @track ogpMeta = {};
    connectedCallback() {
        if (!this.isAgent) {
            return;
        }
        const messageTypePrefixPosition = SUPPORTED_MESSAGE_PREFIX.indexOf(this.messageContent.value.split(':')[0]);
        if (messageTypePrefixPosition > -1) {
            this.messageType = SUPPORTED_MESSAGE_PREFIX[messageTypePrefixPosition];
            console.log('Message Type:'+this.messageType);
        }
        const contentValue = (this.messageContent.value.split(this.messageType + ':').length === 1) ? this.messageContent.value : this.messageContent.value.split(this.messageType + ':')[1];
        console.log('Message contentValue:'+contentValue);
        Promise.all([
            loadStyle(this, chatMessageStyle + '/style.css')
        ]);
        if (this.isPlainText) {
            this.content = contentValue;
        } else if (this.isYoutube) {
            this.content = 'https://www.youtube.com/embed/' + contentValue
        } else if (this.isNavigate) {
            const url = this.extractOriginalUrl(contentValue);
            window.open(url);
            this.content = `Opening ${url}`;
        } else if (this.isImage) {
            this.content = this.extractOriginalUrl(contentValue);
        } else if(this.isLwc) {
            console.log('In LWC');
            //this.content = this.extractOriginalUrl(contentValue);
        } else if (this.isUrl) {
            this.content = this.extractOriginalUrl(contentValue);
            const urlEncoded = encodeURIComponent(this.content);
            const requestURL = 'https://opengraph.io/api/1.1/site/' + urlEncoded + '?app_id=' + OPENGRAPH_API_KEY;
            fetch(requestURL, { method: "GET" })
                .then(response => {
                    return response.json();
                })
                .then(jsonResponse => {
                    if(jsonResponse.hybridGraph) {
                        this.ogpMeta.title = jsonResponse.hybridGraph.title;
                        this.ogpMeta.description = jsonResponse.hybridGraph.description;
                        this.ogpMeta.image = jsonResponse.hybridGraph.image;
                        this.ogpMeta.site_name = jsonResponse.hybridGraph.site_name;
                    }
                })
        } else {
            this.content = contentValue
                .replace(/&lt;/g, '<')
                .replace(/&gt;/g, '>')
                .replace(/&quot;/g, '\"')
                .replace(/<a href='mailto:.*?' target='_blank'>(.*?)<\/a>/g, '$1')
                .replace(/<a href='/g, '')
                .replace(/' target='_blank'.*?<\/a>( +)/g, '$1')
                .replace(/' target='_blank'.*?<\/a>.*?<\/a>/g, '');
        }
    }

    extractOriginalUrl(generatedString) {
        const matched = generatedString.match(/<a href.+>(.*?)<\/a>/);
        if (matched.length > 1) {
            return matched[1];
        }
        return generatedString;
    }

    fallback(event) {
        event.target.onerror = null;
        event.target.style.display = 'none';
        event.target.style.height = 0;
    }

    get isAgent() {
        return this.userType === 'agent';
    }

    get isPlainText() {
        return this.messageType === DEFAULT_MESSAGE_PREFIX;
    }

    get isRichText() {
        return this.messageType === RICHTEXT_MESSAGE_PREFIX;
    }

    get isYoutube() {
        return this.messageType === YOUTUBE_MESSAGE_PREFIX;
    }

    get isImage() {
        return this.messageType === IMAGE_MESSAGE_PREFIX;
    }

    get isLwc() {
        return this.messageType === LWC_MESSAGE_PREFIX;
    }

    get isUrl() {
        return this.messageType === URL_MESSAGE_PREFIX;
    }

    get isNavigate() {
        return this.messageType === NAVIGATE_MESSAGE_PREFIX;
    }

    get hasOGPInfo() {
        return this.ogpMeta.title !== undefined;
    }
}

chatMessage.js-meta.xml

<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
    <apiVersion>50.0</apiVersion>
    <isExposed>true</isExposed>
    <targets>
      <target>lightningSnapin__ChatMessage</target>
    </targets>
</LightningComponentBundle>

chatMessage.css

.chatMessage {
    font-size: 0.875em;
    max-width: 70%;
    padding: 10px;
    white-space: pre-wrap;
    text-align: left;
}

.chasitor {
    color: #FFF;
    background: #005290;
    margin-left: auto;
    border-radius: 10px 10px 0;
    float: right;
}

.agent {
    margin-left: 40px;
    border-radius: 10px 10px 10px 0;
    float: left;
}

.agent.plainText {
    color: #333;
    background: #f4f4f4;
}

.richText {
    border: 1px solid #AAA;
}

.youtube, .image, .url {
    max-width: 100%;
}

.youtube iframe, .image img, .url img {
    max-width: 100%;
    border: 0;
}

.url {
    position: relative;
    padding: 0;
    margin-right: 40px;
    border-radius: 10px;
    border: 1px solid #DDD;
}

.url a {
    position: absolute;
    top: 0;
    left: 0;
    height: 100%;
    width: 100%;
}

.url img {
    border-radius: 10px 10px 0 0;
    width: 100%;
    height: 150px;
    object-fit: cover;
}

.url .ogpInfo {
    padding: 5px;
    color: #333;
}

.url .ogpInfo .title {
    word-break: break-all;
    display: -webkit-box;
    overflow: hidden;
    -webkit-line-clamp: 1;
}

.url .ogpInfo .description {
    margin-top: 10px;
    font-size: 0.8rem;
    color: #3e3e3c;
    word-break: break-all;
    overflow: hidden;
    display: -webkit-box;
    -webkit-line-clamp: 3;
}

.url .ogpInfo .site_name {
    margin-top: 10px;
    font-size: .75rem;
    color: #3e3e3c;
}

Deploy this component to Salesforce Org.

Now, Got to Embedded Service Deployments.

Click on Edit.

Scroll down to Customize with Lightning Components

And choose chatMessage.

Now, We need to update Dialogs in Einstein Bot.

Go to Einstein Bot Builder.

Go to : Setup > Einstein Bots > yourBot

After clicking on your Bot, You’ll go to Einstein Bot Builder.

Now, need to update Dialogs.

If a message in Einstein Bot starts with

COMPONENT:<COMPONENT NAME>

Shows the Component in Einstein Bot.

RICH_TEXT:<RICH_TEXT_CONTENT_INCLUDING_SUPPORTED_HTML_TAGS>

Shows the message in rich text format.

YOUTUBE:<YOUTUBE_VIDEO_ID>

Shows the youtube video in chat window.

IMAGE:<IMAGE_URL>

Shows the image.

NAVIGATE:<TARGET_URL>

Opens the url with a new browser window (tab).

URL:<TARGET_URL>

Shows the OGP info.

PLAIN_TEXT:<MESSAGE>

Shows the message in plain text format.

In my case

For Component :

COMPONENT:myCalculator

After updating all the Dialogs

Activate the Einstein Bot and Test it.

Click on right bottom button “Chat with an Expert”

After Greeting Messages, answer quick questions.

And Type: Calculator

Now It’ll Show you Calculator Component.

As you can see, It’s working now.

This is how we can use Lightning Web Components in Einstein Bot.

I took reference from this repository and Updated it for Lightning Web Components.

I hope It’ll help you somehow.

If you have any question Ask Me

Thanks for Reading 🙂

Write a comment for suggestions and hit the heart icon.

Please click here to read the original article as posted on HeySalesforce.

We source the web to bring you best Salesforce articles for our reader’s convenience. If you want to have this article removed, please follow guidelines at Digital Millennium Copyright Act (DMCA)..