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

Adds unused tickets statistics #34

Merged
merged 7 commits into from
Apr 23, 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
92 changes: 92 additions & 0 deletions Shifty.App/Components/UnusedTickets.razor
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
@namespace Components
@using System.ComponentModel.DataAnnotations
@using Shifty.App.Services
@using Shifty.Api.Generated.AnalogCoreV1
@using Shifty.Api.Generated.AnalogCoreV2
@using Shifty.App.DomainModels
@using Shifty.App.Shared
@using Shared
@using LanguageExt.UnsafeValueAccess
@inject IUnusedTicketsService _unusedTicketsService
@inject ISnackbar Snackbar

<MudContainer MaxWidth="MaxWidth.Medium" Style="margin-top: 20px;">
<MudDataGrid
T="UnusedTicket"
Items="@Items"
Height="500px"
FixedFooter>
<ToolBarContent>
<MudText Typo="Typo.h6">Unused Tickets</MudText>
<MudSpacer />
@if (_loading)
TTA777 marked this conversation as resolved.
Show resolved Hide resolved
{
<LoadingIndicator Height="64px" />
}
<MudDateRangePicker DateRange="@_queryDateRange" Editable=true DateRangeChanged="LoadUnusedTickets"/>
</ToolBarContent>
<Columns>
<PropertyColumn Property="x => x.ProductId" Title="Product Id" />
<PropertyColumn Property="x => x.ProductName" Title="Product Name" AggregateDefinition="_footerLabel"/>
<PropertyColumn Property="x => x.TicketsLeft" Title="Unused Tickets" AggregateDefinition="_ticketsLeftSum" />
<PropertyColumn Property="x => x.UnusedPurchasesValue" Title="Unused value (DKK)" AggregateDefinition="_valueLeftSum">
<CellTemplate>
@context.Item.UnusedPurchasesValue.ToString("0.00")
</CellTemplate>
</PropertyColumn>
</Columns>
<NoRecordsContent>No records found for the given time period</NoRecordsContent>
</MudDataGrid>
</MudContainer>

@code
{
private IEnumerable<UnusedTicket> Items;
private bool _loading = false;
private DateRange _queryDateRange = new(){ Start = new(DateTime.Today.Year, 1, 1), End = new(DateTime.Today.Year, 12, 31)};

private async Task LoadUnusedTickets(DateRange queryDateRange)
{
_loading = true;
if (queryDateRange.Start is null || queryDateRange.End is null) return;

_queryDateRange = queryDateRange;
var result = await _unusedTicketsService.GetUnusedTickets(queryDateRange.Start.Value, queryDateRange.End.Value);

result.Match(
Succ: res => {
Items = res;
},
Fail: error => {
Snackbar.Add(error.Message, Severity.Error);
Items = new List<UnusedTicket>();
}
);
_loading = false;
}

protected override async Task OnInitializedAsync()
{
await LoadUnusedTickets(_queryDateRange);
}

private AggregateDefinition<UnusedTicket> _ticketsLeftSum = new()
{
Type = AggregateType.Sum
};

private AggregateDefinition<UnusedTicket> _valueLeftSum = new()
{
CustomAggregate = x => {
var sum = x.Sum(t => t.UnusedPurchasesValue);
return sum.ToString("0.00");
},
Type = AggregateType.Custom,
};

private AggregateDefinition<UnusedTicket> _footerLabel = new()
{
CustomAggregate = x => "Total",
Type = AggregateType.Custom,
};
}
2 changes: 1 addition & 1 deletion Shifty.App/Components/UserTable.razor
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@

return result.Match(
Succ: res => {
return new TableData<SimpleUserResponse>(){ Items = res.Users.AsEnumerable(), TotalItems = res.TotalUsers};;
return new TableData<SimpleUserResponse>(){ Items = res.Users.AsEnumerable(), TotalItems = res.TotalUsers};
},
Fail: error => {
Snackbar.Add(error.Message, Severity.Error);
Expand Down
24 changes: 24 additions & 0 deletions Shifty.App/DomainModels/UnusedTicket.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
using Components;
using Shifty.Api.Generated.AnalogCoreV2;

namespace Shifty.App.DomainModels
{
public class UnusedTicket
{
public int ProductId { get; set; }
public string ProductName { get; set; }
public int TicketsLeft { get; set; }
public decimal UnusedPurchasesValue { get; set; }

public static UnusedTicket FromDto(UnusedClipsResponse ticket)
TTA777 marked this conversation as resolved.
Show resolved Hide resolved
{
return new UnusedTicket()
{
ProductId = ticket.ProductId,
ProductName = ticket.ProductName,
TicketsLeft = ticket.TicketsLeft,
UnusedPurchasesValue = ticket.UnusedPurchasesValue,
};
}
}
}
24 changes: 24 additions & 0 deletions Shifty.App/Pages/Statistics.razor
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
@page "/Statistics"
@using Components
@inject NavigationManager NavManager

@if (_user is not null && _user.IsInRole("Board"))
TTA777 marked this conversation as resolved.
Show resolved Hide resolved
{
<UnusedTickets />
}

@code {
[CascadingParameter] public Task<AuthenticationState> AuthTask { get; set; }
private System.Security.Claims.ClaimsPrincipal _user;

protected override async Task OnInitializedAsync()
{
var authState = await AuthTask;
_user = authState.User;

if (_user is null || !_user.IsInRole("Board"))
{
NavManager.NavigateTo("/");
}
}
}
2 changes: 2 additions & 0 deletions Shifty.App/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ public static void ConfigureServices(IServiceCollection services, IConfiguration
services.AddScoped<IVoucherRepository, VoucherRepository>();
services.AddScoped<IProductRepository, ProductRepository>();
services.AddScoped<IMenuItemRepository, MenuItemRepository>();
services.AddScoped<IUnusedTicketRepository, UnusedTicketRepository>();
services.AddScoped<CustomAuthStateProvider>();
services.AddScoped<AuthenticationStateProvider>(s => s.GetService<CustomAuthStateProvider>());
services.AddScoped<IAuthenticationService, AuthenticationService>();
Expand All @@ -66,6 +67,7 @@ public static void ConfigureServices(IServiceCollection services, IConfiguration
services.AddScoped<IMenuItemService, MenuItemService>();
services.AddScoped<IUserService, UserService>();
services.AddScoped<IMenuItemService, MenuItemService>();
services.AddScoped<IUnusedTicketsService, UnusedTicketsService>();
services.AddScoped<RequestAuthenticationHandler>();

services.AddMudServices(config =>
Expand Down
15 changes: 15 additions & 0 deletions Shifty.App/Repositories/IUnusedTicketRepository.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using System.Collections;
using System.Collections.Generic;
using System.Threading.Tasks;
using LanguageExt;
using LanguageExt.Common;
using Shifty.Api.Generated.AnalogCoreV1;
using Shifty.Api.Generated.AnalogCoreV2;

namespace Shifty.App.Repositories
{
public interface IUnusedTicketRepository
{
Task<Try<IEnumerable<UnusedClipsResponse>>> GetTickets(UnusedClipsRequest unusedClipsRequest);
}
}
25 changes: 25 additions & 0 deletions Shifty.App/Repositories/UnusedTicketsRepository.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using LanguageExt;
using Shifty.Api.Generated.AnalogCoreV2;
using static LanguageExt.Prelude;

namespace Shifty.App.Repositories
{
public class UnusedTicketRepository : IUnusedTicketRepository
{
private readonly AnalogCoreV2 _client;

public UnusedTicketRepository(AnalogCoreV2 client)
{
_client = client;
}

public async Task<Try<IEnumerable<UnusedClipsResponse>>> GetTickets(UnusedClipsRequest unusedClipsRequest)
{
return await TryAsync(async () => (await _client.ApiV2StatisticsUnusedClipsAsync(unusedClipsRequest)).AsEnumerable());
TTA777 marked this conversation as resolved.
Show resolved Hide resolved
}
}
}
23 changes: 23 additions & 0 deletions Shifty.App/Services/IUnusedTicketsService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using LanguageExt;
using LanguageExt.Common;
using MudBlazor;
using Shifty.Api.Generated.AnalogCoreV1;
using Shifty.Api.Generated.AnalogCoreV2;
using Shifty.App.DomainModels;

namespace Shifty.App.Services
{
public interface IUnusedTicketsService
{
/// <summary>
/// Queries unused tickets
/// </summary>
/// <param name="from">The first date to retrieve unused tickets from</param>
/// <param name="to">The last date to retrieve unused tickets to</param>
/// <returns>A list of unused tickets grouped by product</returns>
Task<Try<IEnumerable<UnusedTicket>>> GetUnusedTickets(DateTimeOffset from, DateTimeOffset to);
}
}
30 changes: 30 additions & 0 deletions Shifty.App/Services/UnusedTicketsService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using LanguageExt;
using Shifty.Api.Generated.AnalogCoreV2;
using Shifty.App.DomainModels;
using Shifty.App.Repositories;

namespace Shifty.App.Services
{
public class UnusedTicketsService : IUnusedTicketsService
{
private readonly IUnusedTicketRepository _unusedTicketRepository;

public UnusedTicketsService(IUnusedTicketRepository unusedTicketRepository)
{
_unusedTicketRepository = unusedTicketRepository;
}

public async Task<Try<IEnumerable<UnusedTicket>>> GetUnusedTickets(DateTimeOffset from, DateTimeOffset to)
{
return await _unusedTicketRepository
.GetTickets(new UnusedClipsRequest(){
StartDate = from,
EndDate = to
})
.Map(x => x.Map(UnusedTicket.FromDto));
}
}
}
6 changes: 5 additions & 1 deletion Shifty.App/Shared/NavMenu.razor
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,16 @@

<MudNavMenu>
<MudNavLink Href="" Match="NavLinkMatch.All" Icon="@Icons.Material.Filled.Home">Home</MudNavLink>
@if (_user is not null && _user.IsInRole("Board"))
@if (_user is not null && (_user.IsInRole("Board") || _user.IsInRole("Manager")))
{
<MudNavLink Href="Voucher" Match="NavLinkMatch.Prefix" Icon="@Icons.Material.Filled.Sell">Issue vouchers</MudNavLink>
}
@if (_user is not null && _user.IsInRole("Board"))
{
<MudNavLink Href="Products" Match="NavLinkMatch.Prefix" Icon="@Icons.Material.Outlined.Inventory">Product Management</MudNavLink>
<MudNavLink Href="MenuItems" Match="NavLinkMatch.Prefix" Icon="@Icons.Material.Outlined.Coffee">Menu Item Management</MudNavLink>
<MudNavLink Href="Users" Match="NavLinkMatch.Prefix" Icon="@Icons.Material.Filled.ManageAccounts">Manage users</MudNavLink>
<MudNavLink Href="Statistics" Match="NavLinkMatch.Prefix" Icon="@Icons.Material.Filled.Analytics">Statistics</MudNavLink>
}
<MudDivider />
<MudNavLink OnClick="_authenticationService.Logout" Match="NavLinkMatch.Prefix" Icon="@Icons.Material.Filled.Logout">Logout</MudNavLink>
Expand Down
Loading
Loading