May 22, 2025
0
Level 1
livewire not updating chat when sending messages
Hello everyone. My stack is laravel 12, reverb, livewire. The problem is that my chat does not update when sending messages. I see through DevTools that messages are coming and everything works on the backend level. It seems to me that Livewire just does not respond to websocket messages
Code:
AdminChat.php:
<?php
namespace App\Livewire\Chat;
use App\Events\Chat\MessageSent;
use App\Models\ChatMessage;
use App\Models\Project;
use Livewire\Component;
class AdminChat extends Component
{
public $projects;
public $selectedProject;
public $newMessage;
public $messages;
public function mount()
{
$this->projects = Project::query()->where('status', ['created', 'working', 'completed'])
->select(['id', 'price', 'status', 'created_at', 'updated_at',])->latest()->get();
$this->selectedProject = $this->projects->first() ?: null;
$this->loadMessages();
}
public function loadMessages()
{
$this->messages = ChatMessage::query()
->where('project_id', $this->selectedProject->id)
->orderBy('created_at')
->get();
}
public function submit()
{
if (!$this->newMessage) {
return;
}
$message = ChatMessage::query()->create([
'project_id' => $this->selectedProject->id,
'sender_id' => auth()->id(),
'receiver_id' => $this->selectedProject->user_id,
'message' => $this->newMessage,
]);
$this->messages->push($message);
broadcast(new MessageSent($message));
$this->newMessage = '';
}
public function getListeners(): array
{
return ["echo-private:chat.{$this->selectedProject->id},MessageSent" => 'newChatMessageNotification'];
}
public function newChatMessageNotification($message): void
{
if ($message['sender_id'] == $this->selectedProject->user_id) {
$messageObj = ChatMessage::find($message['id']);
$this->messages = collect($this->messages)->push($messageObj)->unique('id')->values();
}
}
public function selectProject($id): void
{
$this->selectedProject = Project::find($id);
$this->loadMessages();
}
public function render()
{
return view('livewire.chat.admin-chat');
}
}
admin-chat.blade.php:
<div class="h-screen flex border rounded-xl overflow-hidden shadow-sm">
<div class="w-1/3 flex flex-col border-r bg-white dark:bg-gray-900">
<div class="p-4">
<div class="relative">
<input
type="text"
placeholder="Поиск..."
class="w-full pl-10 pr-4 py-2 mt-2 border border-gray-300 rounded-lg dark:border-gray-600 bg-white dark:bg-gray-800 text-sm focus:outline-none focus:ring-2 focus:ring-primary-500"
/>
<svg class="absolute left-3 top-1/2 transform -translate-y-1/2 w-5 h-5 text-gray-400" fill="none"
stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M21 21l-4.35-4.35M11 19a8 8 0 100-16 8 8 0 000 16z"/>
</svg>
</div>
</div>
@if($projects->isEmpty())
<div class="p-4 text-center text-gray-500 dark:text-gray-400">
Чатов нет
</div>
@else
@foreach($projects as $project)
<div
wire:click="selectProject({{ $project->id }})"
wire:key="project-{{ $project->id }}"
class="p-4 hover:bg-gray-100 dark:hover:bg-gray-800 cursor-pointer {{ $selectedProject && $selectedProject->id === $project->id ? 'bg-gray-900' : 'bg-gray-800' }}">
<div class="flex items-center gap-3">
<img src="https://ui-avatars.com/api/?name=Support+Agent" alt="Avatar"
class="w-8 h-8 rounded-full">
<div class="flex-1 min-w-0">
<p class="font-semibold text-sm">Заказ № {{ $project->id }}</p>
<p class="text-sm text-gray-500 truncate">
Здравствуйте, вы прошли верификацию ✅
</p>
</div>
<span class="text-xs text-gray-400 flex-shrink-0">10:10</span>
</div>
</div>
@endforeach
@endif
</div>
<div class="w-2/3 flex flex-col bg-white dark:bg-gray-950">
@if($selectedProject)
<div class="p-4 border-b flex items-center gap-3">
<img src="https://ui-avatars.com/api/?name=Support+Agent" alt="Avatar"
class="w-8 h-8 rounded-full">
<div class="flex flex-col">
<p class="font-semibold text-sm">Заказ №{{ $selectedProject->id }}</p>
</div>
</div>
@endif
<div class="flex-1 p-4 space-y-4 overflow-y-auto">
@if($messages->isEmpty())
<div class="text-center text-gray-500 dark:text-gray-400 mt-4">
Сообщений пока нет
</div>
@else
@foreach($messages as $message)
<div
class="flex {{ $message->sender_id === auth()->user()->id ? 'justify-end' : 'justify-start' }}">
<div
class="{{ $message->sender_id === auth()->user()->id ? 'bg-primary-600' : 'bg-gray-400' }} text-white rounded-xl p-3">
<p class="text-sm">{{ $message->message }}</p>
</div>
</div>
@endforeach
@endif
</div>
@if($selectedProject)
<div class="p-4 border-t">
<form class="flex items-center gap-2" wire:submit="submit">
<input
wire:model="newMessage"
type="text"
placeholder="Твоё сообщение..."
class="flex-1 px-4 py-2 border border-gray-300 dark:border-gray-600 rounded-lg text-sm bg-white dark:bg-gray-800 focus:outline-none focus:ring-2 focus:ring-primary-500"
/>
<button type="submit"
class="px-3 py-2 bg-primary-600 text-white rounded-lg hover:bg-primary-700 transition duration-150 ease-in-out">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M3 10l9 2-9 2v4l13-6-13-6v4z"/>
</svg>
</button>
</form>
</div>
@endif
</div>
</div>
MessageSent.php:
<?php
namespace App\Events\Chat;
use App\Models\ChatMessage;
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcastNow;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
class MessageSent implements ShouldBroadcastNow
{
use Dispatchable, InteractsWithSockets, SerializesModels;
/**
* Create a new event instance.
*/
public function __construct(public ChatMessage $chatMessage)
{
//
}
/**
* Get the channels the event should broadcast on.
*
* @return array<int, Channel>
*/
public function broadcastOn(): array
{
return [
new PrivateChannel('chat.' . $this->chatMessage->project_id),
];
}
public function broadcastWith(): array
{
return [
'id' => $this->chatMessage->id,
'project_id' => $this->chatMessage->project_id,
'sender_id' => $this->chatMessage->sender_id,
'receiver_id' => $this->chatMessage->receiver_id,
'message' => $this->chatMessage->message,
];
}
}
channels.php:
<?php
use Illuminate\Support\Facades\Broadcast;
Broadcast::channel('chat.{project_id}', function ($user, $project_id) {
return auth()->user()->status === 'admin' || $project_id->user_id === auth()->id();
});
app.js:
import './bootstrap';
import Alpine from 'alpinejs'
import focus from '@alpinejs/focus'
window.Alpine = Alpine
Alpine.plugin(focus)
Alpine.start()
If you need any other file, then let me know and I will gladly provide it. Thanks in advance❤️
Please or to participate in this conversation.