August 10, 2020

Build a Chat App with Laravel

Olususi Oluyemi

Introduction

Known for its elegant structure and ease of integration with modern JavaScript frameworks, such as React.js and Vue.js, Laravel enjoys wide acceptance from developers around the globe and remains one of the most relevant PHP frameworks in the PHP community. In this tutorial, we will take advantage of the infrastructure  put in place by CometChat to implement a chat feature for a Laravel application in no time. This will be a step by step guide that allows you to build authentication and authorization for each user before an access can be granted for participation in a chat session.


A sneak-peek into what you are going to build once are through with this tutorial:


This chat session allows registered and authenticated users to engage in a one-on-one conversation. This application will be built using Laravel and Vue.js. You can download the code for this project here on GitHub.


Prerequisites

Basic knowledge of building web applications with Laravel will help you get the best out of this tutorial. Also, ensure that you have:


Creating a new Laravel application

If you are yet to install the Laravel installer on your computer, run the following command to install it using composer:


composer global require laravel/installer


Once the installation process is complete, you will be able to use the laravel command for installing a new Laravel project. Proceed by using the command below to create a new Laravel project with some extra functionalities out of the box:


{% c-line %}laravel new laravel-chat-app --auth{% c-line-end %}


The preceding command will create a fresh Laravel installation in a directory named laravel-chat-app and place it in your development folder or where you ran the command from. Noticed the flag --auth? That was included to help create our application with all of the authentication scaffolding, which consist of the User model and migration file, Authentication controller, blade views for registration and login, main application layout file, and a default structure for Vue.js component and so on.


Install all javaScript dependencies including Vue.js with the command below:

{% c-block language="c" %}
// move into project
cd laravel-chat-app
{% c-block-end %}


{% c-block language="c" %}
// install dependencies
npm install
{% c-block-end %}


Create CometChat Account

If you haven’t created a CometChat account yet, click here to set up a free CometChat Pro account. Once you are done, create a new CometChat app from your dashboard by clicking on the Add New App button:


Enter the desired name for your application, select a region, technology, and a use case. Once you are done, click on the Add App button to complete the process.


This will automatically spin up a new application for you on CometChat. Depending on the technology selected from the previous step, CometChat will make provision for a quick start guide to facilitate integrating CometChat inside your app or website with ease. You can check it out and go for your preferred option.


Authentication within CometChat and your application

CometChat is by no means a user management solution. While it can maintain the session of the logged in user within the SDK, there is a limit to the authentication flow that can be handled by CometChat for your app. It is expected that authentication is managed for the users of your application before such a user is created or authenticated on CometChat.


To achieve this, we will make use of the CometChat Create user API to create a new user on CometChat once a user signs up in our application. And to log the user in, we will use the generated Auth Token specified for such user during the registration process. Consider this other method as the advanced authentication procedure for users on CometChat. More about this later in the tutorial.


Modify Migration file

If you open the project in your preferred code editor, you will noticed that a User model and its corresponding migration file has been generated already. We will need to make this conform to the structure of our application. Start by opening the migration file and replace its content with the following:


{% c-block language="php" %}
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateUsersTable extends Migration
{
   /**
    * Run the migrations.
    *
    *
@return void
    */
   public function up()
   {
       Schema::create('users', function (Blueprint $table) {
           $table->id();
           $table->string('username')->unique();
           $table->string('password');
           $table->string('authToken')->nullable();
           $table->rememberToken();
           $table->timestamps();
       });
   }
   /**
    * Reverse the migrations.
    *
    *
@return void
    */
   public function down()
   {
       Schema::dropIfExists('users')
   }
}
{% c-block-end %}


Here, we modified the content of this file to create fields for username, password and authToken in the database.


Update protected fillable

Next, open the User model in app/User.php file and modify the $fillable property to reflect this:


{% c-block language="php" %}
protected $fillable = [
   'username', 'password', 'authToken'
];
{% c-block-end %}


Next, with the User Model and migration file properly configured, go ahead and create a database for your application and update the .env file with its details:


DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=YOUR_DB_NAME
DB_USERNAME=YOUR_DB_USERNAME
DB_PASSWORD=YOUR_DB_PASSWORD


Ensure that you replace the YOUR_DB_NAME, YOUR_DB_USERNAME and YOUR_DB_PASSWORD placeholders with your credentials.


Next, issue the following command to run the migration file and create the appropriate fields in your database:


php artisan migrate


After running the preceding command, we are now set to start implementing the authentication logic for this application.


Backend authentication logic

In this section, we will modify the default authentication logic within Laravel to fit in into our use case. One of the reasons for the process is to return JSON response for the authentication controllers as this will be required to communicate with the frontend application that will be handled by Vue.js.


Start with the RegisterController found in app/Http/Controllers/Auth/RegisterController.php file and replace its content with the following code:


{% c-block language="php" %}
<?php
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use App\Providers\RouteServiceProvider;
use App\User;
use Illuminate\Auth\Events\Registered;
use Illuminate\Foundation\Auth\RegistersUsers;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Validator;
class RegisterController extends Controller
{
   use RegistersUsers;
   protected $redirectTo = RouteServiceProvider::HOME;
   /**
    * Create a new controller instance.

    *
    *
@return void
    */
   public function __construct()
   {
       $this->middleware('guest');
   }
   /**
    * Get a validator for an incoming registration request.
    *
    *
@param  array  $data
    *
@return \Illuminate\Contracts\Validation\Validator
    */
   protected function validator(array $data)
   {
       return Validator::make($data, [
           'username' => ['required', 'string', 'max:255', 'unique:users'],
           'password' => ['required', 'string', 'min:8', 'confirmed'],
       ]);
   }
   /**
    * Create a new user instance after a valid registration.
    *
    *
@param  array  $data
    *
@return \App\User
    */
   protected function create(array $data)
   {
       return User::create([
           'username' => $data['username'],
           'password' => Hash::make($data['password']),
       ]);
   }
   public function register(Request $request)
   {
       $this->validator($request->all())->validate();
       event(new Registered($user = $this->create($request->all())));
       if ($request->ajax() || $request->wantsJson()) {
           return response()->json([
               'user' => $this->guard()->user(),
               'status' => true
           ]);
       }
       return $request->wantsJson()
           ? new Response('', 201)
           : redirect($this->redirectPath());
   }
}
{% c-block-end %}



In the file above, we specified the required fields that should be validated during the registration process. And once the user was registered successfully, we returned a JSON response indicating the user’s details.


Update LoginController

Next, open the app/Http/Controllers/Auth/LoginController.php file and use the following code for it:


{% c-block language="php" %}
<?php
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use App\Providers\RouteServiceProvider;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
use Illuminate\Http\Request;
class LoginController extends Controller
{
   use AuthenticatesUsers;
   /**
    * Where to redirect users after login.
    *
    *
@var string
    */
   protected $redirectTo = RouteServiceProvider::HOME;
   /**
    * Create a new controller instance.
    *
    *
@return void
    */
   public function __construct()
   {
       $this->middleware('guest')->except('logout');
   }
   public function sendLoginResponse(Request $request)
   {
       $request->session()->regenerate();
       $this->clearLoginAttempts($request);
       if ($request->ajax() || $request->wantsJson()) {
           return response()->json([
               'user' => $this->guard()->user(),
           ]);
       }
       return $this->authenticated($request, $this->guard()->user())
           ?: redirect()->intended($this->redirectPath());
   }
   public function username()
   {
       return "username";
   }
}
{% c-block-end %}


We modified the logic here to ensure that users can log in by using their username instead of email. Also, once a user is logged in, we returned a User object as a JSON response.


Update Authentication Token

The last function that needs to be created for this application is the updateToken() method. This method will carry out the functionality of persisting the generated token to uniquely identify a user on CometChat into the database. Open the RegisterController.php file and include the method below immediately after the register() function:


{% c-block language="php" %}
<?php
...
class RegisterController extends Controller
{
   ...
   public function updateToken(Request $request) {
       $username = $request->get('uid');
       $token = $request->get('token');
       User::where('username', $username)->update([
           'authToken' => $token
       ]);
       return response()->json([
           'success' => true
       ]);
   }
}
{% c-block-end %}

For the backend, update the route file in routes/web.php by including the following:

Route::post('/update/token', 'Auth\RegisterController@updateToken')->name('updateToken');


Frontend

As mentioned, Vue.js will be used to handle frontend logics and communication with the javaScript SDK of CometChat. We have already install Vue.js and its dependencies earlier, so we will proceed to install the CometChat javaScript SDK using the following command:


{% c-line %}npm install @cometchat-pro/chat --save{% c-line-end %}


Once the installation is complete, navigate back into the Laravel application and add the following variables to the .env file:


MIX_COMMETCHAT_API_KEY=YOUR_COMMETCHAT_API_KEY
MIX_COMMETCHAT_APP_ID=YOUR_COMMETCHAT_APP_ID
MIX_COMMETCHAT_APP_REGION=YOUR_COMETCHAT_APP_REGION


Replace the placeholders with the appropriate details obtained from your CometChat dashboard. Please be sure to use the value of your REST API Key instead of the Auth Key:



Initialize CometChat App

To initialize CometChat, open the resources/js/app.js file and use the following code for it:


{% c-block language="javascript" %}
require
('./bootstrap');
window.Vue = require('vue');
import { CometChat } from "@cometchat-pro/chat/CometChat";
let cometChatAppSetting = new CometChat.AppSettingsBuilder()
   .subscribePresenceForAllUsers()
   .setRegion(process.env.MIX_COMMETCHAT_APP_REGION)
   .build();
CometChat.init(process.env.MIX_COMMETCHAT_APP_ID, cometChatAppSetting).then(
   () => {
       console.log("Initialization completed successfully");
       const app = new Vue({
           el: '#app',
       });
   },
   (error) => {
       console.log("Initialization failed with error:", error);
   }
);
{% c-block-end %}


Creating views and Cloning the UI Kit for Vue

In this section, we will create login, register and a chat view for users. To begin, create a folder named views within resources/js folder and create the following files within the newly created folder:


  • Register.vue
  • Login.vue
  • Chat.vue


Lastly, we will leverage on the UI Kit created by CometChat team to set up our chat view. This comes with the benefit of an appealing user interface and a proper structure for chat applications. To use the kit, clone or download it from this repository using the following command:


{% c-line %} git clone https://github.com/cometchat-pro/vue-chat-ui-kit.git {% c-line-end %}


Once you are done, open it with a code editor or any file explorer and copy the cometchat-components folder and paste it in resources/js folder. We will reference some components from the file as required.


Register view

Open the Register.vue and paste the following content in it:


{% c-block language="xml" %}
<template>
   <div class="login-page">
       <div class="login">
           <div class="register-container auth-container">
               <div class="register-image-column">
                   <div class="image-holder">
                       <img src="#" alt="">
                   </div>
               </div>
               <div class="register-form-column">
                   <form v-on:submit.prevent="registerAppUser">
                       <h3>Create an Account</h3>
                       <div class="form-wrapper">
                           <label for="username">Username</label>
                           <input type="text" name="username" id="username" v-model="username" placeholder="Enter your username" class="form-control" required>
                       </div>
                       <div class="form-wrapper">
                           <label for="password">Password</label>
                           <input type="password" name="password" id="password" v-model="password" placeholder="Enter your password" class="form-control" required>
                       </div>
                       <div class="form-wrapper">
                           <label for="password_confirmation">Confirm Password</label>
                           <input type="password" name="password_confirmation" id="password_confirmation" v-model="password_confirmation" placeholder="Re-enter password" class="form-control" required>
                       </div>
                       <button type="submit" class="mt-3">SIGN UP &nbsp;&nbsp;<span v-if="showSpinner" class="fa fa-spin fa-spinner"></span> </button>
                   </form>
               </div>
           </div>
       </div>
   </div>
</template>
{% c-block-end %}

This  <template></template> section of the file contains the HTML form and the input fields for username and password.

Next, paste the following code immediately after the template section:


{% c-block language="xml" %}
<script>
   export default {
       data() {
           return {
               username: "",
               password: '',
               password_confirmation: '',
               showSpinner: false,
           };
       },
       methods: {
           registerAppUser() {
               if (this.username && this.password && this.password_confirmation) {
                   this.showSpinner = true;
                   if (this.password && this.password_confirmation) {
                       let data = {
                           username: this.username,
                           password: this.password,
                           password_confirmation: this.password_confirmation
                       };
                       axios.post(`http://localhost:8000/register`, data)
                           .then(response => {
                               console.log(response.data.status);
                               if (response.data.status) {
                                   this.createUserOnCometChat(this.username);
                               }
                               this.showSpinner = false;
                           }).catch(error => {
                           console.log(error.response.data.message);
                           this.showSpinner = false;
                       })
                   }
               }
           },
           redirect() {
                  window.location.href = '/login';
           },
           async createUserOnCometChat(username) {
               let url = `https://api-us.cometchat.io/v2.0/users`;
               let data = {
                   uid: username,
                   name: `${username} sample`,
                   avatar: 'https://data-us.cometchat.io/assets/images/avatars/captainamerica.png',
               };
               try {
                   const userDetails = await fetch(url, {
                       method: 'POST',
                       headers: new Headers({
                           appid: process.env.MIX_COMMETCHAT_APP_ID,
                           apikey: process.env.MIX_COMMETCHAT_API_KEY,
                           'Content-Type': 'application/json'
                       }),
                       body: JSON.stringify(data),
                   });
                   const userJson = await userDetails.json();
                   console.log('New User', userJson);
                   this.createAuthTokenAndSaveForUser(username);
               } catch (error) {
                   console.log('Error', error);
               }
           },
           async createAuthTokenAndSaveForUser(uid) {
               let url = `https://api-us.cometchat.io/v2.0/users/${uid}/auth_tokens`;
               try {
                   const tokenDetails = await fetch(url, {
                       method: 'POST',
                       headers: new Headers({
                           appid: process.env.MIX_COMMETCHAT_APP_ID,
                           apikey: process.env.MIX_COMMETCHAT_API_KEY,
                           'Content-Type': 'application/json'
                       }),
                   });
                   const tokenJSON = await tokenDetails.json();
                   console.log(tokenJSON);
                   this.sendTokenToServer(tokenJSON.data.authToken, tokenJSON.data.uid);
               } catch (error) {
                   console.log('Error Token', error);
               }
           },
       }
   };
</script>
{% c-block-end %}

As mentioned, the authentication flow for this application is to register users within it and also create such user immediately on CometChat using the Create User REST API. Here, we created the registerAppUser() to register users within our application. And once that is successful, we used the createUserOnCometChat() method to create the user on CometChat with the same unique username. We then proceeded to create an AuthToken for such user. This token will be used for authentication before such a user can be allowed to participate in a chat session.


Lastly, add the method below to save the generated token in the database for the user:


{% c-block language="xml" %}
<script>
   export default {
       data() {
         ...
       },
       methods: {
         ...
           sendTokenToServer(token, uid) {
               axios.post(`http://localhost:8000/update/token`, {token, uid})
                   .then(response => {
                       console.log("Token updated successfully", response);
                       this.redirect();
                   }).catch(error => {
                       console.log(error.response.data.message);
               })
           }
       }
   };
</script>
{% c-block-end %}


Login View

Open the Login.vue file and paste the code below in it:


{% c-block language="xml" %}
<template>
   <div class="login-page">
       <div class="login">
           <div class="login-container auth-container">
               <div class="login-form-column">
                   <form v-on:submit.prevent="authLoginAppUser">
                       <h3>Hello!</h3>
                       <div class="form-wrapper">
                           <label>Username</label>
                           <input type="text" name="username" id="username" v-model="username" placeholder="Enter your username" class="form-control" required>
                       </div>
                       <div class="form-wrapper">
                           <label for="password">Password</label>
                           <input type="password" name="password" id="password" v-model="password" placeholder="******" class="form-control" required>
                       </div>
                       <button type="submit" class="mt-3">LOG IN &nbsp;&nbsp;<span v-if="showSpinner" class="fa fa-spin fa-spinner"></span> </button>
                   </form>
               </div>
               <div class="login-image-column">
                   <div class="image-holder">
                       <img src="#" alt="">
                   </div>
               </div>
           </div>
       </div>
   </div>
</template>
{% c-block-end %}


We created the input fields for username and password. Next paste the following  <script></script> that contains the logic to login a user:


{% c-block language="xml" %}
<script>
   import { CometChat } from "@cometchat-pro/chat";
   export default {
       data() {
           return {
               username: "",
               password: '',
               showSpinner: false,
               token: '',
           };
       },
       methods: {
           authLoginAppUser() {
               let userData = {
                   username: this.username,
                   password: this.password
               };
               this.showSpinner = true;
               if (this.username && this.password) {
                   axios.post(`http://localhost:8000/login`, userData).then(response => {
                       this.logUserInToCometChat(response.data.user.authToken);
                       this.showSpinner = false;
                   }).catch(error => {
                       console.log(error.response.data.message);
                       this.showSpinner = false;
                   })
               } else {
                   console.log('Please check your credentials');
               }
           },
           logUserInToCometChat(token) {
               CometChat.login(token).then(
                   () => {
                       console.log("successfully login user");
                       window.location.href = '/home';
                   },
                   error => {
                       this.showSpinner = false;
                       alert("Whops. Something went wrong. This commonly happens when you enter a username that doesn't exist. Check the console for more information");
                       console.log("Login failed with error:", error.code);
                   }
               );
           },
       }
   };
</script>
{% c-block-end %}


Once a user can log in successfully into our application, we will retrieve the token generated earlier and use it to authenticate such user on CometChat.


Chat view

To create a structure for the chat view, start by pasting the following code in resources/views/Chat.vue:


{% c-block language="javascript" %}
<template>
   <div class="page-wrapper">
       <div class="page-int-wrapper" id="pageWrapper" :class="{ 'left-open': leftOpen, 'center-open': centerOpen, 'right-open': rightOpen }">
           <div class="ccl-left-panel">
               <UserList />
           </div>
           <MessageContainer :currentUser=currentUser />
           <RightSidebar />
       </div>
   </div>
</template>
{% c-block-end %}


Here, we created a structure that brings together different UI components to represent and build a chat view of our application. Each of the components referenced here is from the UI kit downloaded earlier.


Next, update the <script></script> section with:


{% c-block language="xml" %}
<script>
   import { CometChat } from "@cometchat-pro/chat";
   import UserList from "../cometchat-components/components/UserList";
   import MessageContainer from "../cometchat-components/components/MessageContainer";
   import RightSidebar from "../cometchat-components/components/RightSidebar";
   export default {
       name: 'ContactScreen',
       components: {
           UserList,
           MessageContainer,
           RightSidebar,
       },
       data() {
           return {
               currentUser: null,
               leftOpen: true,
               centerOpen: false,
               rightOpen: false
           }
       },
       created() {
           CometChat.getLoggedinUser().then(user => {
               if (user) {
                   this.currentUser = user;
               }
           }, error => {
               console.log('yes here', error);
           });
       },
       mounted() {
           this.$root.$on("selectedUser", data => {
               console.log(data);
               const el  = document.getElementById('pageWrapper');
               if (el.classList.contains("left-open")) {
                   el.classList.add("center-open");
                   el.classList.remove("left-open");
               }
           });
       },
   }
</script>
{% c-block-end %}

First, we imported CometChat SDK and three different components from the cometchat-components folder:

  • UserList: This component will list the number of registered users within your app on CometChat. With that, a user can easily select a particular user he or she wishes to start a chat with.
  • MessageContainer: This is a very important component for the chat view. It holds the logic to render different message types (Video, Audio, Media, Text) sent to a user during a chat. It has a structure that houses the header of a chat view, the body, that is, the message sent in a conversation and finally the form with an input fields where messages for a chat are composed.
  • RightSidebar: This component house the sidebar on the right hand side of the chat view. It is hidden by default and for the sake of this tutorial, we won’t focus on it.


Next, we used the getLoggedinUser() method from the CometChat() class to retrieve the details of the currently logged in user.


Import all the created components

So far, we have built the user interface into smaller Vue.js components and before we can make use of them within the appropriate Blade templates, register them as Vue.js components, by adding them to resources/js/app.js as shown here:

{% c-block language="php" %}
...
Vue.component('login-component', require('./views/Login.vue').default);
Vue.component('register-component', require('./views/Register.vue').default);
Vue.component('chat-component', require('./views/Chat.vue').default);
...
{% c-block-end %}


Modifying Laravel Blade template

Here, we will make use of all the components created so far within each blade file from Laravel.


Login Blade file

Start with the login.blade.php file in resources/views/auth folder and paste the following content in it:


{% c-block language="javascript" %}
@extends('layouts.app')
@section('content')
<div class="container mt-5">
   <div class="row justify-content-center">
       <div class="col-md-8">
           <div class="card">
               <div class="card-header">{{ __('Login') }}</div>
               <div class="card-body">
                   <login-component></login-component>
               </div>
           </div>
       </div>
   </div>
</div>
@endsection
{% c-block-end %}


Register

Use the content below for resources/views/auth/register.blade.php:


{% c-block language="javascript" %}
@extends('layouts.app')
@section('content')
<div class="container mt-5">
   <div class="row justify-content-center">
       <div class="col-md-8">
           <div class="card">
               <div class="card-header">{{ __('Register') }}</div>
               <div class="card-body">
                   <register-component></register-component>
               </div>
           </div>
       </div>
   </div>
</div>
@endsection
{% c-block-end %}


Home

Finally, render the chat component within resources/views/home.blade.php


{% c-block language="javascript" %}
@extends('layouts.app')
@section('content')
<div class="">
   <chat-component></chat-component>
</div>
@endsection
{% c-block-end %}


Welcome page

Change the content rendered on the homepage by replacing the contents of resources/views/welcome.blade.php file with the following:

{% c-block language="javascript" %}
@extends('layouts.app')
@section('content')
   <div class="mt-5">
       <div class="row justify-content-center">
           <div class="col-md-8">
               <div class="card">
                   <div class="card-header">Vuejs Chat Application</div>
                   <div class="card-body">
                       <div>
                           <p> Welcome! </p>
                           <p> Login / Register using the link above </p>
                       </div>
                   </div>
               </div>
           </div>
       </div>
   </div>
@endsection
{% c-block-end %}


Update Stylesheet

Replace the content of resources/sass/app.scss file with:


{% c-block language="css" %}
// Fonts
@import url('https://fonts.googleapis.com/css?family=Nunito');
{% c-block-end %}


{% c-block language="css" %}
// Variables

@import 'variables';
{% c-block-end %}


{% c-block language="css" %}
// Bootstrap
@import '~bootstrap/scss/bootstrap';
@import "../js/cometchat-components/assets/css/style.css";
@import url("https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css");
.cc1-chat-win-inpt-ext-wrap {
   bottom: 55px !important;
}
.cc1-chat-win-conver-wrap {
   bottom: 55px !important;
}
body {
   font-size: 1.4rem !important;
}
input, nav {
   font-size: 1.4rem !important;
}
{% c-block-end %}


Layout file

To update the Layout file. Replace the content of Layout.blade with the following:


{% c-block language="swift" %}
<!doctype html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
   <meta charset="utf-8">
   <meta name="viewport" content="width=device-width, initial-scale=1">
   <!-- CSRF Token -->
   <meta name="csrf-token" content="{{ csrf_token() }}">
   <title>{{ config('app.name', 'Laravel') }}</title
 <!-- Scripts -->
   <script src="{{ asset('js/app.js') }}" defer></script>
   <!-- Fonts -->
   <link rel="dns-prefetch" href="//fonts.gstatic.com">
   <link href="https://fonts.googleapis.com/css?family=Nunito" rel="stylesheet">
   <!-- Styles -->
   <link href="{{ asset('css/app.css') }}" rel="stylesheet">
</head>
<body>
   <div id="app">
       <nav class="navbar navbar-expand-md navbar-light bg-white shadow-sm">
           <div class="container">
               <a class="navbar-brand" href="{{ url('/') }}">
                   {{ config('app.name', 'Laravel') }}
               </a>
               <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="{{ __('Toggle navigation') }}">
                   <span class="navbar-toggler-icon"></span>
               </button>
               <div class="collapse navbar-collapse" id="navbarSupportedContent">
                   <!-- Left Side Of Navbar -->
                   <ul class="navbar-nav mr-auto">
                   </ul>
                   <!-- Right Side Of Navbar -->
                   <ul class="navbar-nav ml-auto">
                       <!-- Authentication Links -->
                       @guest
                           <li class="nav-item">
                               <a class="nav-link" href="{{ route('login') }}">{{ __('Login') }}</a>
                           </li>
                           @if (Route::has('register'))
                               <li class="nav-item">
                                   <a class="nav-link" href="{{ route('register') }}">{{ __('Register') }}</a>
                               </li>
                           @endi
                       @else
                           <li class="nav-item dropdown">
                               <a id="navbarDropdown" class="nav-link dropdown-toggle" href="#" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" v-pre>
                                   {{ Auth::user()->name }} <span class="caret"></span>
                               </a>
                               <div class="dropdown-menu dropdown-menu-right" aria-labelledby="navbarDropdown">
                                   <a class="dropdown-item" href="{{ route('logout') }}"
                                      onclick="event.preventDefault();
                                                    document.getElementById('logout-form').submit();">
                                       {{ __('Logout') }}
                                   </a>
                                   <form id="logout-form" action="{{ route('logout') }}" method="POST" style="display: none;">
                                       @csrf
                                   </form>
                               </div>
                           </li>
                       @endguest
                   </ul>
               </div>
           </div>
       </nav>
       <main>
           @yield('content')
       </main>
   </div>
</body>
</html>
{% c-block-end %}


Test the application

Open different browser and run the command below to start the Laravel application:


php artisan serve


Next, to compile and start the frontend application use the following command:


npm run watch


Now, navigate to http://localhost:8000, to view the application in your browser:



Register Users

Go ahead and register as a new user. You can create two separate accounts for testing purposes:




Log in, select a user and start a chat

Now, login and select a user to chat with. You will have a page similar to the one depicted by this image:



Conclusion

Irrespective of the size of your application, you can easily implement a chat feature with CometChat SDK. As seen in this tutorial, we started with a non functional Laravel application, gradually built authentication, programmatically created a user and completed the application by including a chat feature. The complete source code can be found here on GitHub. Please feel free to clone it and improve on its existing features.