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.
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
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)
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')
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.
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: '.................................', }
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() } }
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.
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>
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>
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.
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>
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:
The next code will work the same for all the mentioned dialog types.
Our steps here will be as follow:
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') } }); }
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; } }
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); }
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.
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; }, }
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.