How to automatically mark a conversation as "answered" in TalkJS
Published: 2023-04-05 15:25:32



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`

```htmlmixed
<!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>

```




Let’s initialize TalkJS inside a JavaScript file.

```javascript

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'
    });
```




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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5kqra7cvnko6v400mi2i.png)


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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kry7hl2tpopv0z3u6u85.png)

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

![theme-role gif](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/v9ve4cni45pg36wdaaxr.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. 


```javascript
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);
```


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.



```javascript
    const inbox = talkSession.createInbox({ selected: conversation});
    inbox.mount(document.getElementById('talkjs-container'));
```

Run your program! You should see something like this.

![chat sample](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wlcrk4z9px24gv2uk6ts.png)

To display the conversation between Lynd and John, replace:


```javascript
    const inbox = talkSession.createInbox({ selected: conversation});
```

With

```javascript
    const inbox = talkSession.createInbox({ selected: otherConversation});
```

Now you have a conversation with John set up.

![conversation with John](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cqpvz4ovkayj5obphgd1.png)


## 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](https://talkjs.com/resources/how-to-integrate-ngrok-with-talkjs-to-receive-webhooks-locally/) 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
```

We need axios to make API calls.

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

```javascript 
    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');
    });
```

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


![ngrok terminal](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1xue24ddtyn1ib4zehy7.png)

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yidv9bz6qry2jtmbv4u1.png)


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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5pmoi41qqw32y711sktj.png)


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


![ngrok response](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3anmjorp4k4j5qes6t5r.png)


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”}`.

```javascript
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');
});
```

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3o6wxpgvdhsjwivksv8x.png)


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


![dashboard activity](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zjbhqqdh4l2ys0tqx87i.png)


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:


```javascript
    const inbox = talkSession.createInbox({ selected: otherConversation});
```

With

  ```javascript  
const inbox = talkSession.createInbox();
```



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


![all inbox](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/n41nmc3rh8s3z6hnc7qi.png)


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


![Lynda replies John](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mtk2jnw7aebuhyptmvad.png)



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

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

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


![filter inbox](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/j74kty2o1u2yumgednfe.png)


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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vnkgehlixxb4dqq0gv3s.png)

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

```html
<span class="timestamp"><TimeAgo timestamp="{{lastMessage.timestamp}}"/></span>
```

 Add
 
```html
<span t:if="{{conversation.custom.answered == 'true'}}">✔✔ </span>
```

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)

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

```

![mark answered convo](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5a5nfcuzm9z00y85tmj4.png)


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.

```css
.timestamp {
  padding-right: 10px;
}
```



Take a look!


![filter feature complete](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/l6oxbt2hz3b5cyuni5lh.png)


## 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.