DEV Community

ashrakt
ashrakt

Posted on • Edited on

Laravel Real-time

What Are Notifications in Laravel?
Laravel notification is a way to send a message to your users. Think of it as a central hub for all your app's alerts. Instead of writing separate code for emails, text messages, or in-app alerts, Laravel gives you a single, clean way to handle them all. You write the message once, and Laravel sends it through whatever channels you choose.

Types of Notifications
Laravel has several built-in notification types, each for a different purpose:

  1. Mail Notifications:
    These send a standard email. They're perfect for important updates like a new invoice or a password reset link.

  2. Database Notifications:
    This type saves a record of the notification in your database. It's used for the notifications you see inside an app. Users can see their notification history and mark them as read.

  3. SMS Notifications:
    send text messages directly to a user's phone. This is perfect for things that need immediate attention, like verification codes (OTP). Laravel supports this through services like Vonage and Twilio.

  4. Slack Notifications:
    send messages to Slack channels or to team members directly. This is great for sending internal alerts, like error logs or important system updates, helping development teams stay informed.

  5. Broadcast Notifications: This is the key to real-time notifications. It sends the notification data to a service like Pusher or Laravel Echo. This allows a user's browser to get an instant alert without having to refresh the page. This is what makes real-time functionality possible.


*How to Send a Notification to an Admin When a New User Registers
*

I- Prepare the Database
First, you need a table to save the notifications. Use this command to create a migration file:

  • php artisan notifications:table

Then, run the migration to create the table named notifications in your database:
php artisan migrate


  • Make Your Admin Model Notifiable By default, Laravel's User model is already notifiable. But if you have a separate Admin model, you need to add the Notifiable trait to it. This gives the Admin model the superpower to receive notifications.


  • Create the Notification class
    Next, create the notification class that will define the content. This example will create a notification for when a new user signs up.

  • php artisan make:notification NewUserRegisteredNotification

Open the new file app/Notifications/NewUserRegisteredNotification.php.

<?php

namespace App\Notifications;

use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Notification;

class NewUserRegisteredNotification extends Notification
{
    use Queueable;
    public $user;

    public function __construct($newUser)
    {
        $this->user = $newUser;
    }

    public function via(object $notifiable): array
    {
        return ['database'];
    }


    // public function toMail(object $notifiable): MailMessage
    // {
    //     return (new MailMessage)
    //         ->line('The introduction to the notification.')
    //         ->action('Notification Action', url('/'))
    //         ->line('Thank you for using our application!');
    // }


    public function toArray(object $notifiable): array
    {
        return [
            "name"    => $this->user->name,
            "email"   => $this->user->email,
            "message" => "new user registered",
        ];
    }
}
Enter fullscreen mode Exit fullscreen mode

__construct()
This function is the "constructor" of the class. You use it to pass any data that the notification needs before it's sent.

via(object $notifiable): array
This function determines the channels the notification will be sent through. It simply returns an array with the names of the channels you want to use, like mail, database, or slack.

toMail(object $notifiable): MailMessage
This function is specifically for email notifications. If the via() function returns mail, this function will be used to build the email message. Here, you define the subject, the body text, and any buttons that will appear in the email.

toArray(object $notifiable): array
This function is a generic way to convert the notification into an array. It's used by different channels, like database and broadcast, to either save the notification or send it as data.


We want to store this notification in the database, so we'll use the database channel and define the data to be stored.


  • calling notification

If you have just one admin to notify.

public function store(Request $request): RedirectResponse
    {
        $request->validate([
            'name' => ['required', 'string', 'max:255'],
            'email' => ['required', 'string', 'email', 'max:255', 'unique:' . User::class],
            'password' => ['required', 'confirmed', Rules\Password::defaults()],
        ]);

        $user = User::create([
            'name' => $request->name,
            'email' => $request->email,
            'password' => Hash::make($request->password),
        ]);

        event(new Registered($user));

        $admin = Admin::find(1);
        $admin->notify(new NewUserRegisteredNotification($user));

        Auth::login($user);

        return redirect(RouteServiceProvider::HOME);
    }
Enter fullscreen mode Exit fullscreen mode
  • register form

  • notifications table

you can use another way
Notification::send($admin, new NewUserRegisteredNotification($user));


  • displaying notification
<li class="nav-item nav-notif">
            <a class="nav-link text-muted my-2 notificationIcon" href="./#" data-toggle="modal"
                data-target=".modal-notif">
                <span class="fe fe-bell fe-16"></span>
                <span class="dot dot-md text-danger"
                    id="notificationIconCounter">{{ count(Auth::guard('admin')->user()->unreadNotifications) }}</span>
            </a>
        </li>
        {{-- Notification Modal --}}
        <div class="modal fade modal-notif modal-slide" tabindex="-1" role="dialog"
            aria-labelledby="defaultModalLabel" aria-hidden="true">
            <div class="modal-dialog modal-sm" role="document">
                <div class="modal-content">
                    <div class="modal-header">
                        <h5 class="modal-title" id="defaultModalLabel">Notifications</h5>
                        <button type="button" class="close" data-dismiss="modal" aria-label="Close">
                            <span aria-hidden="true">&times;</span>
                        </button>
                    </div>
                    <div class="modal-body" id="notificationIconModal">
                        @if (count(Auth::guard('admin')->user()->notifications) > 0)
                            <div class="list-group list-group-flush my-n3">
                                @foreach (Auth::guard('admin')->user()->notifications->take(5) as $notification)
                                    <div
                                        class="list-group-item @if ($notification->unread()) bg-light @else bg-transparent @endif ">
                                        <div class="row align-items-center">
                                            <div class="col-auto">
                                                <span class="fe fe-box fe-24"></span>
                                            </div>
                                            <div class="col">
                                                {{-- <small><strong>Package has uploaded successfull</strong></small> --}}
                                                <div class="my-0 text-muted small">
                                                    {{ $notification->data['message'] }}
                                                </div>
                                                <small
                                                    class="badge badge-pill badge-light text-muted">{{ $notification->created_at->diffForHumans() }}</small>
                                            </div>
                                        </div>
                                    </div>
                                @endforeach
                            </div>
                        @endif <!-- / .list-group -->
                    </div>
                    <div class="modal-footer" id="clearNotification">
                        <button type="button" class="btn btn-secondary btn-block" data-dismiss="modal">Clear
                            All</button>
                    </div>
                </div>
            </div>
        </div>
Enter fullscreen mode Exit fullscreen mode
<script>
    $("document").ready(function() {
        // mark all notifications to read
        $(document).on('click', ".notificationIcon", function() {
            $.ajax({
                url: {{ Illuminate\Support\Js::from(route('admin.notifications.read')) }},
                method: 'get',
                success: function(data) {
                    $("#notificationIconCounter").load(" #notificationIconCounter > *");
                    $("#notificationIconModal").load(" #notificationIconModal > *");
                },
                error: function() {
                    alert("please try again");
                }
            });
        });



        // clear all notification
        $(document).on('click', "#clearNotification", function() {
            $.ajax({
                url: {{ Illuminate\Support\Js::from(route('admin.notifications.clear')) }},
                method: 'get',
                success: function(data) {
                    $("#notificationIconCounter").load(" #notificationIconCounter > *");
                    $("#notificationIconModal").load(" #notificationIconModal > *");
                },
                error: function() {
                    alert("please try again");
                }
            });
        });
    });
</script>
Enter fullscreen mode Exit fullscreen mode

basic configurations
Before broadcasting any events, you will first need to register the App\Providers\BroadcastServiceProvider. In new Laravel applications, you only need to uncomment this provider in the providers array of your config/app.php configuration file. This BroadcastServiceProvider contains the code necessary to register the broadcast authorization routes and callbacks.

The config/broadcasting.php file is the central configuration hub for Laravel's broadcasting system. Its main role is to tell Laravel which broadcasting service to use and how to connect to it.


Getting Started with broadcast driver (Pusher):

These are the simple steps to set up your account and get your API keys.

  1. Create Your Pusher Account
    Go to the Pusher website (pusher.com).

  2. Choose a Pusher Product
    After signing up, you'll be asked to choose a product.

Select Channels (this is the service used for Laravel's real-time events).

  1. Create a New Application You'll be prompted to Create a New App. Name your app (e.g., laravel-broadcast-app). Select a Cluster (a server region, like eu or us2)—choose one closest to your users for better performance.


  1. Get Your App Keys Once the app is created, you'll be taken to the App Keys section

Copy these keys. You will need to paste them into your Laravel project's .env file to connect your application to Pusher.


Creating a Broadcast Event

1- Generate the Event Class
First, you need to create a new Event class using the Artisan command. We'll name this event NewUserRegisteredEvent.
php artisan make:event NewUserRegisteredEvent

This command creates a new file at app/Events/NewUserRegisteredEvent.php.

2- Implement the Broadcast Interface
Open the newly created file (app/Events/NewUserRegisteredEvent.php). To make any event broadcastable, its class must implement the ShouldBroadcast interface.

  • Use the Interface: Add use Illuminate\Contracts\Broadcasting\ShouldBroadcast;

  • Implement: Add implements ShouldBroadcast to the class definition.

public function broadcastOn(): array
{
    return [
        new Channel('new_user_channel'),
    ];
}
Enter fullscreen mode Exit fullscreen mode

The core function of broadcastOn() is to determine and specify the channel(s) that the event's data will be published to via the broadcasting driver.

channels types

  • public : all users & guests (no Auth required).

  • private : Auth users only (any guard).

  • presence : Auth users only (any guard) , awareness of who is
    subscribed to this channel.


3- Dispatch the Event
Finally, you need to fire the event from your Laravel code (e.g., from a Controller after a user register).

These two lines of code are the ways you trigger (or "fire") the broadcasting process for your event in Laravel.


    public function store(Request $request): RedirectResponse
    {
        $request->validate([
            'name' => ['required', 'string', 'max:255'],
            'email' => ['required', 'string', 'email', 'max:255', 'unique:' . User::class],
            'password' => ['required', 'confirmed', Rules\Password::defaults()],
        ]);

        $user = User::create([
            'name' => $request->name,
            'email' => $request->email,
            'password' => Hash::make($request->password),
        ]);

        event(new Registered($user));

        $admin = Admin::find(1);
        // $admin->notify(new NewUserRegisteredNotification($user));
        Notification::send($admin, new NewUserRegisteredNotification($user));


        // trigger (or "fire") the broadcasting process
        NewUserRegisteredEvent::dispatch($user);
        // broadcast(new NewUserRegisteredEvent($user));

        Auth::login($user);
        return redirect(RouteServiceProvider::HOME);
    }
Enter fullscreen mode Exit fullscreen mode

recievers

  • pusher
  • Laravel Echo

using pusher

1- Install the Pusher PHP SDK

laravel pusher documentation

composer require pusher/pusher-php-server

pusher reciever

  • Subscribe to events on the client.
  <script src="https://js.pusher.com/8.2.0/pusher.min.js"></script>
    <script>
        // Enable pusher logging - don't include this in production
        Pusher.logToConsole = false;

        var pusher = new Pusher("{{ env('PUSHER_APP_KEY') }}", {
            cluster: 'eu'
        });

        var channel = pusher.subscribe('new_user_channel');
        channel.bind('App\\Events\\NewUserRegisteredEvent', function(data) {
            console.log(data['message']);
            let currentCount = parseInt($("#notificationIconCounter").text()) || 0;
            let newCount = currentCount + 1;
            $("#notificationIconCounter").text(newCount);
        });
    </script>
Enter fullscreen mode Exit fullscreen mode

-You will need to update your Laravel project's .env file BROADCAST_DRIVER=pusher.

test your code:


using Laravel Echo

Laravel Echo is a JavaScript library that makes it painless to subscribe to channels and listen for events broadcast by your server-side broadcasting driver. You may install Echo via the NPM package manager.

To successfully switch to Laravel Echo, you must comment out or remove the direct Pusher client initialization script from your HTML or Blade files.

1- install package
npm install --save-dev laravel-echo pusher-js

2- Configure .env
Add your Pusher credentials (Keys, Secret, and Cluster) to your .env file.

BROADCAST_DRIVER=pusher
PUSHER_APP_ID=YOUR_APP_ID
PUSHER_APP_KEY=YOUR_APP_KEY
PUSHER_APP_SECRET=YOUR_APP_SECRET
PUSHER_APP_CLUSTER=eu or mt1 or ap2 
Enter fullscreen mode Exit fullscreen mode

3- Configure Echo
Open the file resources/js/bootstrap.js (or app.js) and uncomment the Echo block, using your .env variables via the VITE_ prefix:

4- Load the compiled and necessary assets for the primary entry point file located at resources/js/app.js."

  • In Development run npm run dev
  • In Production run npm run build

5- Listening for Events
you are ready to start listening for events that are broadcast from your Laravel application. First, use the channel method to retrieve an instance of a channel, then call the listen method to listen for a specified event.


update this example using private channel

1- event

<?php

namespace App\Events;

use App\Models\User;
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Auth;

class NewUserRegisteredEvent implements ShouldBroadcast
{
    use Dispatchable, InteractsWithSockets, SerializesModels;

    public $message;

    public function __construct(public User $user)
    {
        $this->message = "new user registered called $user->name";
    }

    // public channel
    // public function broadcastOn(): array
    // {
    //     return [
    //         new Channel('new_user_channel'),
    //     ];
    // }

    // private channel
    public function broadcastOn(): array
    {
        return [
            new PrivateChannel('new_user_channel'),
        ];
    }
}

Enter fullscreen mode Exit fullscreen mode

2- bootstap.js

import Echo from 'laravel-echo';

import Pusher from 'pusher-js';

window.Pusher = Pusher;

window.Echo = new Echo({
    broadcaster: 'pusher',
    key: import.meta.env.VITE_PUSHER_APP_KEY,
    cluster: import.meta.env.VITE_PUSHER_APP_CLUSTER ?? 'mt1',
    wsHost: import.meta.env.VITE_PUSHER_HOST ? import.meta.env.VITE_PUSHER_HOST : `ws-${import.meta.env.VITE_PUSHER_APP_CLUSTER}.pusher.com`,
    wsPort: import.meta.env.VITE_PUSHER_PORT ?? 80,
    wssPort: import.meta.env.VITE_PUSHER_PORT ?? 443,
    forceTLS: (import.meta.env.VITE_PUSHER_SCHEME ?? 'https') === 'https',
    enabledTransports: ['ws', 'wss'],
});

 // private
   window.Echo.private('new_user_channel')
    .listen('NewUserRegisteredEvent', (e) => {
        console.log(e);

         let currentCount = parseInt($("#notificationIconCounter").text()) || 0;
         let newCount = currentCount + 1;
         $("#notificationIconCounter").text(newCount);
    });
Enter fullscreen mode Exit fullscreen mode

3- authorization

the boot() method in the BroadcastServiceProvider activates the entire authorization layer for your private real-time channels. Without it, your private channels would not work because clients couldn't be authenticated to listen.

  • route/channels.php

a. Broadcast::channel('new_user_channel', ...)
Broadcast::channel(): This static method tells Laravel's broadcasting system to register a new authorization rule for the channel specified in the first argument, 'new_user_channel'.


b. The Authorization Callback (function ($user) { ... })
This is the function that performs the actual security check.

$user: This variable automatically contains the authenticated user model attempting to subscribe to the channel.

return $user->type == "super_admin";: It returns true only if the authenticated user's type attribute matches the string "super_admin".

If it returns true: The user is authorized, and the broadcasting service allows them to subscribe.

If it returns false: The user is denied access, and the subscription request fails with a 403 Forbidden error.


c. Guard Specification (['guards' => ['admin']])

This is an optional security enhancement that specifies which authentication guard(s) should be used to retrieve the authenticated user.

*example using presence channel
*

All presence channels are also private channels; therefore, users must be authorized to access them. However, when defining authorization callbacks for presence channels, you will not return true if the user is authorized to join the channel. Instead, you should return an array of data about the user.

*steps Who's Online for Admins *

This example allows any admin to see which other admins are currently viewing the dashboard in real-time.

1- Generate the Event Class
php artisan make:event NewAdminRoomEvent

2- Implement the Broadcast Interface

3-Dispatch the Event

 public function store(AdminLoginRequest $request)
    {
        $request->authenticate('admin');

        $request->session()->regenerate();

        // fire broadcast event
        NewAdminRoomEvent::dispatch();

        return \to_route('admin.index');
    }

Enter fullscreen mode Exit fullscreen mode

4-Listening for Events using laravel echo


  // presence
   window.Echo.join(`admin-room-channel`)
    .here((users) => {
         console.log("here");
        console.log(users);
    })
    .joining((user) => {
        console.log("joining");
        console.log(user);
    })
    .leaving((user) => {
        console.log("leaving");
        console.log(user);
    })
    .error((error) => {
        console.error("error");
        console.log(user);
    });
Enter fullscreen mode Exit fullscreen mode


The Channel Class

A Channel Class moves your channel authorization logic from the routes/channels.php file into a dedicated PHP class. This follows Laravel's philosophy of separation of concerns.

*The Steps to Create a Channel Class (3 Steps) 🧑‍💻
*

Step 1: Create the Class
Use the Artisan command-line tool to generate a new Channel Class. We'll use 'new user' scenario as an example:

php artisan make:channel NewUserChannel

This command will create a file at app/Broadcasting/NewUserChannel.php.

Step 2: Implement the Authorization Logic
Open the newly created file (app/Broadcasting/NewUserChannel.php). You'll find a single method, join. This is where you put your authorization logic.

<?php

namespace App\Broadcasting;

use App\Models\Admin;

class NewUserChannel
{

    public function __construct()
    {
        //
    }


    public function join(Admin $admin): array|bool
    {
        return $admin->type == "super_admin";
    }
}

Enter fullscreen mode Exit fullscreen mode

Step 3: Register the Class in Routes
Now, open your channel routes file (routes/channels.php). Instead of using a closure (anonymous function), you register the class using the static ::class syntax.

Your original code:

Broadcast::channel('new_user_channel', function ($user) {
    return $user->type == "super_admin";
}, ['guards' => ['admin']]);

Enter fullscreen mode Exit fullscreen mode

Becomes:

use Illuminate\Support\Facades\Broadcast;

Broadcast::channel('new_user_channel', NewUserChannel::class , ['guards' => ['admin']]);
Enter fullscreen mode Exit fullscreen mode

The Benefit of Using a Channel Class 🌟

** Broadcast Event Options **

  • broadcastas()
  • broadcastWith()
  • broadcastWhen()

1- The broadcastAs() Method: Custom Event Naming
When an event is broadcast, Laravel automatically sends it with the class name (e.g., App\Events\UserRegistered).

You can override this default name using the broadcastAs() method:


    public function broadcastAs(): string
    {
        return 'New_User_Registered_Event';
    }
Enter fullscreen mode Exit fullscreen mode

Frontend Listener: On the client side, you then listen using the custom name, preceded by a dot (.):


window.Echo.channel('new_user_channel')
    .listen(".New_User_Registered_Event", (e) => {
        console.log(e);

         let currentCount = parseInt($("#notificationIconCounter").text()) || 0;
         let newCount = currentCount + 1;
         $("#notificationIconCounter").text(newCount);
    });

Enter fullscreen mode Exit fullscreen mode

2- The broadcastWith() Method: Controlling Data
By default, Laravel broadcasts all the public properties of your Event class. However, you often don't want to expose all data.

To control exactly which data is sent , you can define the broadcastWith() method:

 public $message;

    public function __construct(public User $user)
    {
        $this->message = "new user registered called $user->name";
    }

public function broadcastWith(): array
    {
        return [
            'name' => $this->user->name,
            'email' => $this->user->email,
        ];
    }
Enter fullscreen mode Exit fullscreen mode


3- The broadcastWhen() method in a Laravel Event class lets you define a condition that must be true for the event to be broadcast at all. If the method returns false, the event won't be broadcast to any listeners, saving processing time and resources.

 public function broadcastWhen(): bool
    {
        return $this->user->name === 'ashrakt';
    }
Enter fullscreen mode Exit fullscreen mode

model broadcasting

You use Model Broadcasting when you need a real-time notification specifically because an Eloquent model was directly created, updated, or deleted in the database.


Here are the steps for setting up Model Broadcasting for the Post model to handle Create, Update, and Delete events, covering both the backend (Laravel) and frontend (JavaScript) configurations.

Laravel Backend

  1. The Post Model (app/Models/Post.php)
<?php

namespace App\Models;

use App\Models\User;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Broadcasting\Channel;
use Illuminate\Database\Eloquent\BroadcastsEvents;


class Post extends Model
{
    use BroadcastsEvents;
    protected $fillable = ['user_id', 'title', 'body'];


    public function user(): BelongsTo
    {
        return $this->belongsTo(User::class);
    }


    public function broadcastOn(): array
    {
        return [
            new Channel('posts'),
        ];
    }


    public function broadcastAs(string $event): string
    {
        // This will produce: 'post.created', 'post.updated', or 'post.deleted'
        return 'post.' . $event;
    }


    public function broadcastWith(): array
    {
        return [
            'id' => $this->id,
            'title' => $this->title,
            'user_name' => $this->user->name ?? 'N/A',
            'updated_at' => $this->updated_at->diffForHumans(),
        ];
    }
}
Enter fullscreen mode Exit fullscreen mode
<?php

namespace App\Http\Controllers;

use App\Models\Post;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Auth;

class PostController extends Controller
{

    public function index()
    {
        $posts = Post::all();
        return view('posts.index', compact('posts'));
    }


    public function store(Request $request)
    {
        $validated = $request->validate([
            'title' => 'required|string|max:150',
            'body' => 'required|string',
        ]);

        $post = Post::create([
            'user_id' => Auth::id(),
            'title' => $validated['title'],
            'body' => $validated['body'],
        ]);

        return redirect()->route('posts.index')->with('success', 'تم إنشاء المنشور بنجاح.');
    }

    public function edit(Post $post)
    {
        return view('posts.edit', compact('post'));
    }

    public function update(Request $request, Post $post)
    {
        $validated = $request->validate([
            'title' => 'required|string|max:150',
            'body' => 'required|string',
        ]);

        if (Auth::id() !== $post->user_id) {
            return back()->with('error', 'ليس لديك صلاحية لتعديل هذا المنشور.');
        }

        $post->update($validated);

        return redirect()->route('posts.index')->with('success', 'تم تحديث المنشور بنجاح.');
    }


    public function destroy(Post $post)
    {
        if (Auth::id() !== $post->user_id) {
            return back()->with('error', 'ليس لديك صلاحية لحذف هذا المنشور.');
        }

        $post->delete();

        return redirect()->route('posts.index')->with('success', 'تم حذف المنشور بنجاح.');
    }
}

Enter fullscreen mode Exit fullscreen mode

*Frontend Configuration (JavaScript/Echo) *

You must set up Laravel Echo to listen to the common channel ('posts') and handle each specific event type differently.

  1. Echo Listener Setup (Your Blade View or JS File) This JavaScript code listens for all three distinct events (.post.created, .post.updated, .post.deleted).

bootstrap.js file


import Echo from 'laravel-echo';

import Pusher from 'pusher-js';

window.Pusher = Pusher;

window.Echo = new Echo({
    broadcaster: 'pusher',
    key: import.meta.env.VITE_PUSHER_APP_KEY,
    cluster: import.meta.env.VITE_PUSHER_APP_CLUSTER ?? 'mt1',
    wsHost: import.meta.env.VITE_PUSHER_HOST ? import.meta.env.VITE_PUSHER_HOST : `ws-${import.meta.env.VITE_PUSHER_APP_CLUSTER}.pusher.com`,
    wsPort: import.meta.env.VITE_PUSHER_PORT ?? 80,
    wssPort: import.meta.env.VITE_PUSHER_PORT ?? 443,
    forceTLS: (import.meta.env.VITE_PUSHER_SCHEME ?? 'https') === 'https',
    enabledTransports: ['ws', 'wss'],
});


// model broadcasting

        // Listen to the common public channel 'posts'
window.Echo.channel('posts')
    // A. LISTEN FOR CREATE EVENT (post.created)
    .listen(".post.created", (event) => {
                console.log('New Post Created:', event.title);
    // B. LISTEN FOR UPDATE EVENT (post.updated)
    }).listen('.post.updated', (event) => {
                console.log('Post Updated:', event.id, event.title);
    })
    // C. LISTEN FOR DELETE EVENT (post.deleted)
   .listen('.post.deleted', (event) => {
                console.log('Post Deleted:', event.id);
    });
Enter fullscreen mode Exit fullscreen mode

-create post

-update post

-delete post


Top comments (0)