facebook How to Build an Instant Messaging App with QuickBlox and Vue.js • QuickBlox

How to Build an Instant Messaging App with QuickBlox and Vue.js

Hamza Mousa
28 May 2021
How to create a messaging application with Vue JavaScript framework

QuickBlox is communication as an infrastructure platform (CPaaS), which focuses on providing secure privacy-aware messaging functionalities to enterprises. The current QuickBlox features include real-time instant messaging, HD video calling with high-quality audio communication, file-sharing, and push notifications.

QuickBlox has a set of software development kits (SDKs) with full native libraries for mobile platforms such as iOS and Android. It also offers full support for Flutter, React Native, and RESTful API.

To say the least, the platform is a Swiss Army knife for creating interactive rich communication and messaging apps that can cover different use-cases and scopes.

In this article we will demonstrate how to create a messaging application with the Vue JavaScript framework. But first, let us explain why did we choose Vue.js?

Vue is a JavaScript framework for creating web and mobile applications. It has a large community of developers who pack it with countless numbers of libraries, frameworks, and UI components.

Vue’s vast ecosystem is rich with open-source components, code samples, and frameworks that ease the production of a stable solution.

With Vue, developers can create several types of applications starting from statically generated websites, web components (web widgets), mobile applications, control dashboards, API-based websites, and highly dynamic websites with its server-side rendering capabilities.

Vue can be used for creating mobile applications with frameworks like Ionic and Framework7. Furthermore, with some tweaks using Electron, developers can build a fancy desktop application with it.

Requirements

You can install Vue with NPM or YARN. note that it requires admin permission to be installed on macOS and Linux.

npm install -g @vue/cli or yarn global add @vue/cli.

Now let’s make sure Vue is installed.

$ vue --version

@vue/cli 4.5.9

Create your project

To create a new project with Vue, we simply use vue create project_name.

vue create quickblox-chat

Soon as you enter the project creation command, Vue will ask you which Vue will you use, we will use Vue 2 because it has a larger ecosystem for plugins and UI components.

Default ([Vue 2] babel, eslint)

Project setup

Switch to the project’s folder and install the required libraries. Our core library here is QuickBlox JavaScript SDK which provides us with all QuickBlox functionality with simple API.

Buefy is a Bulma CSS framework packed as Vue components. We need it here for more than styling and the design, as it also has many reactive libraries like toast, modal, dialog, alerting and more.

LowDash is a rich JavaScript functional library which comes handy for working with arrays, collections and data manipulation.

Moment.js is a lightweight library for data, time, duration and time-differences manipulation.

yarn add quickblox
yarn add buefy
yarn add lodash
yarn add lowdb
yarn add moment
yarn add array-sort
yarn add vue-moment

Here we will setup our libraries in the main.js.

js
import Vue from 'vue'
import App from './App.vue'

import Buefy from 'buefy'
import 'buefy/dist/buefy.css'

Vue.use(require('vue-moment'));
Vue.use(Buefy)

Vue.config.productionTip = false

new Vue({
  render: h => h(App),
}).$mount('#app')

QuickBlox Setup

In order to start working with QuickBlox API, you need to create an application from the QuickBlox developer’s dashboard. This step will provide you with the Application ID, Authorization key and Authorization secret which you need for creating your app.

QuickBlox Init

Now as we have everything ready let’s import QuickBlox SDK and setup the app credentials.

js
import QB from 'quickblox/quickblox'
const CREDENTIALS = {
  appId: '....',
  authKey: '....',
  authSecret: '...............',
  roomId: '.................',
  roomJID: '.................................',
}

Setup local database support

LowDB is lightweight local JSON database library. It’s powered by Lodash and supports local flat-file, in-memory database and localStorage for the browser. I use it for small projects as a reactive storage for configurations and to provide a local database support.

In the next code snippet at App.vue we will import `lowdb` and setup our local database support. we can setup the default configurations for our app as we see fit.

js
  import low from 'lowdb'
  const Memory = require('lowdb/adapters/LocalStorage')
  const db = low(new Memory())
  db.defaults({
    config: {
      title: "QuickBlox Messaging Widget"
    },
  }).write()
js

computed: {
  db() {
    return this.lastChanged, db
  },
  configs() {
    return this.db.get('config').value()
  },

},

// update database
methods: {

  update() {
    this.lastChanged = Date.now()
  }

}

Let’s start coding

After the previous steps of configuration and setup, It’s the time to start building our QuickBlox messaging application.

js
export default {
  name: 'App',
  components: {
  },
  data() {
    return {
      username: '',
      password: '',
      newMessage: '',
      messages: '',
      loggedIn: '',
      isLoading: false,
      isFullPage: true,
      animated: true,
      lastChanged: Date.now(),
      randomNumber: '',
      currentUserId: '',
      users: ''
    }
  },
  methods:{

  },
  created() {
    var self = this;
    // Init QuickBlox App
    QB.init(CREDENTIALS.appId, CREDENTIALS.authKey, CREDENTIALS.authSecret);
    // Subscribe to new messages
    QB.chat.onMessageListener = onMessage;
    function onMessage(userId, message) {
      self.messages.push(message)
      self.newMessage = ""
    }
  }

}

As you noticed in the code above, we initiated QuickBlox connection within created section which will be used as well to subscribe for new messages.

Creating Login Template

First step of our workflow is the user’s login. Here we will create a template for user’s login in App.vue.

We will create everything in one file to make is easier to read, modify and edit. The main goal is to demonstrate using Vue to build QuickBlox-based apps. You can re-create the experience later using the full power of Vue, create a re-usable components, complex routes, vues and of-course add more QuickBlox functionalities.

html
<template>
  <div id="app" class="section container is-paddingless">
  <b-loading :is-full-page="isFullPage" v-model="isLoading" :can-cancel="true"></b-loading>

  <div class="columns is-centered is-paddingless ">

    <!-- login -->
    <div class="column is-5 is-hiddenx" v-if="!loggedIn">
      <br />
      <br />
      <form class="notification is-white has-shadow is-radiusless">
        <h3 class="subtitle is-3 is-capitalized">login</h3>
        <hr />
        <b-field label="Username">
          <b-input v-model="username"></b-input>
        </b-field>
        <b-field label="Password">
          <b-input v-model="password" type="password"></b-input>
        </b-field>
        <b-button @click="login">Login</b-button>
      </form>
    </div>

    <!--  -->
  </div>

  </div>

</template>

Cosmetics

In `App.vue` style section we will add a minor style to improve our user experience.

html
<!-- App.vue -->
<style>
  body {
    background: #f1f1f1;
    height: 100vh;
    overflow-y: hidden;
    overflow-x: hidden;
  }

  #app {
    font-family: Avenir, Helvetica, Arial, sans-serif;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    color: #2c3e50;
  }

  .has-shadow {
    box-shadow: 2px 1px 19px 1px rgba(0, 0, 0, 0.06);
  }

  .is-vh {
    height: 100vh;
    overflow-y: hidden;
    overflow-x: hidden;
    position: relative;
  }

  .messagesBox {
    position: relative;
    height: 580px;
    overflow-x: auto;
  }

  .msgInput {
    position: absolute;
    bottom: 1px;
    left: 1px;
    display: block;
    z-index: 1003;
    overflow-y: hidden;
  }
</style>

Login to QuickBlox

In this step we will create a login function with a toast function for notification.

js
methods: {
  // toast for notification
  toast(type, message) {
    this.$buefy.toast.open({
      message: message,
      type: 'is-' + type
    })
  },

  login() {
    let self = this;
    var params = {
      login: this.username,
      password: this.password
    }
    QB.createSession(params, function (err, result) {
      // callback function
      if (err) {
        self.toast('danger', 'Session error: Can`t login to QB')
      } else {
        self.toast('success', 'Login success, loading messages')
        self.loggedIn = true;
        self.isLoading = true;

      }
    });
  },

}

It’s the time to put everything to test and make sure our login works.

Creating a messages interface

Soon as you are logged-in we can connect to a certain dialog (room, group) and retrieve messages

html

<!-- Messages -->
<div class="column is-5 is-marginless is-paddinglessx  is-vh" v-if="loggedIn">
  <br />
  <br />
  <div class="notification is-white has-shadow is-radiusless messagesBox ">
    <div v-if="isLoading">
      <b-skeleton v-for="(i,index) in 20" v-bind:key="index" :width="randomNumberx(10,70)+'%'"
        :animated="animated">
      </b-skeleton>
    </div>
    <!--  -->
    <article class="media" v-for="(i, index) in messages" v-bind:key="index">
      <figure class="media-left">
        <p class="image is-64x64 is-rouneded">
          <img :src="'https://i.pravatar.cc/64?img='+index" style="border-radius:50%;">
        </p>
      </figure>
      <div class="media-content">
        <div class="content">
          <p>
            <span class="is-capitalized"><strong>{{getUserName(i.sender_id)}}</strong></span> <small>{{ i.updated_at | moment("from", "now") }}</small>
            <br>
            <small>{{i.message}} {{i.body}}</small>
          </p>
        </div>
      </div>
    </article>
  </div>
  <!-- <b-input ></b-input> -->
  <input type="text" v-if="!isLoading" v-model="newMessage" class="input is-large  is-radiusless"
    @keyup.enter="createNewMessage()">
  <div>
  </div>
</div>

Connect to a channel or a dialog

In the next Vue code snippet, we are implementing a full QuickBlox workflow: login, getting a user’s ID, connecting to a dialog which can be one of three:

  • 1-1 dialog which acts like a direct message between two users;
  • group dialog is for group messaging;
  • public dialog that works similar to a public channel.

The next code will work the same for all the mentioned dialog types.

Our steps here will be as follow:

  1. Login: creating a login Session;
  2. Get the user details;
  3. Connect to a certain dialog;
  4. Retrieve the last messages;
  5. Send messages to the dialog.
js
 // methods

 login() {
   let self = this;
   var params = {
     login: this.username,
     password: this.password
   }
   QB.createSession(params, function (err, result) {
     // callback function
     if (err) {
       self.toast('danger', 'Session error: Can`t login to QB')
     } else {
       self.toast('success', 'Login success, loading messages')
       self.loggedIn = true;
       self.isLoading = true;
       self.getUserId(params.login, params.password)
     }
   });
 },
 getUserId(login, password) {
   var self = this;
   var searchParams = {
     login: login
   };
   QB.users.get(searchParams, function (error, user) {
     if (!error) {
       self.connect({
         userId: user.id,
         password: password
       })
     }else{
       self.toast('danger', 'Could not get the userID')
     }
   });
 },
 connect(userCredentials) {
   let self = this;
   QB.chat.connect(userCredentials, function (error, contactList) {
     if (!error) {

       self.toast('success', 'Dialog connection success')
       var roomId = CREDENTIALS.roomJID;
       // Join Specific Room
       QB.chat.muc.join(roomId, function (error, result) {
         if (error) {

            self.toast('danger', 'Could not join the dialog')
           return
         }
         self.toast('success', 'Connected to dialog: Success')

         var dialogId = result.dialogId
         // Getting Messages List
         self.getMessages(dialogId)
       });
     } else {
       self.toast('danger', 'QB Connection Error')
     }
   });
 },
 // Reterive the dialog messages
 getMessages(dialogId) {
   let self = this;
   self.toast('warning', 'Getting the Dialog Messages...')
   var params = {
     chat_dialog_id: dialogId,
     sort_desc: 'date_sent',
     limit: 10,
     skip: 0
   };
   QB.chat.message.list(params, function (error, messages) {
     if (!error) {
       self.toast('success', 'Retrieving messages: ' + messages.limit)
       self.isLoading = false;
       if (messages.limit > 0) {
         self.messages = _.reverse(messages.items);
         var userIDs = _.map(messages.items, (msg) => {
           return msg.sender_id
         })
         self.userIDs = userIDs;
         self.getUsers(userIDs)
       }
     } else {
        self.toast('error', 'Retrieving messages: error')
     }
   });
 }

Get User details

To get the user details like the full name and email , we have to access the users data through the API. Here we use QB.users.listUsers to list all the current users. We will save this in a separate collection.

js

getUsers(userIds) {
  let self = this;
  var searchParams = {
    filter: {
      field: 'id',
      param: 'in',
      value: userIds
    }
  };
  // Get user
  QB.users.listUsers(searchParams, function (error, result) {
    if (!error) {
      self.users = result.items
    } else {
      console.error('Could not get the user details [QB.users.listUsers]')

    }
  });
},
getUserName(id){
  var users = JSON.parse(JSON.stringify(this.users))
  var user = _.find(users,(o)=>{return o.user.id == id})
  if(user){
    return user.user.full_name;
  }

}

Send a new Message

The last step will handle sending a new message. It requires the dialog ID and few optional parameters. One of them is significant in-case you want to save the message on the server.

javascript

createNewMessage() {
  let self = this;
  var message = {
    type: "groupchat",
    body: self.newMessage,
    extension: {
      save_to_history: 1,
      dialog_id: CREDENTIALS.roomJID
    },
    markable: 1
  };
  var msgID = QB.chat.send(CREDENTIALS.roomJID, message);

}

Using LowDB as a local collection

You may notice that we didn’t use LowDB yet for this application. It can be used to save configurations, save certain JSON collections, perform search in a complex collection and of course as a localStorage interface.

Scroll to the recent message

We need to automate the scrolling to the last message.

js
computed: {
  ...
  //
  updated() {
    this.$nextTick(() => this.scrollToEnd());
  }
},

// methods
methods: {
  ...
  scrollToEnd: function () {

    var container = this.$el.querySelector(".messagesBox");
    container.scrollTop = container.scrollHeight;
  },
}

Conclusion

As We just scratched the serfece with this tutorial, We can see that building messaging application with Vue and QuickBlox is a hustle-free experience. QuickBlox is full of feature to create a rich messaging experiance which we can add easily with the JavaScript SDK.

The application can be extended with QuickBox WebRTC functionalities for video calling and conferencing apps.

With some tweaks, this Vue app can work on Desktop, deploy to a web server, or even build for mobile with Cordova.

Share article

Subscribe for news

Get the latest posts and read anywhere.


    Thanks for subscribing!

    You will receive an email shortly to verify your subscription.

    Check out your inbox!

    Read More

    Ready to get started?

    QUICKBLOX
    QuickBlox post-box