ยท yebor974 ยท Advanced Techniques, Tutorials

Managing public alerts with Filament Notifications in Laravel

Learn how to manage public alerts in your Laravel application using Filament Notifications. A step-by-step guide with model, middleware, and resource panel.

Managing public alerts with Filament Notifications in Laravel - picture

Adding public notifications to your Laravel FilamentPHP application can greatly enhance user engagement and communication. In this guide, we will implement a public notification system using Filament, covering everything from the database model to displaying alerts on public pages.

This article follows up on your feedback from our previous article Introducing public alerts with Laravel Filament Notifications.

To use Filament on public pages, you can follow this article: Guide to using Filament Components in public-facing pages. This guide builds upon that configuration.

Step 1: Create the Alert Model

The Alert model represents the notifications that will be displayed to users. It includes fields for the title, message, type, and display duration.

  • First, create the Alert model and associated migration file with the necessary fields:
php artisan make:model Alert -m
  • Update the generated migration file:
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration {
    public function up(): void
    {
        Schema::create('alerts', function (Blueprint $table) {
            $table->id();
            $table->string('title');
            $table->text('message');
            $table->string('type');
            $table->string('read_more_link')->nullable();
            $table->boolean('is_active')->default(false);
            $table->timestamp('started_display_at');
            $table->timestamp('ended_display_at')->nullable();
            $table->timestamps();
        });
    }

    public function down(): void
    {
        Schema::dropIfExists('alerts');
    }
};
  • Modify the generated model file app/Models/Alert.php:
namespace App\Models;

use App\Enums\AlertTypeEnum;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;

class Alert extends Model
{
    protected $fillable = [
        'title',
        'message',
        'type',
        'is_active',
        'read_more_link',
        'started_display_at',
        'ended_display_at',
    ];

    protected $casts = [
        'type' => AlertTypeEnum::class,
        'started_display_at' => 'datetime',
        'ended_display_at' => 'datetime',
    ];

    public function scopePublished(Builder $query): void
    {
        $query->where('is_active', '=', true)
            ->where('started_display_at', '<=', now())
            ->where(function ($query) {
                $query->where('ended_display_at', '>=', now())
                    ->orWhereNull('ended_display_at');
            });
    }
}
  • Run the migration:
php artisan migrate

Step 2: Create the enum for alert types

Using an enum allows us to standardize alert types and associate icons and colors with each type.

namespace App\Enums;

use Filament\Support\Contracts\HasColor;
use Filament\Support\Contracts\HasIcon;
use Filament\Support\Contracts\HasLabel;

enum AlertTypeEnum: string implements HasColor, HasIcon, HasLabel
{
    case INFO = 'info';
    case WARNING = 'warning';
    case DANGER = 'danger';

    public function getLabel(): string
    {
        return match ($this) {
            AlertTypeEnum::INFO => 'Info',
            AlertTypeEnum::WARNING => 'Warning',
            AlertTypeEnum::DANGER => 'Danger',
        };
    }

    public function getIcon(): string
    {
        return match ($this) {
            AlertTypeEnum::INFO => 'heroicon-o-information-circle',
            AlertTypeEnum::WARNING => 'heroicon-o-exclamation-circle',
            AlertTypeEnum::DANGER => 'heroicon-o-exclamation-triangle',
        };
    }

    public function getColor(): string
    {
        return match ($this) {
            AlertTypeEnum::INFO => 'info',
            AlertTypeEnum::WARNING => 'warning',
            AlertTypeEnum::DANGER => 'danger',
        };
    }
}

Step 3: Middleware for displaying alerts

Middleware ensures that notifications are displayed to users as they browse the site. The alerts are filtered so that only new, active notifications appear.

  • Create the middleware:
php artisan make:middleware AlertMiddleware
  • Modify app/Http/Middleware/AlertMiddleware.php:
namespace App\Http\Middleware;

use App\Models\Alert;
use Closure;
use Filament\Notifications\Actions\Action;
use Filament\Notifications\Notification;
use Illuminate\Http\Request;

class AlertMiddleware
{
    public function handle(Request $request, Closure $next)
    {
        $alertQuery = Alert::query()
            ->published()
            ->whereNotIn('id', session()->get('read_alerts.id', []))
            ->limit(3); //Retrieving only 3 max alerts

        foreach ($alertQuery->get() as $alert) {
            Notification::make()
                ->icon($alert->type->getIcon())
                ->iconColor($alert->type->getColor())
                ->color($alert->type->getColor())
                ->title($alert->title)
                ->body(nl2br($alert->message))
                ->actions(fn() => $alert->read_more_link ? [Action::make('read_more')->label('Read more')->url($alert->read_more_link)->openUrlInNewTab()->button()] : [])
                ->persistent()
                ->send();

            session()->push('read_alerts.id', $alert->id); //Registering alert id on current session
        }

        return $next($request);
    }
}

alerts will only be shown once per session and will not reappear unless the session is reset.

  • Register middleware on public routes:
Route::middleware([\App\Http\Middleware\AlertMiddleware::class])->group(function () {
    //...
});

Of course, you can register this middleware in the Kernel.php file and use an alias when declaring route middleware.

Step 4: Add backend management with Filament Resource

Using Filament, we can create a resource to manage alerts directly from the admin panel.

  • Create the AlertResource:
php artisan make:filament-resource Alert
  • Update app/Filament/Resources/AlertResource.php:
namespace App\Filament\Resources;

use App\Enums\AlertTypeEnum;
use App\Models\Alert;
use Filament\Forms;
use Filament\Resources\Resource;
use Filament\Tables;

class AlertResource extends Resource
{
    //...

    public static function form(Form $form): Form
    {
        return $form
            ->schema([
                Forms\Components\Section::make()
                    ->schema([
                        Forms\Components\TextInput::make('title')
                            ->required()
                            ->maxLength(255),
                        Forms\Components\Select::make('type')
                            ->options(AlertTypeEnum::class)
                            ->required(),
                        Forms\Components\Textarea::make('message')
                            ->required()
                            ->columnSpanFull(),
                        Forms\Components\TextInput::make('read_more_link')
                            ->prefixIcon('heroicon-o-link')
                            ->nullable()
                            ->url()
                            ->maxLength(255)
                            ->columnSpanFull(),
                        DatetimePicker::make('started_display_at')
                            ->native(false)
                            ->required(),
                        DatetimePicker::make('ended_display_at')
                            ->native(false)
                            ->nullable()
                            ->after('started_display_at'),
                        Forms\Components\Checkbox::make('is_active'),
                    ])->columns(2),
            ]);
    }

    public static function table(Table $table): Table
    {
        return $table
            ->columns([
                TextColumn::make('title')
                    ->searchable()
                    ->wrap(),
                Tables\Columns\IconColumn::make('is_active')
                    ->boolean(),
                TextColumn::make('type'),
                TextColumn::make('started_display_at')
                    ->dateTime('d/m/Y H:i')
                    ->sortable(),
                TextColumn::make('ended_display_at')
                    ->dateTime('d/m/Y H:i')
                    ->sortable(),
            ])
            ->actions([
                Tables\Actions\EditAction::make(),
                Tables\Actions\DeleteAction::make(),
            ])
            ->defaultSort('started_display_at', 'desc');
    }
}

Conclusion

With these steps, you now have a fully functional public alert system using Filament in Laravel. Users will see important alerts while you can manage them efficiently from the admin panel. ๐Ÿš€

Here's a look at how the backend configuration works: Filament Mastery Alerts Resource

Here's an example of the associated notification: Filament Mastery Alert Notification

Avatar of yebor974
yebor974
Freelance - French IT Engineer passionate about Laravel and Filament PHP, creating innovative solutions to simplify web development.
React
Share post

Related Posts

View All Posts

Customize your Filament panel theme

Learn how to create and apply custom themes for Filament panels, including setting sidebar colors, defining primary colors, and customizing integrated elements.

Stay ahead in the Filament Mastery adventure

Join our community of Filament PHP enthusiasts! Get exclusive tips, tutorials, and updates delivered straight to your inbox.