unseen-codes/chat
Plug-and-play Livewire single-file chat component for Laravel. Drop livewire:chat-box anywhere for 1-on-1 or group chats with reactions, replies, attachments, read receipts, typing indicator, editing, soft deletes, and fully config-driven features/models.
Install & Publish
Run composer require unseen-codes/chat → php artisan vendor:publish --tag=chat-config → php artisan vendor:publish --tag=chat-migrations → php artisan migrate.
Verify: Check config/chat.php for feature toggles (e.g., emoji_reactions, file_attachments).
Add Trait to User Model
Append use UnseenCodes\Chat\Traits\Chattable; to app/Models/User.php.
Note: The package auto-creates chats() and messages() relationships.
Drop the Component
Place <livewire:chat-box /> in any Blade view (e.g., resources/views/chat.blade.php).
First Test: Visit the page as an authenticated user—you’ll see an empty chat list.
Trigger a Conversation Use the package’s helper:
use UnseenCodes\Chat\Facades\Chat;
Chat::startConversation([$userId1, $userId2]); // 1-on-1
Chat::startGroupConversation([$userId1, $userId2, $userId3]); // Group
Where to call it? In a Livewire component’s mount() or a controller (if not using Livewire/Volt routes).
Embedding in Layouts
<livewire:chat-box /> in a sidebar or modal (e.g., resources/views/layouts/app.blade.php).<livewire:chat-box :participants="[$user->id, $friend->id]" />
wire:key="chat-sidebar-{auth()->id()}").Customizing Conversation Triggers
<button wire:click="startChat({{ $user->id }})">Message</button>
In the Livewire component:
public function startChat(int $userId) {
Chat::startConversation([auth()->id(), $userId]);
}
Route::get('/chat/{user}', [ChatController::class, 'show']) and pass the ID to the component.Handling Attachments
config/chat.php under file_attachments.<livewire:chat-box :allowed-mimes="['image/jpeg', 'application/pdf']" />
Real-Time Features
typing_indicator_timeout).read_receipts in config. Track with:
$message->readBy()->contains(auth()->id()); // Check if current user read
Threaded Replies
$message->replies()->with('author')->get();
<livewire:chat-box /> with @chat in Volt templates.Chat facade to fetch conversations:
$conversations = Chat::conversations()->whereHas('participants', fn($q) => $q->where('users.id', auth()->id()))->get();
MessageSent event (published by the package) to trigger Pusher/broadcasts:
use UnseenCodes\Chat\Events\MessageSent;
MessageSent::dispatch($message)->toOthers(); // Broadcast to all participants except sender
Model Relationships
Chattable trait to the User model breaks all chat functionality.php artisan optimize:clear after adding the trait.Livewire Key Conflicts
<livewire:chat-box /> instances on one page may cause state conflicts.wire:key (e.g., wire:key="chat-{conversationId}").File Storage Paths
storage/app/public/chat. Override in config:
'file_attachments' => [
'disk' => 's3',
'path' => 'chat-files',
],
config/filesystems.php.Soft Deletes
$messages = Message::withTrashed()->where('conversation_id', $id)->get();
Participant Sync
Chat::addParticipant() doesn’t update the UI.refresh() or emit an event:
$this->emit('chat-participants-updated', $conversationId);
Log Messages:
Enable debug mode in config/chat.php:
'debug' => env('APP_DEBUG', false),
Logs appear in storage/logs/laravel.log.
Wire:Model Events: Listen for Livewire model events to debug state:
$this->dispatchBrowserEvent('chat-debug', ['message' => 'Test']);
Custom Models
config/chat.php:
'models' => [
'user' => App\Models\CustomUser::class,
'conversation' => App\Models\CustomConversation::class,
],
Chattable trait.Message Events
Message model to add custom fields:
class Message extends \UnseenCodes\Chat\Models\Message
{
protected $casts = [
'is_pinned' => 'boolean',
];
}
UI Customization
php artisan vendor:publish --tag=chat-views
resources/views/vendor/chat-box.blade.php to change styles/structure.Rate Limiting
Route::middleware(['throttle:10,1'])->group(function () {
// Chat routes
});
How can I help you explore Laravel packages today?