So I would like to build a realtime chat in my website, but i have the chat system without the realtime. Indeed I have to refresh the page for the user who receive the messages.
So here the code
FIRST The view :
<div class="selected-conversation">
{{-- Section pour afficher les messages --}}
<div class="messages" id="message-container">
<livewire:message-chat :conversationId="$conversation->id" :key="$conversation->id" id="chat-area"/>
</div>
<script type="module" src="{{ asset('vendor/livewire/livewire/dist/livewire.js') }}" defer></script>
<script src="https://js.pusher.com/7.0/pusher.min.js"></script>
<script type="module">
import Echo from 'https://cdn.jsdelivr.net/npm/[email protected]/dist/echo.js';
Echo.private('conversation.' + {{ Auth::id() }})
.listen('messageSent', (event) => {
window.livewire.emit('messageSent');
});
const pusherKey = '{{ env("PUSHER_APP_KEY") }}';
const pusherCluster = '{{ env("PUSHER_APP_CLUSTER") }}';
window.Echo = new Echo({
broadcaster: 'pusher',
key: pusherKey,
cluster: pusherCluster,
encrypted: true,
});
</script>
livewire component with his backend:
<div >
@foreach ($messages as $message)
@if ($message->user_id == Auth::id())
<div class="sent-message">
<strong class="you-message">Vous</strong><br>
{{ $message->content }}<br>
<div class="image-container">
@foreach ($message->images as $image)
<img class="message-image mr-2" src="{{ asset('storage/chatImages/' . $image->image_path) }}" alt="Message Image">
@endforeach
</div>
<span class="time">@if ($message->created_at) {{ $message->created_at->diffForHumans() }} @endif</span>
</div>
@else
<div class="received-message">
<strong class="other-message">{{ $message->user->username }}</strong><br>
{{ $message->content }}<br>
<div class="image-container">
@foreach ($message->images as $image)
<img class="message-image mr-2" src="{{ asset('storage/chatImages/' . $image->image_path) }}" alt="Message Image">
@endforeach
</div>
<span class="time">@if ($message->created_at) {{ $message->created_at->diffForHumans() }} @endif</span>
</div>
@endif
@endforeach
</div>
BACKEND
<?php
namespace App\Livewire;
use App\Models\Message;
use Livewire\Component;
class MessageChat extends Component
{
public $conversationId;
public function mount($conversationId)
{
$this->conversationId = $conversationId;
}
public function getListeners()
{
return [
"echo-private:conversation.{$this->conversationId},MessageSent" => 'messageSent',
];
}
public function render()
{
$messages = Message::where('conversation_id', $this->conversationId)->get();
return view('livewire.message-chat', compact('messages'));
}
public function messageSent()
{
$this->render();
}
}
Function in the controller
public function sendMessage(Request $request, Conversation $conversation)
{
$user = Auth::user();
$request->validate([
'message' => 'required_without:image|string',
'image' => 'required_with:message image|mimes:jpeg,png,jpg|max:2048',
]);
$message = $conversation->messages()->create([
'user_id' => $user->id,
'content' => $request->input('message'),
]);
if ($request->hasFile('images')) {
foreach ($request->file('images') as $image) {
$imageName = time() . '_' . $image->getClientOriginalName();
$image->storeAs('chatImages', $imageName, 'public');
$message->images()->create([
'image_path' => $imageName,
]);
}
}
broadcast(new MessageSent($user, $message, $conversation));
return response()->json(['status' => 'Message sent']);
}
The event
<?php
namespace App\Events;
use App\Models\Conversation;
use App\Models\Message;
use App\Models\User;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
class MessageSent implements ShouldBroadcast
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public $user;
public $message;
public $conversation;
public function __construct(User $user, Message $message, Conversation $conversation)
{
$this->user = $user;
$this->message = $message;
$this->conversation = $conversation;
}
public function broadcastOn()
{
return new PrivateChannel('conversation.' . $this->message->conversation_id);
}
public function broadcastAs($message){
return $message;
}
}
The routes
Route::post('/messagerie/{conversation?}/sendMessage', [App\Http\Controllers\MessageController::class, 'sendMessage'])->name('sendMessage');
If you can help me to find out the solution to have realtime, I'll appreciate it. Been a month stuck on this. Help is what I need xD