From 1dafe346d5c69b95fe13881d0dcfc43c8997af48 Mon Sep 17 00:00:00 2001 From: Dan Harrin Date: Sat, 22 Apr 2023 15:31:08 +0100 Subject: [PATCH] do it --- .../layouts/app/topbar/index.blade.php | 4 +- .../views/components/layouts/base.blade.php | 2 + .../views/components/layouts/card.blade.php | 6 +- .../src/Context/Concerns/HasComponents.php | 2 + .../Http/Livewire/DatabaseNotifications.php | 32 +++++ .../app/src/Http/Livewire/Notifications.php | 16 --- .../docs/03-database-notifications.md | 29 ++-- .../resources/js/components/notification.js | 2 +- .../views/components/database/echo.blade.php | 16 +++ .../database/modal/actions.blade.php | 8 +- .../components/database/modal/index.blade.php | 2 +- .../resources/views/components/echo.blade.php | 3 - ...e.php => database-notifications.blade.php} | 12 +- .../resources/views/notification.blade.php | 5 +- .../resources/views/notifications.blade.php | 4 - .../Http/Livewire/DatabaseNotifications.php | 134 ++++++++++++++++++ .../src/Http/Livewire/Notifications.php | 96 +------------ .../src/NotificationsServiceProvider.php | 3 + 18 files changed, 224 insertions(+), 152 deletions(-) create mode 100644 packages/app/src/Http/Livewire/DatabaseNotifications.php create mode 100644 packages/notifications/resources/views/components/database/echo.blade.php rename packages/notifications/resources/views/{components/database/index.blade.php => database-notifications.blade.php} (52%) create mode 100644 packages/notifications/src/Http/Livewire/DatabaseNotifications.php diff --git a/packages/app/resources/views/components/layouts/app/topbar/index.blade.php b/packages/app/resources/views/components/layouts/app/topbar/index.blade.php index 63ce7a53fc..cece985eba 100644 --- a/packages/app/resources/views/components/layouts/app/topbar/index.blade.php +++ b/packages/app/resources/views/components/layouts/app/topbar/index.blade.php @@ -87,7 +87,9 @@
@livewire('filament.core.global-search') - @livewire('filament.core.notifications') + @if (filament()->hasDatabaseNotifications()) + @livewire('filament.core.database-notifications') + @endif diff --git a/packages/app/resources/views/components/layouts/base.blade.php b/packages/app/resources/views/components/layouts/base.blade.php index 31cc78289c..be4c7532f0 100644 --- a/packages/app/resources/views/components/layouts/base.blade.php +++ b/packages/app/resources/views/components/layouts/base.blade.php @@ -86,6 +86,8 @@ {{ $slot }} + @livewire('filament.core.notifications') + {{ filament()->renderHook('scripts.start') }} @livewireScripts diff --git a/packages/app/resources/views/components/layouts/card.blade.php b/packages/app/resources/views/components/layouts/card.blade.php index 17ddf87026..37878ff5c0 100644 --- a/packages/app/resources/views/components/layouts/card.blade.php +++ b/packages/app/resources/views/components/layouts/card.blade.php @@ -54,14 +54,10 @@ @if (filament()->auth()->check())
- @livewire('filament.core.notifications') + @livewire('filament.core.database-notifications')
@endif
- - @if (! filament()->auth()->check()) - @livewire('filament.core.notifications') - @endif diff --git a/packages/app/src/Context/Concerns/HasComponents.php b/packages/app/src/Context/Concerns/HasComponents.php index aa3facdd01..f5163a48ba 100644 --- a/packages/app/src/Context/Concerns/HasComponents.php +++ b/packages/app/src/Context/Concerns/HasComponents.php @@ -2,6 +2,7 @@ namespace Filament\Context\Concerns; +use Filament\Http\Livewire\DatabaseNotifications; use Filament\Http\Livewire\GlobalSearch; use Filament\Http\Livewire\Notifications; use Filament\Pages\Page; @@ -262,6 +263,7 @@ trait HasComponents public function registerLivewireComponents(): void { + $this->queueLivewireComponentForRegistration(DatabaseNotifications::class); $this->queueLivewireComponentForRegistration(GlobalSearch::class); $this->queueLivewireComponentForRegistration(Notifications::class); diff --git a/packages/app/src/Http/Livewire/DatabaseNotifications.php b/packages/app/src/Http/Livewire/DatabaseNotifications.php new file mode 100644 index 0000000000..8bf12e6271 --- /dev/null +++ b/packages/app/src/Http/Livewire/DatabaseNotifications.php @@ -0,0 +1,32 @@ +user(); + } + + public function getPollingInterval(): ?string + { + return Filament::getDatabaseNotificationsPollingInterval(); + } + + public function getTrigger(): View + { + return view('filament::components.layouts.app.topbar.database-notifications-trigger'); + } + + public static function getName(): string + { + return 'filament.core.database-notifications'; + } +} diff --git a/packages/app/src/Http/Livewire/Notifications.php b/packages/app/src/Http/Livewire/Notifications.php index 9d8933138c..ba564ca3cb 100644 --- a/packages/app/src/Http/Livewire/Notifications.php +++ b/packages/app/src/Http/Livewire/Notifications.php @@ -5,7 +5,6 @@ namespace Filament\Http\Livewire; use Filament\Facades\Filament; use Filament\Notifications\Http\Livewire\Notifications as BaseComponent; use Illuminate\Contracts\Auth\Authenticatable; -use Illuminate\Contracts\View\View; use Illuminate\Database\Eloquent\Model; class Notifications extends BaseComponent @@ -15,21 +14,6 @@ class Notifications extends BaseComponent return Filament::auth()->user(); } - public function hasDatabaseNotifications(): bool - { - return $this->getUser() && Filament::hasDatabaseNotifications(); - } - - public function getPollingInterval(): ?string - { - return Filament::getDatabaseNotificationsPollingInterval(); - } - - public function getDatabaseNotificationsTrigger(): View - { - return view('filament::components.layouts.app.topbar.database-notifications-trigger'); - } - public static function getName(): string { return 'filament.core.notifications'; diff --git a/packages/notifications/docs/03-database-notifications.md b/packages/notifications/docs/03-database-notifications.md index 03b879bfd9..102cc9145f 100644 --- a/packages/notifications/docs/03-database-notifications.md +++ b/packages/notifications/docs/03-database-notifications.md @@ -4,8 +4,6 @@ title: Database notifications ## Overview -> To start, make sure the package is [installed](installation) - `@livewire('notifications')` should be in your Blade layout somewhere. - Before we start, make sure that the [Laravel notifications table](https://laravel.com/docs/notifications#database-prerequisites) is added to your database: ```bash @@ -16,12 +14,10 @@ php artisan notifications:table > If you're using UUIDs for your `User` model, make sure that your `notifiable` column is using `uuidMorphs()`: `$table->uuidMorphs('notifiable')`. -To enable database notifications, add the following to a service provider: +To add database notifications to your app, you must add a new Livewire component to your Blade layout: -```php -use Filament\Notifications\Http\Livewire\Notifications; - -Notifications::databaseNotifications(); +```blade +@livewire('database-notifications') ``` Database notifications will be rendered within a modal. To open this modal, you must have a "trigger" button in your view. Create a new trigger button component in your app, for instance at `/resources/views/notifications/database-notifications-trigger.blade.php`: @@ -37,13 +33,12 @@ Database notifications will be rendered within a modal. To open this modal, you In the service provider, point to this new trigger view: ```php -use Filament\Notifications\Http\Livewire\Notifications; +use Filament\Notifications\Http\Livewire\DatabaseNotifications; -Notifications::databaseNotifications(); -Notifications::databaseNotificationsTrigger('filament-notifications.database-notifications-trigger'); +DatabaseNotifications::trigger('filament-notifications.database-notifications-trigger'); ``` -Now, simply move the `@livewire('notifications')` component to the position in your HTML that you wish to render the database notifications trigger button. It should appear, and open the database notifications modal when clicked! +Now, click on the trigger button that is rendered in your view. A modal should appear containing your database notifications when clicked! ## Sending database notifications @@ -100,19 +95,19 @@ Polling is the practice of periodically making a request to the server to check By default, Livewire polls for new notifications every 30 seconds: ```php -use Filament\Notifications\Http\Livewire\Notifications; +use Filament\Notifications\Http\Livewire\DatabaseNotifications; -Notifications::databaseNotifications(); -Notifications::databaseNotificationsPollingInterval('30s'); +DatabaseNotifications::databaseNotifications(); +DatabaseNotifications::databaseNotificationsPollingInterval('30s'); ``` You may completely disable polling if you wish: ```php -use Filament\Notifications\Http\Livewire\Notifications; +use Filament\Notifications\Http\Livewire\DatabaseNotifications; -Notifications::databaseNotifications(); -Notifications::databaseNotificationsPollingInterval(null); +DatabaseNotifications::databaseNotifications(); +DatabaseNotifications::databaseNotificationsPollingInterval(null); ``` ### Using Echo to receive new database notifications with websockets diff --git a/packages/notifications/resources/js/components/notification.js b/packages/notifications/resources/js/components/notification.js index ad6daafc37..c6cb4dcf8e 100644 --- a/packages/notifications/resources/js/components/notification.js +++ b/packages/notifications/resources/js/components/notification.js @@ -107,7 +107,7 @@ export default (Alpine) => { this.isShown = false setTimeout( - () => Livewire.emit('notificationClosed', notification.id), + () => Livewire.emitUp('notificationClosed', notification.id), this.getTransitionDuration(), ) }, diff --git a/packages/notifications/resources/views/components/database/echo.blade.php b/packages/notifications/resources/views/components/database/echo.blade.php new file mode 100644 index 0000000000..1d5acd5790 --- /dev/null +++ b/packages/notifications/resources/views/components/database/echo.blade.php @@ -0,0 +1,16 @@ +@props([ + 'channel', +]) + +
diff --git a/packages/notifications/resources/views/components/database/modal/actions.blade.php b/packages/notifications/resources/views/components/database/modal/actions.blade.php index 4d9521afe8..b7daede301 100644 --- a/packages/notifications/resources/views/components/database/modal/actions.blade.php +++ b/packages/notifications/resources/views/components/database/modal/actions.blade.php @@ -8,11 +8,11 @@
@if ($unreadNotificationsCount) @@ -25,12 +25,12 @@ @endif diff --git a/packages/notifications/resources/views/components/database/modal/index.blade.php b/packages/notifications/resources/views/components/database/modal/index.blade.php index a90a78e89c..6a71f8964e 100644 --- a/packages/notifications/resources/views/components/database/modal/index.blade.php +++ b/packages/notifications/resources/views/components/database/modal/index.blade.php @@ -32,7 +32,7 @@ 'py-2 ps-4 pe-2', 'bg-primary-50 -mb-px dark:bg-gray-700' => $notification->unread(), ])> - {{ $this->getNotificationFromDatabaseRecord($notification)->inline() }} + {{ $this->getNotification($notification)->inline() }}
@endforeach diff --git a/packages/notifications/resources/views/components/echo.blade.php b/packages/notifications/resources/views/components/echo.blade.php index 851dfb17cf..757757fe85 100644 --- a/packages/notifications/resources/views/components/echo.blade.php +++ b/packages/notifications/resources/views/components/echo.blade.php @@ -10,9 +10,6 @@ .notification((notification) => { setTimeout(() => $wire.handleBroadcastNotification(notification), 500) }) - .listen('.database-notifications.sent', () => { - setTimeout(() => $wire.call('$refresh'), 500) - }) }) if (window.Echo) { diff --git a/packages/notifications/resources/views/components/database/index.blade.php b/packages/notifications/resources/views/database-notifications.blade.php similarity index 52% rename from packages/notifications/resources/views/components/database/index.blade.php rename to packages/notifications/resources/views/database-notifications.blade.php index eb739f55b7..e55832c68f 100644 --- a/packages/notifications/resources/views/components/database/index.blade.php +++ b/packages/notifications/resources/views/database-notifications.blade.php @@ -1,6 +1,6 @@ @php - $notifications = $this->getDatabaseNotifications(); - $unreadNotificationsCount = $this->getUnreadDatabaseNotificationsCount(); + $notifications = $this->getNotifications(); + $unreadNotificationsCount = $this->getUnreadNotificationsCount(); @endphp
- @if ($databaseNotificationsTrigger = $this->getDatabaseNotificationsTrigger()) + @if ($trigger = $this->getTrigger()) - {{ $databaseNotificationsTrigger->with(['unreadNotificationsCount' => $unreadNotificationsCount]) }} + {{ $trigger->with(['unreadNotificationsCount' => $unreadNotificationsCount]) }} @endif @@ -19,4 +19,8 @@ :notifications="$notifications" :unread-notifications-count="$unreadNotificationsCount" /> + + @if ($broadcastChannel = $this->getBroadcastChannel()) + + @endif
diff --git a/packages/notifications/resources/views/notification.blade.php b/packages/notifications/resources/views/notification.blade.php index 0c9586c260..64e39484e2 100644 --- a/packages/notifications/resources/views/notification.blade.php +++ b/packages/notifications/resources/views/notification.blade.php @@ -1,3 +1,4 @@ +@php use Filament\Notifications\Http\Livewire\Notifications; @endphp diff --git a/packages/notifications/resources/views/notifications.blade.php b/packages/notifications/resources/views/notifications.blade.php index 009d99c93e..f921a55b99 100644 --- a/packages/notifications/resources/views/notifications.blade.php +++ b/packages/notifications/resources/views/notifications.blade.php @@ -20,10 +20,6 @@ @endforeach - @if ($this->hasDatabaseNotifications()) - - @endif - @if ($broadcastChannel = $this->getBroadcastChannel()) @endif diff --git a/packages/notifications/src/Http/Livewire/DatabaseNotifications.php b/packages/notifications/src/Http/Livewire/DatabaseNotifications.php new file mode 100644 index 0000000000..1def75af3a --- /dev/null +++ b/packages/notifications/src/Http/Livewire/DatabaseNotifications.php @@ -0,0 +1,134 @@ + + */ + protected $listeners = [ + 'notificationClosed' => 'removeNotification', + ]; + + public static ?string $trigger = null; + + public static ?string $pollingInterval = '30s'; + + public function removeNotification(string $id): void + { + $this->getNotificationsQuery() + ->where('id', $id) + ->delete(); + } + + public function clearNotifications(): void + { + $this->getNotificationsQuery()->delete(); + } + + public function markAllNotificationsAsRead(): void + { + $this->getUnreadNotificationsQuery()->update(['read_at' => now()]); + } + + public function getNotifications(): DatabaseNotificationCollection + { + /** @phpstan-ignore-next-line */ + return $this->getNotificationsQuery()->get(); + } + + public function getNotificationsQuery(): Builder | Relation + { + /** @phpstan-ignore-next-line */ + return $this->getUser()->notifications()->where('data->format', 'filament'); + } + + public function getUnreadNotificationsQuery(): Builder | Relation + { + /** @phpstan-ignore-next-line */ + return $this->getNotificationsQuery()->unread(); + } + + public function getUnreadNotificationsCount(): int + { + return $this->getUnreadNotificationsQuery()->count(); + } + + public function getPollingInterval(): ?string + { + return static::$pollingInterval; + } + + public function getTrigger(): ?View + { + $viewPath = static::$trigger; + + if (blank($viewPath)) { + return null; + } + + return view($viewPath); + } + + public function getUser(): Model | Authenticatable | null + { + return auth()->user(); + } + + public function getBroadcastChannel(): ?string + { + $user = $this->getUser(); + + if (! $user) { + return null; + } + + if (method_exists($user, 'receivesBroadcastNotificationsOn')) { + return $user->receivesBroadcastNotificationsOn(); + } + + $userClass = str_replace('\\', '.', $user::class); + + return "{$userClass}.{$user->getKey()}"; + } + + public function getNotification(DatabaseNotification $notification): Notification + { + return Notification::fromDatabase($notification) + ->date($this->formatNotificationDate($notification->getAttributeValue('created_at'))); + } + + protected function formatNotificationDate(CarbonInterface $date): string + { + return $date->diffForHumans(); + } + + public static function trigger(?string $trigger): void + { + static::$trigger = $trigger; + } + + public static function pollingInterval(?string $interval): void + { + static::$pollingInterval = $interval; + } + + public function render(): View + { + return view('filament-notifications::database-notifications'); + } +} diff --git a/packages/notifications/src/Http/Livewire/Notifications.php b/packages/notifications/src/Http/Livewire/Notifications.php index 3948b7d67d..70483c2eb0 100644 --- a/packages/notifications/src/Http/Livewire/Notifications.php +++ b/packages/notifications/src/Http/Livewire/Notifications.php @@ -30,12 +30,6 @@ class Notifications extends Component 'notificationClosed' => 'removeNotification', ]; - public static bool $hasDatabaseNotifications = false; - - public static ?string $databaseNotificationsTrigger = null; - - public static ?string $databaseNotificationsPollingInterval = '30s'; - public static string $horizontalAlignment = 'right'; public static string $verticalAlignment = 'top'; @@ -67,50 +61,11 @@ class Notifications extends Component public function removeNotification(string $id): void { - if ($this->notifications->has($id)) { - $this->notifications->forget($id); - } - - if (! $this->hasDatabaseNotifications()) { + if (! $this->notifications->has($id)) { return; } - $this->getDatabaseNotificationsQuery() - ->where('id', $id) - ->delete(); - } - - public function clearDatabaseNotifications(): void - { - $this->getDatabaseNotificationsQuery()->delete(); - } - - public function markAllDatabaseNotificationsAsRead(): void - { - $this->getUnreadDatabaseNotificationsQuery()->update(['read_at' => now()]); - } - - public function getDatabaseNotifications(): DatabaseNotificationCollection - { - /** @phpstan-ignore-next-line */ - return $this->getDatabaseNotificationsQuery()->get(); - } - - public function getDatabaseNotificationsQuery(): Builder | Relation - { - /** @phpstan-ignore-next-line */ - return $this->getUser()->notifications()->where('data->format', 'filament'); - } - - public function getUnreadDatabaseNotificationsQuery(): Builder | Relation - { - /** @phpstan-ignore-next-line */ - return $this->getDatabaseNotificationsQuery()->unread(); - } - - public function getUnreadDatabaseNotificationsCount(): int - { - return $this->getUnreadDatabaseNotificationsQuery()->count(); + $this->notifications->forget($id); } /** @@ -133,27 +88,6 @@ class Notifications extends Component ); } - public function hasDatabaseNotifications(): bool - { - return $this->getUser() && static::$hasDatabaseNotifications; - } - - public function getPollingInterval(): ?string - { - return static::$databaseNotificationsPollingInterval; - } - - public function getDatabaseNotificationsTrigger(): ?View - { - $viewPath = static::$databaseNotificationsTrigger; - - if (blank($viewPath)) { - return null; - } - - return view($viewPath); - } - public function getUser(): Model | Authenticatable | null { return auth()->user(); @@ -176,32 +110,6 @@ class Notifications extends Component return "{$userClass}.{$user->getKey()}"; } - public function getNotificationFromDatabaseRecord(DatabaseNotification $notification): Notification - { - return Notification::fromDatabase($notification) - ->date($this->formatNotificationDate($notification->getAttributeValue('created_at'))); - } - - protected function formatNotificationDate(CarbonInterface $date): string - { - return $date->diffForHumans(); - } - - public static function databaseNotifications(bool $condition = true): void - { - static::$hasDatabaseNotifications = $condition; - } - - public static function databaseNotificationsTrigger(?string $trigger): void - { - static::$databaseNotificationsTrigger = $trigger; - } - - public static function databaseNotificationsPollingInterval(?string $interval): void - { - static::$databaseNotificationsPollingInterval = $interval; - } - public static function horizontalAlignment(string $alignment): void { static::$horizontalAlignment = $alignment; diff --git a/packages/notifications/src/NotificationsServiceProvider.php b/packages/notifications/src/NotificationsServiceProvider.php index 06733d4ce6..43d1bd6659 100644 --- a/packages/notifications/src/NotificationsServiceProvider.php +++ b/packages/notifications/src/NotificationsServiceProvider.php @@ -2,6 +2,7 @@ namespace Filament\Notifications; +use Filament\Notifications\Http\Livewire\DatabaseNotifications; use Filament\Notifications\Http\Livewire\Notifications; use Filament\Notifications\Testing\TestsNotifications; use Filament\Support\Assets\AssetManager; @@ -35,6 +36,8 @@ class NotificationsServiceProvider extends PackageServiceProvider public function packageBooted(): void { + Livewire::component('database-notifications', DatabaseNotifications::class); + Livewire::component('notifications', Notifications::class); Livewire::listen('component.dehydrate', function (Component $component, Response $response): Response {