Skip to content

Instantly share code, notes, and snippets.

@leastbad
Created March 25, 2021 16:05
Show Gist options
  • Save leastbad/b186f2b97d213b39f18505c8f05f8fb0 to your computer and use it in GitHub Desktop.
Save leastbad/b186f2b97d213b39f18505c8f05f8fb0 to your computer and use it in GitHub Desktop.
Notifications are fun (Devise, Bootstrap 5, Notyf, FontAwesome)
class ApplicationController < ActionController::Base
include CableReady::Broadcaster
include Toastable
end
class ApplicationJob < ActiveJob::Base
include CableReady::Broadcaster
delegate :render, to: :ApplicationController
end
module ApplicationCable
class Channel < ActionCable::Channel::Base
include CableReady::Broadcaster
delegate :render, to: :ApplicationController
end
end
module ApplicationCable
class Connection < ActionCable::Connection::Base
identified_by :session_id
identified_by :current_user
def connect
self.current_user = env["warden"].user
self.session_id = request.session.id
reject_unauthorized_connection unless current_user || session_id
end
end
end
export default {
position: {
x: 'right',
y: 'top'
},
types: [
{
type: 'primary',
background: '#0d6efd',
icon: {
className: 'fas fa-check',
tagName: 'i',
color: 'white'
}
},
{ type: 'secondary', background: '#6c757d' },
{
type: 'success',
background: '#198754',
icon: {
className: 'fas fa-thumbs-up',
tagName: 'i',
color: 'white'
}
},
{
type: 'danger',
background: '#dc3545',
icon: { className: 'fas fa-times', tagName: 'i', color: 'white' }
},
{ type: 'warning', background: '#ffc107' },
{
type: 'info',
background: '#0dcaf0',
icon: {
className: 'fas fa-exclamation-triangle',
tagName: 'i',
color: 'white'
}
},
{ type: 'light', background: '#f8f9fa' },
{ type: 'dark', background: '#212529' },
{
type: 'alert',
background: '#dc3545',
icon: { className: 'fas fa-times', tagName: 'i', color: 'white' }
},
{
type: 'notice',
background: '#0d6efd',
icon: {
className: 'fas fa-check',
tagName: 'i',
color: 'white'
}
}
]
}
class ToastJob < ApplicationJob
queue_as :default
def perform(user, type, message)
ActionCable.server.broadcast("users:#{user.to_gid_param}", {notification: [type, message]})
end
end
# frozen_string_literal: true
module Toastable
extend ActiveSupport::Concern
included do
add_flash_types :primary, :secondary, :success, :danger, :warning, :info, :light, :dark
after_action :broadcast_flash, if: :user_signed_in?
after_action :clear_flash, unless: :user_signed_in?
private
def broadcast_flash
flash.each { |k, v| ToastJob.set(wait: 2.second).perform_later(current_user, k, v) }
flash.clear
end
def clear_flash
flash.clear
end
end
end
import consumer from './consumer'
import CableReady from 'cable_ready'
import { Notyf } from 'notyf'
import flash from '../shared/notyf'
let channel
document.addEventListener('turbolinks:load', () => {
if (channel) return
channel = consumer.subscriptions.create('UsersChannel', {
received (data) {
if (!data) channel = undefined
if (data.notification) notify(data.notification)
if (data.cableReady) CableReady.perform(data.operations)
}
})
})
function notify (notification) {
new Notyf(flash).open({ type: notification[0], message: notification[1] })
}
class UsersChannel < ApplicationCable::Channel
def subscribed
if current_user
stream_for(current_user)
else
transmit false
reject
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment