DEV Community πŸ‘©β€πŸ’»πŸ‘¨β€πŸ’»

Enoch Chejieh
Enoch Chejieh

Posted on

How to build a Live Chat in your Web Application using Robin Part 2

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

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.

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
Enter fullscreen mode Exit fullscreen mode

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)
Enter fullscreen mode Exit fullscreen mode

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'
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

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
}
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

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

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 and view the demo in action.

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

Top comments (0)

🌚 Browsing with dark mode makes you a better developer.

It's a scientific fact.