DEV Community

Cover image for Laravel Reverb: make a chatbox component for your site!
Omar Malas
Omar Malas

Posted on

Laravel Reverb: make a chatbox component for your site!

Laravel 11 was released a few weeks ago and with it is laravel reverb, a first-party websocket package to help with real-time applications.
In this article I'll demonstrate how to make a simple chatbox component for support-related purposes...

first off we'll create a new laravel application using laravel new

laravel new chatbox
cd chatbox
Enter fullscreen mode Exit fullscreen mode

then after all installation is complete we can use the new command to install laravel reverb

php artisan install:broadcasting
Enter fullscreen mode Exit fullscreen mode

make sure the .env file has this line set to sync

QUEUE_CONNECTION=sync
Enter fullscreen mode Exit fullscreen mode

next all we have to do is to create an event and listen on its channel

php artisan make:event MessageSent
Enter fullscreen mode Exit fullscreen mode

and make it look something like this

<?php

namespace App\Events;

use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;

class MessageSent implements ShouldBroadcast
{
    use Dispatchable, InteractsWithSockets, SerializesModels;

    /**
     * Create a new event instance.
     */
    public function __construct( public string $name, public string $text)
    {
        //
    }

    /**
     * Get the channels the event should broadcast on.
     *
     * @return array<int, \Illuminate\Broadcasting\Channel>
     */
    public function broadcastOn(): array
    {
        return [
            new Channel('messages'),
        ];
    }
}
Enter fullscreen mode Exit fullscreen mode

next we create the livewire component to listen on the channel

php artisan make:volt ChatBox --class
Enter fullscreen mode Exit fullscreen mode

and make it like so...

<?php
use App\Events\MessageSent;
use Livewire\Volt\Component;
new class extends Component
{
    /**
     * @var string[]
     */
    public array $messages = [];
    public string $message = '';
    protected $listeners = ['echo:messages,MessageSent' => 'onMessageSent'];
    public function addMessage()
    {
        MessageSent::dispatch(auth()->user()->name, $this->message);
        $this->reset('message');
    }
    #[On('echo:messages,MessageSent')]
    public function onMessageSent($event)
    {
        $this->messages[] = $event;
    }
}
?>

<div x-data="{ open: true }" >
    <div :class="{'-translate-y-0': open, 'translate-y-full': !open}" class="fixed transition-all duration-300 transform bottom-10 right-12 h-60 w-80">
        <div class="mb-2">
            <button @click="open = !open" type="button" :class="{ 'text-indigo-600 dark:text-white hover:bg-transparent': open }" class="w-full text-start flex items-center gap-x-3.5 py-2 px-2.5 text-sm text-white rounded-lg hover:bg-indigo-400 dark:bg-indigo-600 dark:hover:bg-indigo-400">
                Chat

                <x-heroicon-o-chevron-up x-show="!open" x-cloak class="ms-auto block size-4" />
                <x-heroicon-o-chevron-down x-show="open" x-cloak class="ms-auto block size-4" />

            </button>
        </div>
        <div class="w-full h-full bg-white dark:bg-gray-800 border border-gray-300 dark:border-gray-700 rounded overflow-auto flex flex-col px-2 py-4">
            <div x-ref="chatBox" class="flex-1 p-4 text-sm flex flex-col gap-y-1">
                @foreach($messages as $message)
                    <div><span class="text-indigo-600">{{ $message['name'] }}:</span> <span class="dark:text-white">{{ $message['text'] }}</span></div>
                @endforeach
            </div>
            <div>
                <form wire:submit.prevent="addMessage" class="flex gap-2">
                    <x-text-input wire:model="message" x-ref="messageInput" name="message" id="message" class="block w-full" />
                    <x-primary-button>
                        Send
                    </x-primary-button>
                </form>
            </div>
        </div>
    </div>
</div>
Enter fullscreen mode Exit fullscreen mode

next we add it anywhere to the welcome page of the default laravel, and we need to start the reverb server...

php artisan serve
Enter fullscreen mode Exit fullscreen mode

and on another terminal

php artisan reverb:start
Enter fullscreen mode Exit fullscreen mode

and we are all set!
the chatbox should be working and all should be complete

Top comments (1)

Collapse
 
xwero profile image
david duymelinck • Edited

I would have loved it to be that easy, but i ran into some difficulties.
I'm using ddev for my project, instead of running it on my OS. So some of the problems could be caused by this setup.

I'm not a laravel expert so some of the things are due to my lack of knowledge.

The first thing I encountered was the creation of the livewire component. I started from a fresh laravel 11 installation so i needed to add livewire and volt.

For people, like me, who are not that familiar with livewire. The way to add the volt component is;

<livewire:chatbox />
Enter fullscreen mode Exit fullscreen mode

The next thing I got an error on was x-heroicon-o-chevron-up in the volt component.
After a quick search I found it came from github.com/blade-ui-kit/blade-hero.... So I added that.

The next things where x-text-input and x-primary-button. To get it running as fast as possible I just converted them to plain html tags

<input type="text" wire:model="message" x-ref="messageInput" name="message" id="message" class="block w-full" />
<button type="submit">Send</button>
Enter fullscreen mode Exit fullscreen mode

Now I could see the page without errors, and the component was visible. When I added some text and clicked the send button, I got an error on the MessageSent::dispatch(auth()->user()->name, $this->message); line of the volt component. So i replaced getting the user name with a static string.

update:

Adding the following to .ddev/config.yaml exposed the port

hooks:
  post-start:
    - exec: "php artisan reverb:start"
web_extra_exposed_ports:
  - name: reverb
    container_port: 8080
    http_port: 8080
    https_port: 8080
Enter fullscreen mode Exit fullscreen mode

My ddev app is also named reverb so I don't need other urls.

After sending a message I couldn't see a change. In the browser console I got the error log; couldn't find Echo.
The fix was to add @vite('resources/js/app.js') to the page template.

I didn't look for the reason that wsHost: import.meta.env.VITE_REVERB_HOST in resources/js/echo.js translated to localhost during the build, so I changed it to reverb.ddev.site.

Now I can send a message and see it. But when I want to send a second message I get an internal server error: Pusher error: Internal server error.. {"exception":"[object]

So it almost works, but now I hit a wall because the error log is not helpful.