How to build a Live Chat in your Web Application using Robin Part 2
Tags: vue, webdev, opensource, tutorial
Published: 2022-08-12 10:13:18


In the last part, you looked at how you can set up Robin using its Javascript SDK while building a web applications customer service live chat feature. In this part, you will be looking at how you can set up Robin's Vue SDK to quickly set up a customer support client for CryptoDegen to respond to their user messages.


![CryptoDegen Support](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cvr2vy9aef6b6p9jhjxn.png)


## Prerequisites

To follow along with this tutorial, you should have the following:

- Knowledge of Vue.JS
- Robin API key
- A backend server to retrieve data from a database (You can use any of your choice)

If you haven't gotten your Robin API key already, you can get your Robin API key from your [Robin Account](https://dashboard.robinapp.co/signup).


## Registering Robin Vue SDK

Before proceeding, you first need to install the Robin Vue SDK. Copy and paste the following code into your terminal.

```
npm install robin-vue --save
```

Next, in your main entry file, you will need to register the Robin Vue SDK in your Vue instance. In this tutorial, it's `src/main.ts`. Copy and paste the following code:

```
// main.ts

import RobinChat from 'robin-vue'

Vue.use(RobinChat)
```

Next, import Robin's global styles. Add the following line of code to your `src/main.ts` file:

```
// main.ts

import 'robin-vue/dist/style.css'
```


## RobinChat Component

Before setting up your RobinChat component, Create a view component called `src/views/Login.vue`. This is how the support team for CryptoDegen would gain access to the Robin platform to respond to user messages.

```
// login.vue

<template>
  <div class="signin-ctn section" id="app">
    <div class="inner">
      <div class="auth-box">
        <!-- image -->
        <span>Distributing finance for everyone</span>
        <form @submit.prevent>
          <div class="form-group" :class="{ error: !emailValidate }">
            <input
              v-model="email"
              type="email"
              placeholder="email@company.com"
            />
            <label>Your Email</label>
          </div>
          <div class="form-group">
            <div class="password-field">
              <input
                v-model="password"
                :type="obscure ? 'password' : 'text'"
                placeholder="********"
              />
              <i class="material-symbols-outlined" @click="obscure = !obscure">
                {{ obscure ? 'visibility_off' : 'visibility' }}
              </i>
            </div>
            <label>Password</label>
          </div>
          <button v-if="!isLoading" class="primary-btn" @click="signIn()">
            Login
          </button>
          <button v-else class="primary-btn" disabled>
            <div class="spinner2"></div>
          </button>
        </form>
      </div>
    </div>
  </div>
</template>

export default Vue.extend({
  name: 'Login',
  data() {
    return {
      email: '' as string,
      password: '',
      obscure: true,
      isLoading: false,
    }
  },
  computed: {
    emailValidate() {
      // eslint-disable-next-line
      return /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/.test(
        this.email
      )
    },
  },
  methods: {
  },
})
</script>

<style scoped>
h1 {
  font-weight: 500;
  font-size: clamp(0.3rem, 7vw, 2rem);
}
span {
  display: block;
  font-size: clamp(0.3rem, 7vw, 1rem);
  color: #8d9091;
  margin: 0.625rem 0 1.375rem;
}
label {
  font-size: clamp(0.3rem, 5vw, 1rem);
}
.section {
  display: flex;
  justify-content: center;
  width: 100%;
}
.section > .inner {
  width: 90%;
}
.signin-ctn.section {
  min-height: 100vh;
  align-items: center;
}
.signin-ctn > .inner {
  max-width: 600px;
}
.auth-box {
  text-align: center;
  padding: 10% 15%;
  height: auto;
  min-height: 650px;
  padding-bottom: 5%;
}
.auth-box img {
  border-radius: 11px;
  margin-bottom: 1rem;
}
.form-group {
  margin-top: 1.5rem;
  position: relative;
  text-align: left;
  display: flex;
  flex-direction: column-reverse;
}
.form-group label {
  font-size: 1rem;
  display: block;
  line-height: 32px;
  transition: 0.3s;
}
.form-group input {
  display: block;
  background: #f5f7fc;
  border-radius: 4px;
  transition: 0.3s;
  width: 100%;
  height: 55px;
  padding: 0 1.5rem;
  font-size: 1rem;
  -webkit-transition: 0.3s;
  -moz-transition: 0.3s;
  -ms-transition: 0.3s;
  -o-transition: 0.3s;
}
.form-group input::placeholder {
  color: #9999bc;
}
.form-group .password-field {
  padding-right: 1.5rem;
  display: flex;
  align-items: center;
  background: #f5f7fc;
  border-radius: 4px;
  width: 100%;
  transition: 0.3s;
  -webkit-transition: 0.3s;
  -moz-transition: 0.3s;
  -ms-transition: 0.3s;
  -o-transition: 0.3s;
}
.form-group .password-field input {
  border: none;
  transition: 0s;
  -webkit-transition: 0s;
  -moz-transition: 0s;
  -ms-transition: 0s;
  -o-transition: 0s;
}
.form-group .icon {
  position: absolute;
  right: 16px;
  top: 50%;
}
.flex-ctn.link {
  width: max-content;
  margin-left: auto;
  margin-top: 0.5rem;
  font-size: 0.925rem;
}
.flex-ctn.link div {
  font-size: 1rem;
  color: #f66b03;
  cursor: pointer;
  font-weight: 400;
  line-height: 24px;
}
.header {
  margin: 10% auto 0 auto;
}
form {
  margin-top: 10%;
}
.primary-btn {
  margin-top: 2rem;
}
@media screen and (max-width: 1450px) {
  .section > .inner {
    width: 90%;
  }
}
@media screen and (max-height: 900px) {
  .auth-box {
    padding: 5% 15%;
    min-height: 560px;
  }
  .header {
    margin-top: 5%;
    font-size: 1.3rem;
  }
  .primary-btn {
    margin-left: auto;
    margin-right: auto;
  }
}
@media screen and (max-width: 600px) {
  .auth-box {
    padding: 5% 8%;
    height: auto;
    min-height: auto;
  }
  .primary-btn {
    min-width: auto;
    width: 100%;
    font-size: 0.9rem;
    height: 45px;
  }
  .flex-ctn.link {
    margin-top: 15%;
    font-size: 0.775rem;
  }
  .section > .inner {
    width: 95%;
  }
}
</style>
```

This tutorial mocks the user authentication process from the client side same as in the part 1 of this series.

Next, Create a function called `signIn()`:

```

async signIn() {
  this.isLoading = true
  const promise: Promise<ObjectType> = new Promise((resolve, reject) => {
    setTimeout(() => {
      if (
        this.email == 'cryptodegensuppor@gmail.com' &&
        this.password == 'JetpaySupport'
      ) {
        resolve({ status: 'success', data: { 
           _id: '983388d4d769496eb4bc0e42a6c0593a',
          email: 'cryptodegensuppor@gmail.com',
          username: 'Support',
          user_token: 'SxPzdCcGZeyNUGPUZRNIiFXH'
        }})
      } else {
        reject({ status: 'error', error: 'Invalid email or password' })
      }
    }, 2000)
  })
  const response = await promise as ObjectType
  if (response.status === 'success') {
    this.$router.push('/chat')
    localStorage.setItem('data', JSON.stringify(response.data))
  } else {
    console.log(response)
  }
  this.isLoading = false
}
```

Now, to initialize the RobinChat component, create a view component `src/views/Chat.vue` and paste the following code snippet below:

```

<template>
  <div class="chat">
    <RobinChat
      logo="https://iili.io/wUVjdG.png"
      api-key="NT-XmIzEmWUlsrQYypZOFRlogDFvQUsaEuxMfZf"
      :users="users"
      :user-token="userToken"
      :keys="keys"
      :user-name="userName"
      channel="private_chat"
      :features="[]"
    >
    </RobinChat>
  </div>
</template>

<script lang="ts">
import Vue from 'vue'

type ObjectType = Record<string, any>

export default Vue.extend({
  name: 'Chat',
  data() {
    return {
      userName: '',
      userToken: '',
      users: [] as Array<ObjectType>,
      keys: {
        userToken: 'robin_user_token',
        profileImage: 'profile_photo',
        userName: 'username',
      },
    }
  },
  created() {
    if (localStorage.getItem('data')) {
      const data = JSON.parse(localStorage.getItem('data') || '{}')
      this.userToken = data.user_token
      this.userName = data.user_name
    }

    this.getUsers()
  },
  methods: {
    async getUsers() {
      const promise: Promise<Array<ObjectType>> = new Promise((resolve) => {
        setTimeout(() => {
          const users = [
            {
              _id: '983388d4d769496eb4bc0e42a6c0593a',
              email: 'cryptodegensupport@gmail.com',
              username: 'CryptoDegen Support',
              robin_user_token: 'SxPzdCcGZeyNUGPUZRNIiFXH',
              profile_photo: '',
            },
            {
              _id: 'b990738c18584abfbad077ad90712b56',
              email: 'enoch11@gmail.com',
              username: 'Enoch Chejieh',
              robin_user_token: 'SHkPHNIYqwQIvyaYFaovLlHa',
              profile_photo: '',
            },
          ]
          resolve(users)
        }, 1000)
      })
      const response = await promise
      this.users = [...response]
    },
  },
})
</script>
```

Robin Vue SDK provides extra options like features which allows you to specify which Robin feature you would like to use on the platform, such as `create-chat`, `forward-messages`, delete-messages, `archive-chat`, `reply-messages`, `voice-recorder`, `message-reactions.view` and `message-reaction.delete`.


![robin-vue User Interface](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/05bnkbc80upp0t3tf39g.png)


## Conclusion

So quick recap. In this part you’ve learned how to use the Robin Vue SDK in your Vue application.

In-app live chat communication just got a lot easier with no extra configurations needed using Robin’s official SDKs is as easy as plug-in-play.

You can get the source code in this [repository](https://github.com/ECJ222/cryptodegen-support) and view the [demo](cryptodegen-support.vercel.app) in action.

I hope you enjoyed this short series, I can’t wait to see what you build!