DEV Community

Emmanuel Aiyenigba
Emmanuel Aiyenigba

Posted on • Updated on

How to automatically mark a conversation as "answered" in TalkJS

In a field where you have to respond to messages from your customers, you would want to remove answered chats from your inbox or maybe add a sign to indicate that you have responded to this customer. Doing so helps you stay organized and prioritized. TalkJS allows you to add custom data to every message. This custom data can help filter conversations in your inbox.

This article aims to teach you how to automatically mark a conversation as “answered" and filter out answered conversations from your inbox or indicate with a label if it is answered. A good use case for this is in the field of customer service, where customers can create support tickets regarding any issues they might have or inquiries they might want to make about your product. Support wants to know which messages they have answered to stay prioritized.

Pre-requisites

To follow along, you need:

  • A free TalkJS account.
  • Familiarity with JavaScript
  • Any code editor of your choice

Creating a conversation

Let’s add TalkJS to our application and start a conversation between a Support staff and two customers. Smith and John are customers chatting with Lynda, a support staff. Smith has a payment issue to resolve, while John wants to inquire about a product.

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Auto mark conversation as read</title>
</head>
<body>
<script>
(function(t,a,l,k,j,s){
s=a.createElement('script');s.async=1;s.src="https://cdn.talkjs.com/talk.js";a.head.appendChild(s)
;k=t.Promise;t.Talk={v:3,ready:{then:function(f){if(k)return new k(function(r,e){l.push([f,r,e])});l
.push([f])},catch:function(){return k&&new k()},c:l}};})(window,document,[]);
</script>

    <div id="talkjs-container" style="width: 90%; margin: 30px; height: 500px">
      <i>Loading chat...</i>

    </div>

</body>
</html>

Enter fullscreen mode Exit fullscreen mode

Let’s initialize TalkJS inside a JavaScript file.


Talk.ready.then(function() {

        const support = new Talk.User({
            id: '123456',
            name: 'Lynda from Support',
            email: 'lynda@test.app',
            photoUrl: 'https://talkjs.com/images/avatar-1.jpg',
            welcomeMessage: 'Hi! I am Lynda from support, how may I be of   help!',
            role: 'support'
        });

    window.talkSession = new Talk.Session({
        appId: 'YOUR_APP_ID',
        me: support,
    });
    const customer1 = new Talk.User({
        id: '654321',
      name: 'Smith',
      email: 'smith@example.com',
      photoUrl: 'https://talkjs.com/images/avatar-5.jpg',
      welcomeMessage: 'Hey, I have some troubles with...',
      role: 'customer'
    });

    const customer2 = new Talk.User({
      id: '1000001',
      name: 'John',
      email: 'john@example.com',
      photoUrl: 'https://talkjs.com/images/avatar-4.jpg',
      welcomeMessage: 'Hey, I want to make an inquiry...',
      role: 'customer'
    });
Enter fullscreen mode Exit fullscreen mode

Replace YOUR_APP_ID with the App ID on your TalkJS dashboard. We added the customer and support roles we shall create in our dashboard shortly. The role attribute will help us determine whether a message is from support or a customer.

Creating a custom role and theme

create custom role

Go to your TalkJS dashboard and create the two roles we assigned above.

At some point, we would want to display a label in the conversation list indicating whether a conversation is answered. To do this, we need to create a custom theme because we don’t want to modify the default theme.

Let’s create a custom theme and set our roles to use it. We will give it the name custom.

custom theme

Set the customer and support roles to use the created custom theme.

theme-role gif

Starting a conversation between support and customers

Let’s start a chat between our imaginary support staff, Lynda and Smith. And another chat between Lynda and John.

const conversation = talkSession.getOrCreateConversation(
        Talk.oneOnOneId(support, customer1)
        );
    conversation.setAttributes({
        subject: "Payment Issues"
    })
    conversation.setParticipant(support);
    conversation.setParticipant(customer1);

    const otherConversation =   talkSession.getOrCreateConversation(Talk.oneOnOneId(support, customer2));
    otherConversation.setAttributes({ subject: "Inquiry"});

    otherConversation.setParticipant(support);
    otherConversation.setParticipant(customer2);
Enter fullscreen mode Exit fullscreen mode

The subject of the conversation between Lynda (support) and Smith (customer1) is “Payment Issues” while John (customer2) wants to make an “Inquiry.”

Create an inbox for the conversation between Lynda and Smith.

    const inbox = talkSession.createInbox({ selected: conversation});
    inbox.mount(document.getElementById('talkjs-container'));
Enter fullscreen mode Exit fullscreen mode

Run your program! You should see something like this.

chat sample

To display the conversation between Lynd and John, replace:

    const inbox = talkSession.createInbox({ selected: conversation});
Enter fullscreen mode Exit fullscreen mode

With

    const inbox = talkSession.createInbox({ selected: otherConversation});
Enter fullscreen mode Exit fullscreen mode

Now you have a conversation with John set up.

conversation with John

Listening to messages via webhooks

To know whether a message is from a customer or a support staff, we need to listen to it via the TalkJS webhooks. Integrate ngrok to test the webhooks locally. ngrok enables you to expose your local development server to the internet. Follow this guide to set up ngrok on your local machine.

Let’s spin up an Express.js server to use webhooks.

    mkdir chat-backend
    cd chat-backend
    npm install express axios
Enter fullscreen mode Exit fullscreen mode

We need axios to make API calls.

Create an index.js file inside your Express project and add the following code

    const express = require('express');
    const app = express();
    const http = require('http');
    const server = http.createServer(app);

    app.use(express.json())

    app.post('/talkjs', (req, res) => {
      console.log(req.body)
      res.status(200).send('OK')
    });

    server.listen(8080, () => {
      console.log('listening on *:8080');
    });
Enter fullscreen mode Exit fullscreen mode

“/talkjs” is the route that will receive the webhooks request. Go ahead and run ngrok on your machine.

ngrok terminal

Go to your TalkJS dashboard, and add the forwarding address from ngrok as your webhook URL. Don’t forget to add the “/talkjs” suffix. You should also enable message.sent as that is the only hook we need.

webhooks settings

Now, we can receive sent messages in our backend via the webhook. Let’s test it out!

Lynda (support) sends John (customer2) a message.

Lynda and John's conversation

If you navigate to the ngrok address at localhost:4040 you will get the message object.

ngrok response

You can also see this message object in the console of your server running on port 8080 (or whatever port you specified). We will update the message data from the backend via TalkJS REST API

Updating a conversation via REST API

Whenever the backend receives the message object, we want to update it to include custom data. Ensure to do this on the backend so as not to expose your application’s secret token - that would be a big security risk.

If the sender is a customer, we want to add a custom property {answered: “false”} to the conversation (custom property can also have string values hence the boolean in a string). But if the sender is Lynda, the support staff, we want to add a custom property {answered: “true”}.

const express = require('express');
const app = express();
const http = require('http');
const server = http.createServer(app);
const axios = require("axios");
require('dotenv').config()


app.use(express.json())




const token = process.env.SECRET_TOKEN
const appId = process.env.APP_ID


async function UpdateConversationforSupport(conversationId){


const supportData= {
  custom: {
    answered: "true"
  }
}


const config = {
  headers : {
    Authorization: `Bearer ${token}`
  }
}


  axios.put(
    `https://api.talkjs.com/v1/${appId}/conversation/${conversationId}`,
    supportData,
    config


  )

}




async function UpdateConversationforCustomer(conversationId){


  const customerData= {
    custom: {
      answered: "false"
    }
  }

  const config = {
    headers : {
      Authorization: `Bearer ${token}`
    }
  }

    axios.put(
      `https://api.talkjs.com/v1/${appId}/conversation/${conversationId}`,
      customerData,
      config

    )  
}


app.post('/talkjs', (req, res) => {
    console.log(req.body)
    res.status(200).send('OK')


    const {role} = req.body.data.sender
    const {conversationId} = req.body.data.message


    if(role == "support"){
      UpdateConversationforSupport(conversationId)
    }else{
      UpdateConversationforCustomer(conversationId)
    }
 });




server.listen(8080, () => {
  console.log('listening on *:8080');
});
Enter fullscreen mode Exit fullscreen mode

Ensure to put your application’s secret key and token inside a .env file.

A custom data will be added to every message based on the sender's role. Let’s try it out.

Lynda sends another chat to John

Lynda chat John

If you go to our TalkJS dashboard, click on Activity, scroll down, and select the conversation.

dashboard activity

You can see that the custom data was added to the conversation.

Filtering Inbox based custom data

As a support staff, you’d want to stay organized. You want every answered conversation to be automatically filtered out of your inbox so that you can easily prioritize the unanswered conversations.

To demonstrate the TalkJS FeedFilter method for filtering our inbox, Smith and John (our customers) will each send Lynda a message.
You can go to another page of your application, set it up and send a message as John and another as Smith.

To display both conversations in your inbox, replace:

    const inbox = talkSession.createInbox({ selected: otherConversation});
Enter fullscreen mode Exit fullscreen mode

With

const inbox = talkSession.createInbox();
Enter fullscreen mode Exit fullscreen mode

Now, we can see the messages from Smith and John.

all inbox

Let’s make Lynda reply to John but not Smith.

Lynda replies John

We now have one answered conversation and one unanswered conversation. Let’s use the FeedFilter method to remove the answered conversation from the inbox.

 inbox.setFeedFilter({ custom: { answered: ["==", "false"] } })
Enter fullscreen mode Exit fullscreen mode

Any conversation with custom property {answered: “true”} is removed from your inbox.

filter inbox

The conversation with John has been filtered out of the list because it is answered.

Adding a label to answered conversation

Alternatively, you may want to add a label to every answered conversation instead of filtering it out of your inbox. Let’s add “✔✔” to every answered conversation.
To do this, we need to go inside our TalkJS dashboard to edit the ConversationListItem subcomponent of our custom theme.

custom theme subcomponent

We have access to the custom data inside the ConversationListItem subcomponent. Let’s use it to display the “✔✔” label on answered conversations.

Scroll down to line 62. The next line after the following code

<span class="timestamp"><TimeAgo timestamp="{{lastMessage.timestamp}}"/></span>
Enter fullscreen mode Exit fullscreen mode

Add

<span t:if="{{conversation.custom.answered == 'true'}}">✔✔ </span>
Enter fullscreen mode Exit fullscreen mode

The above code adds “✔✔” to every answered conversation.

To see the effect, remove the FeedFilter to display all conversations inside the inbox.

Remove (or comment out)

 inbox.setFeedFilter({ custom: { answered: ["==", "false"] } })

Enter fullscreen mode Exit fullscreen mode

mark answered convo

Now we have the double check mark beside John’s conversation (because it is answered).

The check mark seems too close to the timestamp. Let's add some padding to it.
Scroll down to the styling, locate the .timestamp class and add a padding-right property.

.timestamp {
  padding-right: 10px;
}
Enter fullscreen mode Exit fullscreen mode

Take a look!

filter feature complete

Summary

TalkJS lets you listen to incoming messages via its webhooks. You can also add custom data to conversations. This custom data can be useful for conditionally filtering out conversations from your inbox using the FeedFilter method.

Automatically marking a conversation as answered can be helpful in customer service. Support staff stays organized and prioritized while serving their customers.

Top comments (0)