Black Friday: coupon FRIDAY24 for 40% off Yearly/Lifetime membership! Read more here
Courses

Laravel Reverb: Four "Live" Practical Examples

There are many customer support chat solutions, but sometimes you need something simple. For that, we can use Reverb and create a chat around it:

On the admin side, the administrator user will be able to see the chat requests and reply to them:

With this solution, we don't need to use any third-party free/paid software. We also have complete control over how it works/looks of what happens. Finally, all the data stays on our servers.


Project Overview

Our demo project contains two critical parts in the application:

On the user side - we have a chatbox that will be used to send messages to the support team:

Chatbox has this code inside:

Note: Repository is linked at the end of the tutorial.

<div class="fixed bottom-2 right-2 bg-blue-900 rounded-xl"
style="width: 64px; height: 64px;">
<button id="chatbox-button" class="mx-auto flex justify-center items-center "
style="width: 64px; height: 64px;">
</button>
</div>
<div id="chatbox-container" class="hidden fixed bottom-24 right-2 bg-gray-200 border-2 border-blue-400"
style="min-width: 400px; max-width: 30%; height: 600px">
<div class="p-6 flex flex-col justify-between h-full">
<div class="pb-4 mb-4 border-b-2 border-b-gray-400">
<h2 class="text-2xl text-center">Chat with Customer Support</h2>
</div>
<div class="overflow-y-scroll h-full" id="messagesList">
<div class="">
<div class="font-bold">System</div>
<p>
Hello, how can we help you?
</p>
</div>
</div>
<div class="pt-4 mt-4 border-t-2 border-t-gray-400">
<textarea id="message" class="w-full"></textarea>
<button id="sendMessage" class="w-full bg-blue-300 py-2">Send Message</button>
</div>
</div>
</div>
 
<script type="text/html">
<div class="_POSITION_">
<div class="font-bold">_SENDER_</div>
<p>MESSAGE</p>
</div>
</script>
 
<script>
const MESSAGE_ICON = `
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="-3 -2 32 32" fill="none" stroke="#FFFFFF" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-mail p-0 m-0">
<path d="M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z"></path>
<polyline points="22,6 12,13 2,6"></polyline>
</svg>
`;
 
const CLOSE_ICON = `
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="-3 -2 32 32" fill="#FFFFFF" stroke="#FFFFFF" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-x p-0 m-0">
<line x1="18" y1="6" x2="6" y2="18"></line>
<line x1="6" y1="6" x2="18" y2="18"></line>
</svg>
`;
 
// Set the session identifier
// This acts as "rooms" for now, and will be cleared on page refresh
let identifier = '{{ auth()->id() }}-{{ uniqid() }}';
 
// Add default chatbox button icon as soon as page loads
const chatboxButton = document.getElementById('chatbox-button');
chatboxButton.innerHTML = MESSAGE_ICON;
 
// Add event listener to chatbox button (open/close chatbox)
document.getElementById('chatbox-button').addEventListener('click', function () {
const chatboxContainer = document.getElementById('chatbox-container');
chatboxContainer.classList.toggle('hidden');
if (chatboxContainer.classList.contains('hidden')) {
chatboxButton.innerHTML = MESSAGE_ICON;
} else {
chatboxButton.innerHTML = CLOSE_ICON;
}
})
 
 
// Send the message on sendMessage button click
document.getElementById('sendMessage').addEventListener('click', function () {
const message = document.getElementById('message').value;
const messagesList = document.getElementById('messagesList');
const messageTemplate = document.querySelector('script[type="text/html"]').innerHTML;
 
// Post the message to the server
fetch('{{ route('send-message') }}', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').getAttribute('content')
},
body: JSON.stringify({message: message, identifier: identifier})
})
.then(() => {
const newMessage = messageTemplate
.replace('_POSITION_', 'text-right')
.replace('_SENDER_', 'You')
.replace('MESSAGE', message);
messagesList.innerHTML += newMessage;
 
messagesList.scrollTop = messagesList.scrollHeight;
 
document.getElementById('message').value = '';
});
});
</script>

On the support side (admin), we have a list of all user-created chat rooms. From there, we can go inside the chat room and see all the messages that were sent:

We are simply using a controller and a table to display all the chat rooms:

app/Http/Controllers/CustomerChatsController.php

// ...
 
public function index()
{
$chatRooms = ChatRoom::query()
->with(['user'])
->withCount('chatMessages')
->orderBy('updated_at', 'desc')
->paginate(15);
 
return view('chatRooms.index', compact('chatRooms'));
}
 
// ...

resources/views/chatRooms/index.blade.php

{{-- ... --}}
 
<table class="w-full">
<thead>
<tr>
<th class="border px-4 py-2">ID</th>
<th class="border px-4 py-2">User Name</th>
<th class="border px-4 py-2">Message Count</th>
<th class="border px-4 py-2">Last Update</th>
<th class="border px-4 py-2">Actions</th>
</tr>
</thead>
<tbody>
@foreach ($chatRooms as $chatRoom)
<tr>
<td class="border px-4 py-2">{{ $chatRoom->identifier }}</td>
<td class="border px-4 py-2">{{ $chatRoom->user->name }}</td>
<td class="border px-4 py-2">{{ $chatRoom->chat_messages_count }}</td>
<td class="border px-4 py-2">{{ $chatRoom->updated_at }}</td>
<td class="border px-4 py-2">
<a href="{{ route('chatRooms.show', $chatRoom->id) }}"
class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded">View</a>
</td>
</tr>
@endforeach
</tbody>
</table>
 
{{-- ... --}}

The chat room has this code...

This lesson is only for Premium Members.
Want to access all lessons of this course?

You also get:

  • 67 courses (1172 lessons, 43 h 18 min total)
  • Premium tutorials
  • Access to repositories
  • Private Discord