Use notifications badge

This commit is contained in:
Eugene Burmakin 2024-11-03 15:21:29 +01:00
parent 14b7397840
commit bec9db1198
5 changed files with 61 additions and 33 deletions

File diff suppressed because one or more lines are too long

View file

@ -2,46 +2,73 @@ import { Controller } from "@hotwired/stimulus"
import consumer from "../channels/consumer"
export default class extends Controller {
static targets = ["container"]
static targets = ["badge"]
static values = { userId: Number }
initialize() {
this.subscription = null
}
connect() {
console.log("Controller connecting...")
// Ensure we clean up any existing subscription
console.log("[Stimulus] Notifications controller connecting...")
// Clean up any existing subscription
if (this.subscription) {
console.log("Cleaning up existing subscription")
console.log("[Stimulus] Cleaning up existing subscription")
this.subscription.unsubscribe()
this.subscription = null
}
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)
}
})
// Create new subscription
this.createSubscription()
}
disconnect() {
console.log("Controller disconnecting...")
console.log("[Stimulus] Notifications 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}`
createSubscription() {
console.log("[Stimulus] Creating new notification subscription")
this.subscription = consumer.subscriptions.create("NotificationsChannel", {
connected: () => {
console.log("[WebSocket] Connected to NotificationsChannel")
},
disconnected: () => {
console.log("[WebSocket] Disconnected from NotificationsChannel")
},
received: (data) => {
console.log("[WebSocket] Received notification:", data)
this.animateBadge()
}
})
}
this.containerTarget.appendChild(notification)
setTimeout(() => notification.remove(), 5000) // Auto-hide after 5 seconds
animateBadge() {
let badge = this.hasBadgeTarget ? this.badgeTarget : null
if (!badge) {
badge = document.createElement("span")
badge.className = "badge badge-xs badge-primary absolute top-0 right-0"
badge.setAttribute("data-notifications-target", "badge")
this.element.querySelector('.btn').appendChild(badge)
}
// Create ping effect div if it doesn't exist
let pingEffect = badge.querySelector('.ping-effect')
if (!pingEffect) {
pingEffect = document.createElement("span")
pingEffect.className = "ping-effect absolute inline-flex h-full w-full rounded-full animate-ping bg-primary opacity-75"
badge.appendChild(pingEffect)
} else {
// Reset animation
pingEffect.remove()
requestAnimationFrame(() => {
badge.appendChild(pingEffect)
})
}
}
}

View file

@ -18,13 +18,14 @@ class Notification < ApplicationRecord
private
def broadcast_notification
Rails.logger.debug "Broadcasting notification to #{user.id}"
NotificationsChannel.broadcast_to(
user,
{
id: id,
title: title,
content: content,
kind: kind
kind: kind,
timestamp: Time.current.to_i
}
)
end

View file

@ -21,9 +21,6 @@
<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>

View file

@ -53,7 +53,9 @@
<div class="navbar-end">
<ul class="menu menu-horizontal bg-base-100 rounded-box px-1">
<% if user_signed_in? %>
<div class="dropdown dropdown-end dropdown-bottom">
<div class="dropdown dropdown-end dropdown-bottom"
data-controller="notifications"
data-notifications-user-id-value="<%= current_user.id %>">
<div tabindex="0" role="button" class='btn btn-sm btn-ghost hover:btn-ghost'>
<svg
xmlns="http://www.w3.org/2000/svg"
@ -68,7 +70,8 @@
d="M15 17h5l-1.405-1.405A2.032 2.032 0 0118 14.158V11a6.002 6.002 0 00-4-5.659V5a2 2 0 10-4 0v.341C7.67 6.165 6 8.388 6 11v3.159c0 .538-.214 1.055-.595 1.436L4 17h5m6 0v1a3 3 0 11-6 0v-1m6 0H9" />
</svg>
<% if @unread_notifications.present? %>
<span class="badge badge-xs badge-primary"></span>
<span class="badge badge-xs badge-primary absolute top-0 right-0"
data-notifications-target="badge"></span>
<% end %>
</div>
<ul tabindex="0" class="dropdown-content z-10 menu p-2 shadow-lg bg-base-100 rounded-box min-w-52">