zvizvi/filament-notifications-tabs
Adds Unread and All tabs with an unread-count badge to the Filament database notifications modal, plus per-notification delete and read/unread toggle actions. Configurable default tab and optional delete confirmation. For Filament v5 panels.
Confirm the prerequisites actually exist in your panel before installing anything:
php artisan notifications:table migration has been published and run (notifications table with notifiable_type, notifiable_id, data, read_at).->databaseNotifications(). This package decorates that modal; it does not enable database notifications for you.Require it: composer require zvizvi/filament-notifications-tabs:^0.0.2. Note the hard pin — the README only documents ^0.0.2 against Filament v5, so treat Filament version bumps as a compatibility event, not a routine update.
Register the package Blade files in your Filament theme CSS (resources/css/filament/admin/theme.css) and rebuild assets:
@source '../../../../vendor/zvizvi/filament-notifications-tabs/resources/views/**/*.blade.php';
The ../ count is relative to the theme CSS file, not the project root. If the tabs render unstyled/garbled, this path is almost always the culprit.
First use case: open the bell dropdown → "View all" modal. You should see two tabs (Unread with a count badge, All) and each row should show a trash icon plus a read/unread toggle instead of the default close button.
Where to look first in the vendor directory: the package's service provider (to see how it hooks the modal — most likely a Blade view override/View::replace of Filament's database-notifications modal component) and the published view itself. Read the view before you plan any customization; you need to know whether you can extend it or must fork it.
Sending notifications that behave well in the tabbed view. Keep toDatabase() payloads small and self-describing, since two tabs and per-row actions mean users scan many rows quickly:
Notification::make()
->title('Invoice #1042 overdue')
->body('Customer has not paid in 14 days.')
->icon('heroicon-o-exclamation-triangle')
->color('danger')
->sendToDatabase($user);
Pair with polling for the unread badge. The tab badge is only as fresh as the modal data. Set an explicit interval in the panel provider so the count does not look stale during a support/ops session:
->databaseNotifications()
->databaseNotificationsPolling('30s')
Bulk-triage workflow. The read/unread toggle plus delete is effectively a mini inbox. If your team's process is "read it, act on it, clear it," document that the delete action hard-deletes the notifications row — there is no archive. If audit history matters, write the important events to your own activity_log-style table when the notification is sent, not when it is dismissed.
Custom notification classes with action URLs. Because the per-row actions now occupy the trailing slot, put your actual "go there" affordance in the body/actions of the notification itself (->actions([Action::make('view')->url(...)])) and let the package own read/delete.
Multi-panel awareness. If you run admin and app panels, a view override typically installs globally. Verify appearance on every panel, not just the one you installed it for.
Test the state transitions, not the UI. In Pest/PHPUnit, assert notifications rows and read_at nullability after markAsRead()/markAsUnread(); use Livewire tests for the modal if the tabs are Livewire-driven.
0.0.2, and the README's own Packagist badges/links point at zvizvi/relation-manager-repeater (copy-paste leftovers). Budget time to read the source; assume no test suite and no upgrade guarantees.composer update on a fresh clone, CI deploy, or theme change, run npm run build — the @source glob only matters at build time, never at runtime.resources/views/vendor/ and theme for notification overrides before installing.resources/views/vendor/... and own it. That removes an upgrade dependency for a package this small and makes the change greppable for the next developer.storage/logs/laravel.log for Livewire action errors and confirm the notification model is Filament's DatabaseNotification (a custom notifiable or a Notifiable trait mismatch will make row-level actions fail). If the unread badge never changes, confirm read_at is actually being written — a read-only DB user or a missing column default is easy to miss.NotificationDeleted listener or swap the delete action for a markAsArchived custom column — do not assume you can reconstruct the payload later.config or View::share would appear. If a newer version adds a publishable config or view tag, publishing is cleaner than editing vendor files — check php artisan vendor:publish --provider="Zvizvi\..." after upgrading.How can I help you explore Laravel packages today?