mirror of
https://github.com/Freika/dawarich.git
synced 2026-01-10 01:01:39 -05:00
Add raw implementation of notifications interactive channel
This commit is contained in:
parent
34c12a9536
commit
14b7397840
12 changed files with 125 additions and 1 deletions
|
|
@ -1,4 +1,21 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module ApplicationCable
|
||||
class Connection < ActionCable::Connection::Base
|
||||
identified_by :current_user
|
||||
|
||||
def connect
|
||||
self.current_user = find_verified_user
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def find_verified_user
|
||||
if (verified_user = env['warden'].user)
|
||||
verified_user
|
||||
else
|
||||
reject_unauthorized_connection
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
7
app/channels/notifications_channel.rb
Normal file
7
app/channels/notifications_channel.rb
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class NotificationsChannel < ApplicationCable::Channel
|
||||
def subscribed
|
||||
stream_for current_user
|
||||
end
|
||||
end
|
||||
|
|
@ -8,3 +8,4 @@ import "leaflet"
|
|||
import "leaflet-providers"
|
||||
import "chartkick"
|
||||
import "Chart.bundle"
|
||||
import "./channels"
|
||||
|
|
|
|||
6
app/javascript/channels/consumer.js
Normal file
6
app/javascript/channels/consumer.js
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
// Action Cable provides the framework to deal with WebSockets in Rails.
|
||||
// You can generate new channels where WebSocket features live using the `bin/rails generate channel` command.
|
||||
|
||||
import { createConsumer } from "@rails/actioncable"
|
||||
|
||||
export default createConsumer()
|
||||
2
app/javascript/channels/index.js
Normal file
2
app/javascript/channels/index.js
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
// Import all the channels to be used by Action Cable
|
||||
import "notifications_channel"
|
||||
15
app/javascript/channels/notifications_channel.js
Normal file
15
app/javascript/channels/notifications_channel.js
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
import consumer from "./consumer"
|
||||
|
||||
consumer.subscriptions.create("NotificationsChannel", {
|
||||
connected() {
|
||||
console.log("Connected to the notifications channel!");
|
||||
},
|
||||
|
||||
disconnected() {
|
||||
// Called when the subscription has been terminated by the server
|
||||
},
|
||||
|
||||
received(data) {
|
||||
// Called when there's incoming data on the websocket for this channel
|
||||
}
|
||||
});
|
||||
47
app/javascript/controllers/notifications_controller.js
Normal file
47
app/javascript/controllers/notifications_controller.js
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
import { Controller } from "@hotwired/stimulus"
|
||||
import consumer from "../channels/consumer"
|
||||
|
||||
export default class extends Controller {
|
||||
static targets = ["container"]
|
||||
static values = { userId: Number }
|
||||
|
||||
connect() {
|
||||
console.log("Controller connecting...")
|
||||
// Ensure we clean up any existing subscription
|
||||
if (this.subscription) {
|
||||
console.log("Cleaning up existing subscription")
|
||||
this.subscription.unsubscribe()
|
||||
}
|
||||
|
||||
this.subscription = consumer.subscriptions.create("NotificationsChannel", {
|
||||
connected: () => {
|
||||
console.log("Connected to NotificationsChannel", this.subscription)
|
||||
},
|
||||
disconnected: () => {
|
||||
console.log("Disconnected from NotificationsChannel")
|
||||
},
|
||||
received: (data) => {
|
||||
console.log("Received notification:", data, "Subscription:", this.subscription)
|
||||
this.displayNotification(data)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
disconnect() {
|
||||
console.log("Controller disconnecting...")
|
||||
if (this.subscription) {
|
||||
this.subscription.unsubscribe()
|
||||
this.subscription = null
|
||||
}
|
||||
}
|
||||
|
||||
displayNotification(data) {
|
||||
console.log("Notification received:", data) // For debugging
|
||||
const notification = document.createElement("div")
|
||||
notification.classList.add("notification", `notification-${data.kind}`)
|
||||
notification.innerHTML = `<strong>${data.title}</strong>: ${data.content}`
|
||||
|
||||
this.containerTarget.appendChild(notification)
|
||||
setTimeout(() => notification.remove(), 5000) // Auto-hide after 5 seconds
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,8 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class Notification < ApplicationRecord
|
||||
after_create_commit :broadcast_notification
|
||||
|
||||
belongs_to :user
|
||||
|
||||
validates :title, :content, :kind, presence: true
|
||||
|
|
@ -12,4 +14,18 @@ class Notification < ApplicationRecord
|
|||
def read?
|
||||
read_at.present?
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def broadcast_notification
|
||||
Rails.logger.debug "Broadcasting notification to #{user.id}"
|
||||
NotificationsChannel.broadcast_to(
|
||||
user,
|
||||
{
|
||||
title: title,
|
||||
content: content,
|
||||
kind: kind
|
||||
}
|
||||
)
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
<head>
|
||||
<title><%= full_title(yield(:title)) %></title>
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||
<%= action_cable_meta_tag %>
|
||||
<%= csrf_meta_tags %>
|
||||
<%= csp_meta_tag %>
|
||||
|
||||
|
|
@ -20,6 +21,9 @@
|
|||
<div class='container mx-auto'>
|
||||
<%= render 'shared/navbar' %>
|
||||
<%= render 'shared/flash' %>
|
||||
<div data-controller="notifications" data-notifications-user-id-value="<%= current_user.id %>">
|
||||
<div data-notifications-target="container" class="notifications-container"></div>
|
||||
</div>
|
||||
<div class="flex flex-row gap-5 w-full px-5">
|
||||
<%= yield %>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -16,4 +16,7 @@ pin 'leaflet-providers' # @2.0.0
|
|||
pin 'chartkick', to: 'chartkick.js'
|
||||
pin 'Chart.bundle', to: 'Chart.bundle.js'
|
||||
pin 'leaflet.heat' # @0.2.0
|
||||
pin "leaflet-draw" # @1.0.4
|
||||
pin 'leaflet-draw' # @1.0.4
|
||||
pin '@rails/actioncable', to: 'actioncable.esm.js'
|
||||
pin_all_from 'app/javascript/channels', under: 'channels'
|
||||
pin 'notifications_channel', to: 'channels/notifications_channel.js'
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
require 'sidekiq/web'
|
||||
|
||||
Rails.application.routes.draw do
|
||||
mount ActionCable.server => '/cable'
|
||||
mount Rswag::Api::Engine => '/api-docs'
|
||||
mount Rswag::Ui::Engine => '/api-docs'
|
||||
authenticate :user, ->(u) { u.admin? } do
|
||||
|
|
|
|||
5
spec/channels/notifications_channel_spec.rb
Normal file
5
spec/channels/notifications_channel_spec.rb
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
require 'rails_helper'
|
||||
|
||||
RSpec.describe NotificationsChannel, type: :channel do
|
||||
pending "add some examples to (or delete) #{__FILE__}"
|
||||
end
|
||||
Loading…
Reference in a new issue