[ADD] NOTIFICATION: Added notification sound
This commit is contained in:
@@ -1750,6 +1750,15 @@ class PenaltyAccounts(HorillaModel):
|
||||
ordering = ["-created_at"]
|
||||
|
||||
|
||||
class NotificationSound(models.Model):
|
||||
from employee.models import Employee
|
||||
|
||||
employee = models.OneToOneField(
|
||||
Employee, on_delete=models.CASCADE, related_name="notification_sound"
|
||||
)
|
||||
sound_enabled = models.BooleanField(default=False)
|
||||
|
||||
|
||||
@receiver(post_save, sender=PenaltyAccounts)
|
||||
def create_deduction_cutleave_from_penalty(sender, instance, created, **kwargs):
|
||||
"""
|
||||
|
||||
@@ -8,36 +8,29 @@ var notify_refresh_period = 15000;
|
||||
var consecutive_misfires = 0;
|
||||
var registered_functions = [];
|
||||
|
||||
function fill_notification_badge(data) {
|
||||
var badges = document.getElementsByClassName(notify_badge_class);
|
||||
if (badges) {
|
||||
for(var i = 0; i < badges.length; i++){
|
||||
badges[i].innerHTML = data.unread_count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function fill_notification_list(data) {
|
||||
var menus = document.getElementsByClassName(notify_menu_class);
|
||||
if (menus) {
|
||||
var messages = data.unread_list.map(function (item) {
|
||||
var message = "";
|
||||
if(typeof item.actor !== 'undefined'){
|
||||
message = item.actor;
|
||||
}
|
||||
if(typeof item.verb !== 'undefined'){
|
||||
message = message + " " + item.verb;
|
||||
}
|
||||
if(typeof item.target !== 'undefined'){
|
||||
message = message + " " + item.target;
|
||||
}
|
||||
if(typeof item.timestamp !== 'undefined'){
|
||||
message = message + " " + item.timestamp;
|
||||
}
|
||||
return '<li>' + message + '</li>';
|
||||
}).join('')
|
||||
var messages = data.unread_list
|
||||
.map(function (item) {
|
||||
var message = "";
|
||||
if (typeof item.actor !== "undefined") {
|
||||
message = item.actor;
|
||||
}
|
||||
if (typeof item.verb !== "undefined") {
|
||||
message = message + " " + item.verb;
|
||||
}
|
||||
if (typeof item.target !== "undefined") {
|
||||
message = message + " " + item.target;
|
||||
}
|
||||
if (typeof item.timestamp !== "undefined") {
|
||||
message = message + " " + item.timestamp;
|
||||
}
|
||||
return "<li>" + message + "</li>";
|
||||
})
|
||||
.join("");
|
||||
|
||||
for (var i = 0; i < menus.length; i++){
|
||||
for (var i = 0; i < menus.length; i++) {
|
||||
menus[i].innerHTML = messages;
|
||||
}
|
||||
}
|
||||
@@ -51,30 +44,30 @@ function fetch_api_data() {
|
||||
if (registered_functions.length > 0) {
|
||||
//only fetch data if a function is setup
|
||||
var r = new XMLHttpRequest();
|
||||
r.addEventListener('readystatechange', function(event){
|
||||
if (this.readyState === 4){
|
||||
if (this.status === 200){
|
||||
r.addEventListener("readystatechange", function (event) {
|
||||
if (this.readyState === 4) {
|
||||
if (this.status === 200) {
|
||||
consecutive_misfires = 0;
|
||||
var data = JSON.parse(r.responseText);
|
||||
for(var i = 0; i < registered_functions.length; i++) {
|
||||
registered_functions[i](data);
|
||||
for (var i = 0; i < registered_functions.length; i++) {
|
||||
registered_functions[i](data);
|
||||
}
|
||||
}else{
|
||||
} else {
|
||||
consecutive_misfires++;
|
||||
}
|
||||
}
|
||||
})
|
||||
r.open("GET", notify_api_url+'?max='+notify_fetch_count, true);
|
||||
});
|
||||
r.open("GET", notify_api_url + "?max=" + notify_fetch_count, true);
|
||||
r.send();
|
||||
}
|
||||
if (consecutive_misfires < 10) {
|
||||
setTimeout(fetch_api_data,notify_refresh_period);
|
||||
setTimeout(fetch_api_data, notify_refresh_period);
|
||||
} else {
|
||||
var badges = document.getElementsByClassName(notify_badge_class);
|
||||
if (badges) {
|
||||
for (var i = 0; i < badges.length; i++){
|
||||
for (var i = 0; i < badges.length; i++) {
|
||||
badges[i].innerHTML = "!";
|
||||
badges[i].title = "Connection lost!"
|
||||
badges[i].title = "Connection lost!";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ from distutils.version import ( # pylint: disable=no-name-in-module,import-erro
|
||||
)
|
||||
|
||||
from django import get_version
|
||||
from django.urls import path
|
||||
|
||||
from . import views
|
||||
|
||||
@@ -44,6 +45,11 @@ urlpatterns = [
|
||||
views.live_all_notification_list,
|
||||
name="live_all_notification_list",
|
||||
),
|
||||
path(
|
||||
"notification-sound",
|
||||
views.notification_sound,
|
||||
name="notification-sound",
|
||||
),
|
||||
]
|
||||
|
||||
app_name = "notifications"
|
||||
|
||||
@@ -7,12 +7,14 @@ from distutils.version import ( # pylint: disable=no-name-in-module,import-erro
|
||||
from django import get_version
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.forms import model_to_dict
|
||||
from django.http import HttpResponse # noqa
|
||||
from django.shortcuts import get_object_or_404, redirect
|
||||
from django.utils.decorators import method_decorator
|
||||
from django.views.decorators.cache import never_cache
|
||||
from django.views.generic import ListView
|
||||
from swapper import load_model
|
||||
|
||||
from base.models import NotificationSound
|
||||
from notifications import settings
|
||||
from notifications.settings import get_config
|
||||
from notifications.utils import id2slug, slug2id
|
||||
@@ -25,8 +27,6 @@ else:
|
||||
# Django 1.6 doesn't have a proper JsonResponse
|
||||
import json
|
||||
|
||||
from django.http import HttpResponse # noqa
|
||||
|
||||
def date_handler(obj):
|
||||
return obj.isoformat() if hasattr(obj, "isoformat") else obj
|
||||
|
||||
@@ -248,3 +248,14 @@ def live_all_notification_count(request):
|
||||
"all_count": request.user.notifications.count(),
|
||||
}
|
||||
return JsonResponse(data)
|
||||
|
||||
|
||||
@login_required
|
||||
def notification_sound(request):
|
||||
employee = request.user.employee_get
|
||||
sound, created = NotificationSound.objects.get_or_create(employee=employee)
|
||||
if not created:
|
||||
sound.sound_enabled = not sound.sound_enabled
|
||||
sound.save()
|
||||
|
||||
return HttpResponse("")
|
||||
|
||||
BIN
static/static/audio/notification-sound.wav
Normal file
BIN
static/static/audio/notification-sound.wav
Normal file
Binary file not shown.
@@ -1,63 +1,104 @@
|
||||
{% load basefilters %}
|
||||
{% load static %}
|
||||
{% load i18n %}
|
||||
{% load notifications_tags %}
|
||||
{% notifications_unread as unread_count %}
|
||||
{% load basefilters %} {% load static %} {% load i18n %}
|
||||
{% load notifications_tags %} {% notifications_unread as unread_count %}
|
||||
|
||||
<div
|
||||
class="oh-navbar__notifications"
|
||||
id="notificationIcon"
|
||||
x-data="{open: false}"
|
||||
hx-get="{% url 'notifications' %}"
|
||||
hx-target="#notificationContainer"
|
||||
class="oh-navbar__notifications"
|
||||
id="notificationIcon"
|
||||
x-data="{open: false}"
|
||||
hx-get="{% url 'notifications' %}"
|
||||
hx-target="#notificationContainer"
|
||||
>
|
||||
<a href="#" class="oh-navbar__notification-link" @click="open = !open" title="Notifications">
|
||||
<ion-icon name="notifications-outline" class="oh-navbar__icon"></ion-icon>
|
||||
<span class="oh-navbar__notification-beacon">
|
||||
{% live_notify_badge %}
|
||||
</span>
|
||||
<a
|
||||
href="#"
|
||||
class="oh-navbar__notification-link"
|
||||
@click="open = !open"
|
||||
title="Notifications"
|
||||
>
|
||||
<ion-icon
|
||||
name="notifications-outline"
|
||||
class="oh-navbar__icon"
|
||||
></ion-icon>
|
||||
<span class="oh-navbar__notification-beacon">
|
||||
{% live_notify_badge %}
|
||||
</span>
|
||||
</a>
|
||||
|
||||
<div id="showallnotificationbtn" class="oh-navbar__notification-tray"
|
||||
x-data="{markRead: false, visible: true}" x-show="open" style="display: none;"
|
||||
@click.outside="open = false">
|
||||
<div id="notificationContainer">
|
||||
{% include 'notification/notification_items.html' %}
|
||||
</div>
|
||||
<div class="oh-navbar__notification-footer" x-show="visible">
|
||||
<a
|
||||
{% comment %} href="{% url 'notifications:all' %}" {% endcomment %}
|
||||
id="viewallnotification"
|
||||
data-target="#allNotifications"
|
||||
hx-get="{% url 'all-notifications' %}"
|
||||
hx-target="#allNotificationBody"
|
||||
class="oh-navbar__notification-tray-link oh-activity-sidebar__open">{% trans "View all notifications" %}</a>
|
||||
</div>
|
||||
<div class="oh-navbar__notification-empty" x-show="!visible">
|
||||
<img src="{% static 'images/ui/happy.svg' %}" alt="All caught up" width="50" height="50" loading="lazy" />
|
||||
<span class="oh-navbar__notification-empty-title">{% trans "All caught up!" %}</span>
|
||||
<span class="oh-navbar__notification-empty-desc">{% trans "You have no new notifications at the moment." %}</span>
|
||||
</div>
|
||||
<div
|
||||
id="showallnotificationbtn"
|
||||
class="oh-navbar__notification-tray"
|
||||
x-data="{markRead: false, visible: true}"
|
||||
x-show="open"
|
||||
style="display: none"
|
||||
@click.outside="open = false"
|
||||
>
|
||||
<div id="notificationContainer">
|
||||
{% include 'notification/notification_items.html' %}
|
||||
</div>
|
||||
<div class="oh-navbar__notification-empty" x-show="!visible">
|
||||
<img
|
||||
src="{% static 'images/ui/happy.svg' %}"
|
||||
alt="All caught up"
|
||||
width="50"
|
||||
height="50"
|
||||
loading="lazy"
|
||||
/>
|
||||
<span class="oh-navbar__notification-empty-title"
|
||||
>{% trans "All caught up!" %}</span
|
||||
>
|
||||
<span class="oh-navbar__notification-empty-desc"
|
||||
>{% trans "You have no new notifications at the moment." %}</span
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="{% static 'notifications/notify.js' %}" type="text/javascript"></script>
|
||||
{% register_notify_callbacks callbacks='fill_notification_list,fill_notification_badge' %}
|
||||
<script>
|
||||
function markAsRead(notificationId) {
|
||||
fetch('/notifications/mark-as-read/' + notificationId + '/')
|
||||
.then(response => {
|
||||
if (response.ok) {
|
||||
// Reload the page to update the notifications
|
||||
location.reload();
|
||||
} else {
|
||||
console.error('Failed to mark notification as read');
|
||||
}
|
||||
});
|
||||
}
|
||||
var staticUrl = $("#statiUrl").attr("data-url");
|
||||
var notification_sound = {{request.user.employee_get.notification_sound.sound_enabled|yesno:"true,false"}};
|
||||
function fill_notification_badge(data) {
|
||||
var badges = document.getElementsByClassName(notify_badge_class);
|
||||
let previousUnreadCount = parseInt(localStorage.getItem('previousUnreadCount')) || 0;
|
||||
if (notification_sound) {
|
||||
if (
|
||||
previousUnreadCount !== null &&
|
||||
previousUnreadCount < data.unread_count
|
||||
) {
|
||||
const audio = new Audio(
|
||||
`${staticUrl}static/audio/notification-sound.wav`
|
||||
);
|
||||
audio.play();
|
||||
}
|
||||
}
|
||||
|
||||
$("#viewallnotification").click(function () {
|
||||
$("#showallnotificationbtn").toggle();
|
||||
});
|
||||
if (badges) {
|
||||
for (var i = 0; i < badges.length; i++) {
|
||||
badges[i].innerHTML = data.unread_count;
|
||||
}
|
||||
}
|
||||
localStorage.setItem('previousUnreadCount', data.unread_count);
|
||||
}
|
||||
|
||||
</script>
|
||||
<script
|
||||
src="{% static 'notifications/notify.js' %}"
|
||||
type="text/javascript"
|
||||
></script>
|
||||
{% register_notify_callbacks callbacks='fill_notification_list,fill_notification_badge' %}
|
||||
<script>
|
||||
function markAsRead(notificationId) {
|
||||
fetch("/notifications/mark-as-read/" + notificationId + "/").then(
|
||||
(response) => {
|
||||
if (response.ok) {
|
||||
// Reload the page to update the notifications
|
||||
location.reload();
|
||||
} else {
|
||||
console.error("Failed to mark notification as read");
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
$("#viewallnotification").click(function () {
|
||||
$("#showallnotificationbtn").toggle();
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -103,6 +103,27 @@
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="oh-navbar__notification-footer" x-show="visible" style="position:relative;">
|
||||
<a
|
||||
id="viewallnotification"
|
||||
data-target="#allNotifications"
|
||||
hx-get="{% url 'all-notifications' %}"
|
||||
hx-target="#allNotificationBody"
|
||||
class="oh-navbar__notification-tray-link oh-activity-sidebar__open"
|
||||
>{% trans "View all notifications" %} </a
|
||||
>
|
||||
<div class="oh-navbar__volume-icon" title="{% trans 'Notification Sound' %}" style="position:absolute; right:25px" hx-get="{% url 'notifications:notification-sound' %}" hx-swap="none">
|
||||
{% if request.user.employee_get.notification_sound.sound_enabled %}
|
||||
<span class="material-symbols-outlined text-danger">
|
||||
volume_up
|
||||
</span>
|
||||
{% else %}
|
||||
<span class="material-symbols-outlined text-danger">
|
||||
volume_off
|
||||
</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
$(document).ready(function () {
|
||||
$(".oh-navbar__notification-item").on("click", function (event) {
|
||||
|
||||
Reference in New Issue
Block a user