From 514a9726a986e90bd7391f6fe2d4c182f4373d1f Mon Sep 17 00:00:00 2001 From: Mukesh Murugan Date: Thu, 18 Mar 2021 19:25:43 +0530 Subject: [PATCH] added dashboard service --- .../GetData/DashboardDataResponse.cs | 16 ++++ .../GetData/GetDashboardDataQuery.cs | 41 ++++++++++ .../Services/Identity/IRoleService.cs | 1 + .../Services/Identity/IUserService.cs | 1 + .../Managers/Dashboard/DashboardManager.cs | 38 ++++++++++ .../Managers/Dashboard/IDashboardManager.cs | 12 +++ .../Routes/BrandsEndpoint.cs | 1 + .../Routes/DashboardEndpoint.cs | 13 ++++ .../Routes/ProductsEndpoint.cs | 2 +- .../Services/Identity/RoleService.cs | 5 ++ .../Services/Identity/UserService.cs | 6 ++ .../Catalog/AddEditProductModal.razor.cs | 1 + .../Client/Pages/Content/Dashboard.razor | 75 +++++++++++++++++++ .../Client/_Imports.razor | 4 +- .../v1/Catalog/BrandsController.cs | 2 +- .../v1/Catalog/ProductsController.cs | 1 - .../Controllers/v1/DashboardController.cs | 23 ++++++ 17 files changed, 238 insertions(+), 4 deletions(-) create mode 100644 BlazorHero.CleanArchitecture.Application/Features/Dashboard/GetData/DashboardDataResponse.cs create mode 100644 BlazorHero.CleanArchitecture.Application/Features/Dashboard/GetData/GetDashboardDataQuery.cs create mode 100644 BlazorHero.CleanArchitecture.Client.Infrastructure/Managers/Dashboard/DashboardManager.cs create mode 100644 BlazorHero.CleanArchitecture.Client.Infrastructure/Managers/Dashboard/IDashboardManager.cs create mode 100644 BlazorHero.CleanArchitecture.Client.Infrastructure/Routes/DashboardEndpoint.cs create mode 100644 BlazorHero.CleanArchitecture/Client/Pages/Content/Dashboard.razor create mode 100644 BlazorHero.CleanArchitecture/Server/Controllers/v1/DashboardController.cs diff --git a/BlazorHero.CleanArchitecture.Application/Features/Dashboard/GetData/DashboardDataResponse.cs b/BlazorHero.CleanArchitecture.Application/Features/Dashboard/GetData/DashboardDataResponse.cs new file mode 100644 index 000000000..d7a256d1c --- /dev/null +++ b/BlazorHero.CleanArchitecture.Application/Features/Dashboard/GetData/DashboardDataResponse.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace BlazorHero.CleanArchitecture.Application.Features.Dashboard.GetData +{ + public class DashboardDataResponse + { + public int ProductCount { get; set; } + public int BrandCount { get; set; } + public int UserCount { get; set; } + public int RoleCount { get; set; } + } +} diff --git a/BlazorHero.CleanArchitecture.Application/Features/Dashboard/GetData/GetDashboardDataQuery.cs b/BlazorHero.CleanArchitecture.Application/Features/Dashboard/GetData/GetDashboardDataQuery.cs new file mode 100644 index 000000000..4427bd802 --- /dev/null +++ b/BlazorHero.CleanArchitecture.Application/Features/Dashboard/GetData/GetDashboardDataQuery.cs @@ -0,0 +1,41 @@ +using BlazorHero.CleanArchitecture.Application.Interfaces.Repositories; +using BlazorHero.CleanArchitecture.Application.Interfaces.Services.Identity; +using BlazorHero.CleanArchitecture.Domain.Entities.Catalog; +using BlazorHero.CleanArchitecture.Shared.Wrapper; +using MediatR; +using Microsoft.EntityFrameworkCore; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace BlazorHero.CleanArchitecture.Application.Features.Dashboard.GetData +{ + public class GetDashboardDataQuery : IRequest> + { + public class GetDashboardDataQueryHandler : IRequestHandler> + { + private readonly IUnitOfWork _unitOfWork; + private readonly IUserService _userService; + private readonly IRoleService _roleService; + + public GetDashboardDataQueryHandler(IUnitOfWork unitOfWork, IUserService userService, IRoleService roleService) + { + _unitOfWork = unitOfWork; + _userService = userService; + _roleService = roleService; + } + public async Task> Handle(GetDashboardDataQuery query, CancellationToken cancellationToken) + { + var response = new DashboardDataResponse(); + response.ProductCount = await _unitOfWork.Repository().Entities.CountAsync(); + response.BrandCount = await _unitOfWork.Repository().Entities.CountAsync(); + response.UserCount = await _userService.GetCountAsync(); + response.RoleCount = await _roleService.GetCountAsync(); + return Result.Success(response); + } + } + } +} diff --git a/BlazorHero.CleanArchitecture.Application/Interfaces/Services/Identity/IRoleService.cs b/BlazorHero.CleanArchitecture.Application/Interfaces/Services/Identity/IRoleService.cs index 5588a16d1..920609c92 100644 --- a/BlazorHero.CleanArchitecture.Application/Interfaces/Services/Identity/IRoleService.cs +++ b/BlazorHero.CleanArchitecture.Application/Interfaces/Services/Identity/IRoleService.cs @@ -10,6 +10,7 @@ namespace BlazorHero.CleanArchitecture.Application.Interfaces.Services.Identity public interface IRoleService : IService { Task>> GetAllAsync(); + Task GetCountAsync(); Task> GetByIdAsync(string id); diff --git a/BlazorHero.CleanArchitecture.Application/Interfaces/Services/Identity/IUserService.cs b/BlazorHero.CleanArchitecture.Application/Interfaces/Services/Identity/IUserService.cs index bdbd426f9..51802ddce 100644 --- a/BlazorHero.CleanArchitecture.Application/Interfaces/Services/Identity/IUserService.cs +++ b/BlazorHero.CleanArchitecture.Application/Interfaces/Services/Identity/IUserService.cs @@ -10,6 +10,7 @@ namespace BlazorHero.CleanArchitecture.Application.Interfaces.Services.Identity public interface IUserService : IService { Task>> GetAllAsync(); + Task GetCountAsync(); Task> GetAsync(string userId); diff --git a/BlazorHero.CleanArchitecture.Client.Infrastructure/Managers/Dashboard/DashboardManager.cs b/BlazorHero.CleanArchitecture.Client.Infrastructure/Managers/Dashboard/DashboardManager.cs new file mode 100644 index 000000000..6bf4abcbd --- /dev/null +++ b/BlazorHero.CleanArchitecture.Client.Infrastructure/Managers/Dashboard/DashboardManager.cs @@ -0,0 +1,38 @@ +using BlazorHero.CleanArchitecture.Application.Features.Dashboard.GetData; +using BlazorHero.CleanArchitecture.Client.Infrastructure.Extensions; +using BlazorHero.CleanArchitecture.Shared.Wrapper; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net.Http; +using System.Text; +using System.Threading.Tasks; + +namespace BlazorHero.CleanArchitecture.Client.Infrastructure.Managers.Dashboard +{ + public class DashboardManager : IDashboardManager + { + private readonly HttpClient _httpClient; + + public DashboardManager(HttpClient httpClient) + { + _httpClient = httpClient; + } + + public async Task> GetDataAsync() + { + try + { + var response = await _httpClient.GetAsync(Routes.DashboardEndpoint.GetData); + var data = await response.ToResult(); + return data; + } + catch (Exception ex) + { + + throw; + } + + } + } +} diff --git a/BlazorHero.CleanArchitecture.Client.Infrastructure/Managers/Dashboard/IDashboardManager.cs b/BlazorHero.CleanArchitecture.Client.Infrastructure/Managers/Dashboard/IDashboardManager.cs new file mode 100644 index 000000000..3c135f09f --- /dev/null +++ b/BlazorHero.CleanArchitecture.Client.Infrastructure/Managers/Dashboard/IDashboardManager.cs @@ -0,0 +1,12 @@ +using BlazorHero.CleanArchitecture.Application.Features.Dashboard.GetData; +using BlazorHero.CleanArchitecture.Shared.Wrapper; +using System.Threading.Tasks; + +namespace BlazorHero.CleanArchitecture.Client.Infrastructure.Managers.Dashboard +{ + public interface IDashboardManager : IManager + { + Task> GetDataAsync(); + + } +} diff --git a/BlazorHero.CleanArchitecture.Client.Infrastructure/Routes/BrandsEndpoint.cs b/BlazorHero.CleanArchitecture.Client.Infrastructure/Routes/BrandsEndpoint.cs index e2657fd64..ee08cf661 100644 --- a/BlazorHero.CleanArchitecture.Client.Infrastructure/Routes/BrandsEndpoint.cs +++ b/BlazorHero.CleanArchitecture.Client.Infrastructure/Routes/BrandsEndpoint.cs @@ -5,5 +5,6 @@ public static class BrandsEndpoint public static string GetAll = "api/v1/brands"; public static string Delete = "api/v1/brands"; public static string Save = "api/v1/brands"; + public static string GetCount = "api/v1/brands/count"; } } \ No newline at end of file diff --git a/BlazorHero.CleanArchitecture.Client.Infrastructure/Routes/DashboardEndpoint.cs b/BlazorHero.CleanArchitecture.Client.Infrastructure/Routes/DashboardEndpoint.cs new file mode 100644 index 000000000..50990cd3e --- /dev/null +++ b/BlazorHero.CleanArchitecture.Client.Infrastructure/Routes/DashboardEndpoint.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace BlazorHero.CleanArchitecture.Client.Infrastructure.Routes +{ + public class DashboardEndpoint + { + public static string GetData = "api/v1/dashboard"; + } +} diff --git a/BlazorHero.CleanArchitecture.Client.Infrastructure/Routes/ProductsEndpoint.cs b/BlazorHero.CleanArchitecture.Client.Infrastructure/Routes/ProductsEndpoint.cs index a6a97107d..5e4a9ce9d 100644 --- a/BlazorHero.CleanArchitecture.Client.Infrastructure/Routes/ProductsEndpoint.cs +++ b/BlazorHero.CleanArchitecture.Client.Infrastructure/Routes/ProductsEndpoint.cs @@ -6,7 +6,7 @@ public static string GetAllPaged(int pageNumber, int pageSize) { return $"api/v1/products?pageNumber={pageNumber}&pageSize={pageSize}"; } - + public static string GetCount = "api/v1/products/count"; public static string GetProductImage(int productId) { return $"api/v1/products/image/{productId}"; diff --git a/BlazorHero.CleanArchitecture.Infrastructure/Services/Identity/RoleService.cs b/BlazorHero.CleanArchitecture.Infrastructure/Services/Identity/RoleService.cs index 787df0904..7dfed5cb9 100644 --- a/BlazorHero.CleanArchitecture.Infrastructure/Services/Identity/RoleService.cs +++ b/BlazorHero.CleanArchitecture.Infrastructure/Services/Identity/RoleService.cs @@ -157,5 +157,10 @@ public async Task> UpdatePermissionsAsync(PermissionRequest reque return Result.Fail(ex.Message); } } + public async Task GetCountAsync() + { + var count = await _roleManager.Roles.CountAsync(); + return count; + } } } \ No newline at end of file diff --git a/BlazorHero.CleanArchitecture.Infrastructure/Services/Identity/UserService.cs b/BlazorHero.CleanArchitecture.Infrastructure/Services/Identity/UserService.cs index 0b5647cad..9b2537d92 100644 --- a/BlazorHero.CleanArchitecture.Infrastructure/Services/Identity/UserService.cs +++ b/BlazorHero.CleanArchitecture.Infrastructure/Services/Identity/UserService.cs @@ -215,5 +215,11 @@ public async Task ResetPasswordAsync(ResetPasswordRequest request) return Result.Fail("An Error has occured!"); } } + + public async Task GetCountAsync() + { + var count = await _userManager.Users.CountAsync(); + return count; + } } } \ No newline at end of file diff --git a/BlazorHero.CleanArchitecture/Client/Pages/Catalog/AddEditProductModal.razor.cs b/BlazorHero.CleanArchitecture/Client/Pages/Catalog/AddEditProductModal.razor.cs index c1a0decce..c361591e8 100644 --- a/BlazorHero.CleanArchitecture/Client/Pages/Catalog/AddEditProductModal.razor.cs +++ b/BlazorHero.CleanArchitecture/Client/Pages/Catalog/AddEditProductModal.razor.cs @@ -57,6 +57,7 @@ private async Task SaveAsync() form.Validate(); if (form.IsValid) { + //TODO: Try to integrate validation with Mudblazor component - Select if (BrandId == 0) { _snackBar.Add("Select a Brand.", Severity.Error); diff --git a/BlazorHero.CleanArchitecture/Client/Pages/Content/Dashboard.razor b/BlazorHero.CleanArchitecture/Client/Pages/Content/Dashboard.razor new file mode 100644 index 000000000..9cb50762e --- /dev/null +++ b/BlazorHero.CleanArchitecture/Client/Pages/Content/Dashboard.razor @@ -0,0 +1,75 @@ +@page "/dashboard" +@inject Microsoft.Extensions.Localization.IStringLocalizer localizer + + + + + +
+ Products + @ProductCount +
+
+
+ + + +
+ Brands + @BrandCount +
+
+
+ + + +
+ Registered Users + @UserCount +
+
+
+ + + +
+ Registered Roles + @RoleCount +
+
+
+ + + Charts comming soon ish... + + + + + Charts comming soon ish... + + +
+@code{ + + [Parameter] + public int ProductCount { get; set; } + [Parameter] + public int BrandCount { get; set; } + [Parameter] + public int UserCount { get; set; } + [Parameter] + public int RoleCount { get; set; } + protected override async Task OnInitializedAsync() => await LoadDataAsync(); + + private async Task LoadDataAsync() + { + var data = await _dashboardManager.GetDataAsync(); + if(data.Succeeded) + { + ProductCount = data.Data.ProductCount; + BrandCount = data.Data.BrandCount; + UserCount = data.Data.UserCount; + RoleCount = data.Data.RoleCount; + } + } +} diff --git a/BlazorHero.CleanArchitecture/Client/_Imports.razor b/BlazorHero.CleanArchitecture/Client/_Imports.razor index 6e435e701..44ac4ff16 100644 --- a/BlazorHero.CleanArchitecture/Client/_Imports.razor +++ b/BlazorHero.CleanArchitecture/Client/_Imports.razor @@ -20,6 +20,7 @@ @using BlazorHero.CleanArchitecture.Client.Infrastructure.Managers.Preferences @using BlazorHero.CleanArchitecture.Client.Infrastructure.Managers.Catalog.Product @using BlazorHero.CleanArchitecture.Client.Infrastructure.Managers.Catalog.Brand +@using BlazorHero.CleanArchitecture.Client.Infrastructure.Managers.Dashboard @*Shared Libraries*@ @using BlazorHero.CleanArchitecture.Shared.Constants.Permission @@ -51,4 +52,5 @@ @inject IRoleManager _roleManager @inject IUserManager _userManager @inject IProductManager _productManager -@inject IBrandManager _brandManager \ No newline at end of file +@inject IBrandManager _brandManager +@inject IDashboardManager _dashboardManager \ No newline at end of file diff --git a/BlazorHero.CleanArchitecture/Server/Controllers/v1/Catalog/BrandsController.cs b/BlazorHero.CleanArchitecture/Server/Controllers/v1/Catalog/BrandsController.cs index e1006bb90..1f35d866d 100644 --- a/BlazorHero.CleanArchitecture/Server/Controllers/v1/Catalog/BrandsController.cs +++ b/BlazorHero.CleanArchitecture/Server/Controllers/v1/Catalog/BrandsController.cs @@ -26,7 +26,7 @@ public async Task GetById(int id) var brand = await _mediator.Send(new GetBrandByIdQuery() { Id = id }); return Ok(brand); } - + [Authorize(Policy = Permissions.Brands.Create)] [HttpPost] public async Task Post(AddEditBrandCommand command) diff --git a/BlazorHero.CleanArchitecture/Server/Controllers/v1/Catalog/ProductsController.cs b/BlazorHero.CleanArchitecture/Server/Controllers/v1/Catalog/ProductsController.cs index 256ccaf4d..844c707e8 100644 --- a/BlazorHero.CleanArchitecture/Server/Controllers/v1/Catalog/ProductsController.cs +++ b/BlazorHero.CleanArchitecture/Server/Controllers/v1/Catalog/ProductsController.cs @@ -26,7 +26,6 @@ public async Task GetProductImageAsync(int id) var result = await _mediator.Send(new GetProductImageQuery(id)); return Ok(result); } - [Authorize(Policy = Permissions.Products.Create)] [HttpPost] public async Task Post(AddEditProductCommand command) diff --git a/BlazorHero.CleanArchitecture/Server/Controllers/v1/DashboardController.cs b/BlazorHero.CleanArchitecture/Server/Controllers/v1/DashboardController.cs new file mode 100644 index 000000000..6e23c7a31 --- /dev/null +++ b/BlazorHero.CleanArchitecture/Server/Controllers/v1/DashboardController.cs @@ -0,0 +1,23 @@ +using BlazorHero.CleanArchitecture.Application.Features.Dashboard.GetData; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace BlazorHero.CleanArchitecture.Server.Controllers.v1 +{ + [ApiController] + public class DashboardController : BaseApiController + { + [Authorize] + [HttpGet] + public async Task GetDataAsync() + { + var result = await _mediator.Send(new GetDashboardDataQuery()); + return Ok(result); + } + } +}