Skip to content

Commit

Permalink
Merge pull request #25 from EasyAbp/offcanvas
Browse files Browse the repository at this point in the history
Notifications offcanvas and real-time updates
  • Loading branch information
gdlcf88 authored Jul 8, 2024
2 parents 193556d + 6f084ca commit 2b7cda6
Show file tree
Hide file tree
Showing 22 changed files with 236 additions and 215 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
@using EasyAbp.ProcessManagement.Localization
@using Microsoft.AspNetCore.Mvc.Localization
@inject IHtmlLocalizer<ProcessManagementResource> L
@model EasyAbp.ProcessManagement.Web.Components.NotificationsOffcanvasWidget.NotificationsOffcanvasWidgetViewModel

<script>
const notificationLifetimeMilliseconds = @Model.Options.NotificationLifetime.TotalMilliseconds;
</script>

<style>
.svg-icon {
width: 24px;
height: 24px;
margin-right: 10px;
}
.state-update-time {
position: absolute;
bottom: 0;
right: 0;
padding: .8rem 1rem;
text-align: right !important;
}
.alert-purple {
background-color: #cf9ce6;
color: #212529;
}
.fade-in {
animation: fadeIn 0.5s;
}
.fade-out {
animation: fadeOut 0.5s;
}
@@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
@@keyframes fadeOut {
from { opacity: 1; }
to { opacity: 0; }
}
</style>

<div class="offcanvas offcanvas-end" tabindex="-1" id="notificationsOffcanvas"
aria-labelledby="notificationsOffcanvasLabel">
<div class="offcanvas-header">
<h5 class="offcanvas-title" id="notificationsOffcanvasLabel">@L["Notifications"]</h5>
<button type="button" class="btn-close text-reset" data-bs-dismiss="offcanvas" aria-label="Close"></button>
</div>
<div class="offcanvas-body">
<div id="alert-placeholder"></div>
</div>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
(function ($) {

abp.widgets.NotificationsOffcanvasWidget = function ($widget) {

function fetchAndShowAlerts() {
easyAbp.processManagement.notifications.notification.getList({
fromCreationTime: new Date(abp.clock.now() - notificationLifetimeMilliseconds),
userId: abp.currentUser.id,
dismissed: false,
maxResultCount: 10
}).then(function (res) {
var alertPlaceholder = $('#alert-placeholder');
var existingAlerts = alertPlaceholder.find('.alert');

var existingAlertIds = new Map();
existingAlerts.each(function () {
var id = $(this).data('id');
existingAlertIds.set(id, $(this));
});

res.items.forEach(function (item) {
if (!existingAlertIds.has(item.id)) {
var newAlert = createAlert(item);
alertPlaceholder.append(newAlert);
}
});

existingAlertIds.forEach(function (alert, id) {
if (!res.items.some(item => item.id === id)) {
alert.addClass('fade-out').one('animationend', function () {
$(this).remove();
});
}
});
});
}

function getAlertColorClassName(stateFlag) {
switch (stateFlag) {
case 1:
return "alert-dark";
case 2:
return "alert-success";
case 3:
return "alert-danger";
case 4:
return "alert-primary";
case 5:
return "alert-purple";
case 6:
return "alert-warning";
default:
break;
}
}

function createAlert(item) {
return $(`
<div class="alert ${getAlertColorClassName(item.stateFlag)} alert-dismissible fade-in" role="alert">
<div class="d-flex">
<img src="/images/process-management/icons/${item.stateFlag}.svg" class="svg-icon" alt=""/>
<div>
<strong>${item.actionName ? item.actionName : item.stateDisplayName}</strong>
<p class="small mb-4">
${item.stateSummaryText}
</p>
</div>
</div>
<div class="state-update-time">
<span class="small"><time class="timeago" datetime="${item.creationTime}">${item.creationTime}</time></span>
</div>
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
`).data('id', item.id);
}

function init() {
var offcanvasElement = document.getElementById('notificationsOffcanvas');
var intervalId;

offcanvasElement.addEventListener('show.bs.offcanvas', function () {
fetchAndShowAlerts();
intervalId = setInterval(fetchAndShowAlerts, 5000);
});

offcanvasElement.addEventListener('hide.bs.offcanvas', function () {
if (intervalId) clearInterval(intervalId);
});
}

return {
init: init
};
};
})(jQuery);
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
using System.Threading.Tasks;
using EasyAbp.ProcessManagement.Web.Options;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
using Volo.Abp.AspNetCore.Mvc;
using Volo.Abp.AspNetCore.Mvc.UI.Widgets;

namespace EasyAbp.ProcessManagement.Web.Components.NotificationsOffcanvasWidget;

[Widget(
AutoInitialize = true,
RefreshUrl = "/Widgets/ProcessManagement/NotificationsOffcanvas",
ScriptFiles = ["/Components/NotificationsOffcanvasWidget/Default.js"]
)]
public class NotificationsOffcanvasWidgetViewComponent : AbpViewComponent
{
protected ProcessManagementWebOptions Options =>
LazyServiceProvider.LazyGetRequiredService<IOptions<ProcessManagementWebOptions>>().Value;

public NotificationsOffcanvasWidgetViewComponent()
{
}

public virtual async Task<IViewComponentResult> InvokeAsync()
{
return View("~/Components/NotificationsOffcanvasWidget/Default.cshtml",
new NotificationsOffcanvasWidgetViewModel(Options));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using EasyAbp.ProcessManagement.Web.Options;

namespace EasyAbp.ProcessManagement.Web.Components.NotificationsOffcanvasWidget;

public class NotificationsOffcanvasWidgetViewModel
{
public ProcessManagementWebOptions Options { get; }

public NotificationsOffcanvasWidgetViewModel(ProcessManagementWebOptions options)
{
Options = options;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
@using EasyAbp.ProcessManagement.Localization
@using Microsoft.AspNetCore.Mvc.Localization
@inject IHtmlLocalizer<ProcessManagementResource> L
@model EasyAbp.ProcessManagement.Web.Components.NotificationsToolbarItemWidget.NotificationsToolbarItemWidgetViewModel

<div class="dropdown">
<a class="nav-link notifications-toolbar-item" data-bs-toggle="offcanvas" href="#notificationsOffcanvas" role="button" aria-controls="notificationsOffcanvas">
<i class="fas fa-bell"></i> @Model.UnreadCount
</a>
</div>
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,17 @@
using Volo.Abp.AspNetCore.Mvc;
using Volo.Abp.AspNetCore.Mvc.UI.Widgets;

namespace EasyAbp.ProcessManagement.Web.Components.NotificationsWidget;
namespace EasyAbp.ProcessManagement.Web.Components.NotificationsToolbarItemWidget;

[Widget(
AutoInitialize = true,
RefreshUrl = "/Widgets/ProcessManagement/Notifications",
ScriptFiles = ["/Components/NotificationsWidget/Default.js"]
RefreshUrl = "/Widgets/ProcessManagement/NotificationsToolbarItem"
)]
public class NotificationsWidgetViewComponent : AbpViewComponent
public class NotificationsToolbarItemWidgetViewComponent : AbpViewComponent
{
private readonly NotificationCountCache _notificationCountCache;

public NotificationsWidgetViewComponent(NotificationCountCache notificationCountCache)
public NotificationsToolbarItemWidgetViewComponent(NotificationCountCache notificationCountCache)
{
_notificationCountCache = notificationCountCache;
}
Expand All @@ -24,7 +23,7 @@ public virtual async Task<IViewComponentResult> InvokeAsync()
{
var notificationCount = await _notificationCountCache.GetOrAddAsync();

return View("~/Components/NotificationsWidget/Default.cshtml",
new NotificationsWidgetViewModel(notificationCount));
return View("~/Components/NotificationsToolbarItemWidget/Default.cshtml",
new NotificationsToolbarItemWidgetViewModel(notificationCount));
}
}
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
namespace EasyAbp.ProcessManagement.Web.Components.NotificationsWidget;
namespace EasyAbp.ProcessManagement.Web.Components.NotificationsToolbarItemWidget;

public class NotificationsWidgetViewModel
public class NotificationsToolbarItemWidgetViewModel
{
/// <summary>
/// 0~99 unread notifications.
/// </summary>
public int UnreadCount { get; set; }

public NotificationsWidgetViewModel()
public NotificationsToolbarItemWidgetViewModel()
{
}

public NotificationsWidgetViewModel(int unreadCount)
public NotificationsToolbarItemWidgetViewModel(int unreadCount)
{
UnreadCount = unreadCount;
}
Expand Down

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
<div id="ToolbarNotificationsWidgetArea">
@await Component.InvokeAsync("NotificationsWidget")
</div>
@await Component.InvokeAsync("NotificationsToolbarItemWidget")
</div>

<script>
setInterval(function () {
let widgetManager = new abp.WidgetManager({
wrapper: '#ToolbarNotificationsWidgetArea'
});
widgetManager.refresh();
}, 5000);
</script>
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ namespace EasyAbp.ProcessManagement.Web.Controllers;
public class ProcessManagementWidgetsController : AbpController
{
[HttpGet]
[Route("Notifications")]
public IActionResult Notifications()
[Route("NotificationsToolbarItem")]
public IActionResult NotificationsToolbarItem()
{
return ViewComponent("NotificationsWidget");
return ViewComponent("NotificationsToolbarItemWidget");
}
}

This file was deleted.

This file was deleted.

Loading

0 comments on commit 2b7cda6

Please sign in to comment.