Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feature : adding a manager for notifications and integrating notifications into the appbar #13

Merged
merged 1 commit into from
Jan 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 50 additions & 0 deletions Components/Specific/Notifications/AppBarNotifications.razor
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
@using PartyGameTime.Core.Services.Notifications
@using PartyGameTime.Core.Model
@inject NotificationManager NotificationManager;

<MudBadge Color="Color.Secondary" Dot="true" Overlap="true" Visible="NotificationManager.NotificationsUnread()">
<MudMenu Icon="@Icons.Material.Outlined.Notifications" Color="Color.Inherit" AnchorOrigin="Origin.BottomCenter" TransformOrigin="Origin.TopRight" PopoverClass="docs-layout-menu-shadow" ListClass="pa-2 docs-menu-list" LockScroll="true">
<div class="d-flex justify-space-between align-center px-2">
<MudText Typo="Typo.subtitle2">Notifications</MudText>
<MudButton Disabled="@(NotificationManager.NotificationsUnread() == false)" OnClick="NotificationManager.MarkNotificationAllAsRead" StartIcon="@Icons.Material.Filled.DoneAll" Variant="Variant.Text" Color="Color.Primary" Class="ml-16 mr-n2">Mark as read</MudButton>
</div>
@if (NotificationManager.NotificationsUnread())
{
@foreach (var notification in NotificationManager.Notifications.Where(x=>x.Read == false).OrderByDescending(x=>x.CreatedAt))
{
<MudMenuItem Class="px-2 py-0 rounded" OnClick="(x) => OnClickOnNotification(x,notification)">
<MudText Typo="Typo.subtitle2">@notification.Title</MudText>
<MudText Typo="Typo.body2">@($"{notification.Content} • {notification.TimeSinceStr}")</MudText>
</MudMenuItem>
<MudDivider Class="my-2"/>
}
}
else
{
<div class="d-flex justify-center align-center px-2 py-8 relative">
<MudText Class="mud-text-secondary my-12">No new notifications</MudText>
<MudBlazorLogo Class="docs-logo-filter mx-16 absolute"/>

Check warning on line 26 in Components/Specific/Notifications/AppBarNotifications.razor

View workflow job for this annotation

GitHub Actions / build

Found markup element with unexpected name 'MudBlazorLogo'. If this is intended to be a component, add a @using directive for its namespace.
</div>
}
</MudMenu>
</MudBadge>

@code {
protected override async Task OnInitializedAsync()
{
NotificationManager.OnNewNotification += (x) => Refresh();
NotificationManager.OnNotificationRead += () => Refresh();
}

private void Refresh()
{
StateHasChanged();
}

private void OnClickOnNotification(MouseEventArgs e, Notification notification)
{
NotificationManager.MarkNotificationAsRead(notification);
notification.OnClickAction?.Invoke();
Refresh();
}
}
26 changes: 26 additions & 0 deletions Core/Model/Notification.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
namespace PartyGameTime.Core.Model;

public class Notification
{
public Guid Id { get; set; }
public string Title { get; set; }

Check warning on line 6 in Core/Model/Notification.cs

View workflow job for this annotation

GitHub Actions / build

Non-nullable property 'Title' must contain a non-null value when exiting constructor. Consider declaring the property as nullable.
public string Content { get; set; }
public bool Read { get; set; }
public Action OnClickAction { get; set; }
public DateTime CreatedAt { get; set; } = DateTime.Now;
public string TimeSinceStr
{
get
{
var difference = DateTime.Now - CreatedAt;

if (difference.Days > 0)
return difference.Days.ToString() + "day(s) ago";

if (difference.Hours > 0)
return difference.Hours.ToString() + "hour(s) ago";

return difference.Minutes.ToString() + "min(s) ago";
}
}
}
59 changes: 59 additions & 0 deletions Core/Services/Notifications/NotificationManager.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
using PartyGameTime.Core.Model;

namespace PartyGameTime.Core.Services.Notifications;

public class NotificationManager
{
public NotificationManager()

Check warning on line 7 in Core/Services/Notifications/NotificationManager.cs

View workflow job for this annotation

GitHub Actions / build

Non-nullable event 'OnNewNotification' must contain a non-null value when exiting constructor. Consider declaring the event as nullable.

Check warning on line 7 in Core/Services/Notifications/NotificationManager.cs

View workflow job for this annotation

GitHub Actions / build

Non-nullable event 'OnNotificationRead' must contain a non-null value when exiting constructor. Consider declaring the event as nullable.
{

}

public List<Notification> Notifications { get; set; } = new List<Notification>();
public event Action<Notification> OnNewNotification;
public event Action OnNotificationRead;

public void SendNotification(Notification notification)
{
Notifications.Add(notification);
OnNewNotification?.Invoke(notification);
}

public void SendNotification(string title, string content)
{
var notification = new Notification
{
Content = content,
Title = title,
CreatedAt = DateTime.Now
};
SendNotification(notification);
}

public async Task<List<Notification>> GetNotifications()

Check warning on line 33 in Core/Services/Notifications/NotificationManager.cs

View workflow job for this annotation

GitHub Actions / build

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.
{
return Notifications;
}

public void MarkNotificationAsRead(Notification notification)
{
var notif = Notifications.FirstOrDefault(x => x.Id == notification.Id);
if (notif is not null)
{
notif.Read = true;
OnNotificationRead?.Invoke();
}
}
public void MarkNotificationAllAsRead()
{
Notifications.ForEach(x => x.Read = true);
OnNotificationRead?.Invoke();
}

public bool NotificationsUnread()
{
return Notifications.Any(x => x.Read == false);
}


}
9 changes: 9 additions & 0 deletions Pages/Settings/Account/Account.razor
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
@page "/settings/account"
@using System.Security.Claims
@using System.ComponentModel.DataAnnotations
@using PartyGameTime.Core.Model
@using PartyGameTime.Core.Services.Notifications
@inject AccountManager AccountManager
@inject AuthenticationStateProvider AuthenticationStateProvider
@inject ISnackbar _snackbar
@inject IDialogService DialogService
@inject NotificationManager NotificationManager;

<MudGrid Justify="Justify.Center" Class="mt-16">
<MudItem xs="12">
Expand Down Expand Up @@ -45,6 +48,12 @@
{
userName = await AccountManager.GetCurrentUserUsername();
email = await AccountManager.GetCurrentUserEmail();
var test = new Notification();
test.Content = "Ceci est un test !";
test.Title = "Une notif";
test.CreatedAt = DateTime.Now;

NotificationManager.SendNotification(test);
}

private async Task UpdateAccount()
Expand Down
3 changes: 2 additions & 1 deletion Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
using PartyGameTime.Core.Model;
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using PartyGameTime.Core.Auth;
using PartyGameTime.Core.Services.Notifications;


var builder = WebApplication.CreateBuilder(args);
Expand Down Expand Up @@ -67,7 +68,7 @@
builder.Services.AddScoped<RoleManager<AccountRole>>();
builder.Services.AddScoped<SignInManager<Account>>();
builder.Services.AddScoped<AccountManager>();

builder.Services.AddScoped<NotificationManager>();


// Services injection end
Expand Down
3 changes: 2 additions & 1 deletion Shared/MainLayout.razor
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
@inherits LayoutComponentBase
@inject GlobalValuesManager _gvManager;
@using Components.Specific;

<PageTitle>PartyGameTime</PageTitle>

<Authorized>

Check warning on line 7 in Shared/MainLayout.razor

View workflow job for this annotation

GitHub Actions / build

Found markup element with unexpected name 'Authorized'. If this is intended to be a component, add a @using directive for its namespace.
<MudLayout>
<MudAppBar Elevation="1">
<MudIconButton Icon="@Icons.Material.Filled.Menu" Color="Color.Inherit" Edge="Edge.Start" OnClick="@((e) => DrawerToggle())" />
<MudText Typo="Typo.h5" Class="ml-3">PartyGameTime</MudText>
<MudSpacer />
<MudIconButton Icon="@Icons.Material.Filled.MoreVert" Color="Color.Inherit" Edge="Edge.End" />
<AppBarNotifications />
</MudAppBar>
<MudDrawer @bind-Open="_drawerOpen" ClipMode="DrawerClipMode.Always" Elevation="2">
<NavMenu/>
Expand Down
1 change: 1 addition & 0 deletions _Imports.razor
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,10 @@
@using PartyGameTime
@using PartyGameTime.Shared
@using MudBlazor
@using Microsoft.AspNetCore.Components.Authorization

Check warning on line 12 in _Imports.razor

View workflow job for this annotation

GitHub Actions / build

The using directive for 'Microsoft.AspNetCore.Components.Authorization' appeared previously in this namespace
@using Microsoft.AspNetCore.Authorization

Check warning on line 13 in _Imports.razor

View workflow job for this annotation

GitHub Actions / build

The using directive for 'Microsoft.AspNetCore.Authorization' appeared previously in this namespace
@using PartyGameTime.Core.Auth
@using PartyGameTime.Components
@using PartyGameTime.Components.Dialog
@using PartyGameTime.Components.Specific.Notifications
@attribute [Authorize]
Loading