# Events

# How to send events to users?

Let's look at the example of a new alert notification.

Create a listener for the entity_post_save event with the hint XF\Entity\UserAlert.
Then create a new broadcasting event with UpdateAlerts name in YourAddon/Broadcasting/Events folder:

namespace YourAddon\Broadcasting\Events;

use BS\XFWebSockets\Broadcasting\Event;
use BS\XFWebSockets\Broadcasting\UserChannel;
use XF\Entity\UserAlert;

class UpdateAlerts implements Event
{
    public UserAlert $fromAlert;

    /**
     * Event constructor.
     * Save the alert from which we should load new alerts.
     * 
     * @param \XF\Entity\UserAlert $fromAlert
     */
    public function __construct(UserAlert $fromAlert)
    {
        $this->fromAlert = $fromAlert;
    }
    
    /**
     * The channels to which the event will be broadcast.
     */
    public function toChannels(): array
    {
        return [
            // Broadcast to the alert recipient's private channel.
            new UserChannel($this->fromAlert->alerted_user_id)
        ];
    }

    /**
     * The data to be broadcast.
     */
    public function payload(): array
    {
        return [
            'from_alert_id' => $this->fromAlert->alert_id
        ];
    }

    /**
     * Event name. 
     * Optional method. 
     * By default, the name of an event is its class.
     */
    public function broadcastAs(): string
    {
        return 'UpdateAlerts';
    }
}

Now we can broadcast this notification in the listener we created:

use BS\XFWebSockets\Broadcast;
use XF\Entity\UserAlert;

public static function postSaveUserAlert(UserAlert $alert)
{
    if (! $alert->isInsert()) {
        return;
    }

    Broadcast::event(
        'YourAddon:UpdateAlerts',
        $alert
    );
}

Users will now receive an UpdateAlerts event with the from_alert_id parameter on every alert.

# How to handle events?

Let's look at an example of handling the UpdateAlerts event we just created.

Create a new template modification to import watch.js file:

  • Template: helper_js_global
  • Modification key: your_adddon_helper_js_global_watch_js
  • Search type: Simple replacement
  • Find: <!--XF:JS-->
  • Replace:
$0
<xf:if is="$xf.visitor.user_id">
  <xf:js src="your_addon/watch.js" min="1" />
</xf:if>

Create a watch.js in the js/your_addon folder with the following content:

!function ( $, window, document ) {
  "use strict";

  XF.RealTimeAlerts = $.extend(XF.RealTimeAlerts || {}, {
    init () {
      /*
       * Listen to the `UpdateAlerts` event on the `visitor` channel.
       * The `visitor` channel is created automatically when the user is logged in.
       * 
       * getWebsocketsPromise() is a function that returns a promise 
       * that resolves when the WebSockets connection is established and you can subscribe to channels.
       * It resolves { manager: XF.EchoManager, echo: XF.Echo }.
       * 
       * ?. is the optional chaining operator, help to avoid errors when user has no permission to use WebSockets.
       */
      window.getWebsocketsPromise?.().then(( { echo, manager } ) => {
        manager.channels['visitor']
          .listen('UpdateAlerts', XF.proxy(this, 'updateAlerts'))
      })
    },

    updateAlerts ( { from_alert_id } ) {
      // Send a request to the server to get new alerts.
    }
  })

  $(document).ready(() => XF.RealTimeAlerts.init())
}
(window.jQuery, window, document);