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

Menuitems on products #25

Merged
merged 15 commits into from
Mar 5, 2024
Merged
1,000 changes: 853 additions & 147 deletions Shifty.Api/Generated/AnalogCoreV2/AnalogCoreV2.cs

Large diffs are not rendered by default.

28 changes: 28 additions & 0 deletions Shifty.App/Components/MenuItems.razor
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
@namespace Components
@using System.ComponentModel.DataAnnotations
@using Shifty.App.Services
@using Shifty.Api.Generated.AnalogCoreV1
@using Shifty.Api.Generated.AnalogCoreV2
@using Shared
@using LanguageExt.UnsafeValueAccess
@using Shifty.App.Repositories
@inject ISnackbar Snackbar
@inject IJSRuntime JSRuntime

<MudPaper Elevation="15" Style="margin: 2em; border-radius: 5px;">
@if (_loading)
{
<MudContainer Style="width: 100%; display: flex;">
<LoadingIndicator Height="400px" />
</MudContainer>
}
</MudPaper>

@code
{
private bool _loading = true;

protected override async Task OnInitializedAsync()

Check warning on line 25 in Shifty.App/Components/MenuItems.razor

View workflow job for this annotation

GitHub Actions / build / Build webapp / Build and test Webapp

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.

Check warning on line 25 in Shifty.App/Components/MenuItems.razor

View workflow job for this annotation

GitHub Actions / build / Build webapp / Build and test Webapp

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.
{
}
}
130 changes: 62 additions & 68 deletions Shifty.App/Components/ProductManager.razor
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
@namespace Components
@using System.ComponentModel.DataAnnotations
@using MudExtensions
@using Shifty.App.Services
@using Shifty.Api.Generated.AnalogCoreV1
@using Shifty.Api.Generated.AnalogCoreV2
@using Shared
@using LanguageExt.UnsafeValueAccess
@using Components
@using Shifty.App.DomainModels
@using System.Collections.ObjectModel
@inject ISnackbar Snackbar
@inject IProductService ProductService
@inject IJSRuntime JSRuntime
@inject IMenuItemService MenuItemService

<style>
.mud-table-cell {
Expand All @@ -24,7 +28,7 @@
}
<MudDataGrid
@ref="_dataGrid"
T="ProductResponse"
T="Product"
Items="@_products"
EditMode="DataGridEditMode.Form"
ReadOnly="false"
Expand All @@ -33,7 +37,7 @@
CommittedItemChanges="@CommittedItemChanges"
EditTrigger="DataGridEditTrigger.Manual"
QuickFilter="e => _showNonvisible || e.Visible"
RowStyleFunc="@_RowStyleFunc"
RowStyleFunc="@RowStyleFunc"
FixedHeader="true"
Height="calc(100vh - 250px)"
Dense="true"
Expand Down Expand Up @@ -97,6 +101,21 @@
</CellTemplate>
</PropertyColumn>
<PropertyColumn Property="x => x.Description" Title="Description" IsEditable="true" />
<PropertyColumn Property="x => x.EligibleMenuItems" Title="Eligible menu items" IsEditable="true" Hidden>
<EditTemplate>
<MudComboBox
T="MenuItem"
Label="Eligible menu items"
MultiSelection="true"
Editable="true"
@bind-SelectedValues="context.Item.EligibleMenuItems">
@foreach (var mi in _allMenuItems)
{
<MudComboBoxItem Text="@mi.Name" Value="@mi">@mi.Name</MudComboBoxItem>
}
</MudComboBox>
</EditTemplate>
</PropertyColumn>
</Columns>
</MudDataGrid>

Expand All @@ -113,37 +132,51 @@
</MudPaper>
@code
{
private MudDataGrid<ProductResponse> _dataGrid;
private IEnumerable<ProductResponse> _products = new List<ProductResponse>();
private MudDataGrid<Product> _dataGrid;
private IEnumerable<Product> _products = new List<Product>();
private Dictionary<UserGroup, bool> UserGroupDict = new();

private void StartedEditingItem(ProductResponse item)
private IEnumerable<MenuItem> _allMenuItems = new List<MenuItem>();

private void StartedEditingItem(Product item)
{
UserGroupDict = new();
foreach (var group in Enum.GetValues<UserGroup>())
{
UserGroupDict.Add(group, item.AllowedUserGroups.Contains(group));
}
FocusFirst();

Check warning on line 147 in Shifty.App/Components/ProductManager.razor

View workflow job for this annotation

GitHub Actions / build / Build webapp / Build and test Webapp

Because this call is not awaited, execution of the current method continues before the call is completed. Consider applying the 'await' operator to the result of the call.

Check warning on line 147 in Shifty.App/Components/ProductManager.razor

View workflow job for this annotation

GitHub Actions / build / Build webapp / Build and test Webapp

Because this call is not awaited, execution of the current method continues before the call is completed. Consider applying the 'await' operator to the result of the call.
}

private bool _loading = true;
private bool _showNonvisible = true;
protected override async Task OnInitializedAsync()
{
var result = await ProductService.GetProducts();
_loading = false;
result.Match(
var productsResult = await ProductService.GetProducts();
productsResult.Match(
Succ: products => {
_products = products;
_products = new List<Product>(products);
StateHasChanged();
},
Fail: error => {
Snackbar.Add(error.Message, Severity.Error);
}
);

var menuItemsResult = await MenuItemService.GetMenuItems();

menuItemsResult.Match(
Succ: menuItems => {
_allMenuItems = menuItems;
},
Fail: error => {
Snackbar.Add(error.Message, Severity.Error);
}
);

_loading = false;
}

void CanceledEditingItem(ProductResponse item)
void CanceledEditingItem(Product item)
{
Snackbar.Add("Cancelled product changes", Severity.Info);
}
Expand All @@ -153,35 +186,31 @@
await JSRuntime.InvokeVoidAsync("window.focusElement", "first-edit-element");
}

async Task CommittedItemChanges(ProductResponse item)
async Task CommittedItemChanges(Product item)
{
List<UserGroup> AllowedUserGroups =
UserGroupDict.Where(e => e.Value)
.ToDictionary(kv => kv.Key, kv => kv.Value)
.Keys
.ToList();

item.AllowedUserGroups = AllowedUserGroups;

if (item.Id == 0)
{
var result = await addProduct(item, AllowedUserGroups);
var result = await ProductService.AddProduct(item);

result.Match(
Succ: async product =>
Succ: product =>
{
// Succesfully added product
Snackbar.Add("Product added", Severity.Success);

// Retrieve all items again in order to update id
var retrieveItems = await ProductService.GetProducts();
retrieveItems.Match(
Succ: items => {
_products = items;
},
Fail: error => {
// Errors while re-retrieving items, non-fatal (just means _products are slightly outdated)
Snackbar.Add(error.Message, Severity.Warning);
}
);
// Override the created product with the placeholder item
_products = _products.Where(p => p.Id != 0)
.Append(product);

StateHasChanged();
},
Fail: error => {
Snackbar.Add(error.Message, Severity.Error);
Expand All @@ -190,23 +219,13 @@
}
else
{
var result = await updateProduct(item, AllowedUserGroups);
var result = await ProductService.UpdateProduct(item, item.Id);

result.Match(
Succ: async result =>
Succ: product =>
{
Snackbar.Add("Product updated", Severity.Success);

var retrieveItems = await ProductService.GetProducts();
retrieveItems.Match(
Succ: items => {
_products = items;
},
Fail: error => {
// Errors while re-retrieving items, non-fatal (just means _products are slightly outdated)
Snackbar.Add(error.Message, Severity.Warning);
}
);
_products.FirstOrDefault(p => p.Id == item.Id).IsPerk = product.IsPerk;
},
Fail: error =>
{
Expand All @@ -216,49 +235,24 @@
}
}

async Task<LanguageExt.Try<ChangedProductResponse>> updateProduct(ProductResponse item, List<UserGroup>
AllowedUserGroups)
{
return await ProductService.UpdateProduct(new UpdateProductRequest{
Id = item.Id,
Name = item.Name,
Description = item.Description,
NumberOfTickets = item.NumberOfTickets,
Price = item.Price,
Visible = item.Visible,
AllowedUserGroups = AllowedUserGroups
});
}

async Task<LanguageExt.Try<ChangedProductResponse>> addProduct(ProductResponse item, List<UserGroup>
AllowedUserGroups)
{
return await ProductService.AddProduct(new AddProductRequest{
Name = item.Name,
Description = item.Description,
NumberOfTickets = item.NumberOfTickets,
Price = item.Price,
Visible = item.Visible,
AllowedUserGroups = AllowedUserGroups
});
}

void AddItemToDataGrid()
{
_products = _products.Append<ProductResponse>(new ProductResponse{
_products = _products.Append(new Product{
Id = 0,
Name = "",
Description = "",
IsPerk = false,
NumberOfTickets = 1,
Price = 0,
Visible = true,
AllowedUserGroups = new List<UserGroup>()
AllowedUserGroups = new List<UserGroup>(),
EligibleMenuItems = new List<MenuItem>(),
});
StateHasChanged();
_dataGrid.SetEditingItemAsync(_products.Last());
}

private Func<ProductResponse, int, string> _RowStyleFunc => (x, i) =>
private Func<Product, int, string> RowStyleFunc => (x, i) =>
{
if (!x.Visible)
{
Expand Down
13 changes: 7 additions & 6 deletions Shifty.App/Components/Voucher.razor
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
@using Shared
@using LanguageExt.UnsafeValueAccess
@using Shifty.App.Repositories
@using Shifty.App.DomainModels
@inject IProductService _productService
@inject IVoucherService _voucherService
@inject ISnackbar Snackbar
Expand All @@ -16,7 +17,7 @@
<MudCardContent>
<MudText Align="Align.Center" Class="mb-n4">Issue Voucher Form</MudText>
<MudForm @bind-IsValid="@_isFormValid" >
<MudAutocomplete T="ProductResponse"
<MudAutocomplete T="Product"
Required="true"
RequiredError="Product is required"
Placeholder="Select product"
Expand Down Expand Up @@ -100,7 +101,7 @@
private VoucherForm _voucherForm = new();
private bool _isFormValid = false;
private bool _showProgressBar = false;
private IEnumerable<ProductResponse> _products = new List<ProductResponse>();
private IEnumerable<Product> _products = new List<Product>();
private IEnumerable<IssueVoucherResponse> _vouchers;
private string _voucherCodes;
private MudTextField<string> _multilineReference;
Expand All @@ -109,7 +110,7 @@
{
[Required]
public string Description { get; set; }
public ProductResponse Product { get; set; }
public Product Product { get; set; }
public int Amount { get; set; } = 1;
public string Requester { get; set; }
public string Prefix { get; set; }
Expand All @@ -121,7 +122,7 @@

result.Match(
Succ: products => {
_products = products.Filter<ProductResponse>(p => p.Visible);
_products = products.Filter<Product>(p => p.Visible);
_voucherForm.Prefix = User.Claims.Single(el => el.Type.Contains("email")).Value[..3].ToUpper();
},
Fail: error => {
Expand All @@ -130,7 +131,7 @@
);
}

private async Task<IEnumerable<ProductResponse>> Products(string value)
private async Task<IEnumerable<Product>> Products(string value)

Check warning on line 134 in Shifty.App/Components/Voucher.razor

View workflow job for this annotation

GitHub Actions / build / Build webapp / Build and test Webapp

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.

Check warning on line 134 in Shifty.App/Components/Voucher.razor

View workflow job for this annotation

GitHub Actions / build / Build webapp / Build and test Webapp

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.
{
if (string.IsNullOrEmpty(value))
return _products;
Expand Down Expand Up @@ -168,6 +169,6 @@
);
}

Func<ProductResponse,string> _converter = p => p != null ? $"{p.Name} - {p.NumberOfTickets} ticket" + (p.NumberOfTickets == 1 ? "" : "s") : "";
Func<Product,string> _converter = p => p != null ? $"{p.Name} - {p.NumberOfTickets} ticket" + (p.NumberOfTickets == 1 ? "" : "s") : "";
Func<string, string> _prefixValidation = str => str.Length == 3 ? null : "Prefix must be 3 letters";
}
36 changes: 36 additions & 0 deletions Shifty.App/DomainModels/MenuItem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
using System;
using System.Data.Common;
using Shifty.Api.Generated.AnalogCoreV1;
using Shifty.Api.Generated.AnalogCoreV2;

namespace Shifty.App.DomainModels
{
public record MenuItem {
public int Id { get; init; }
public string Name { get; set; }
public static MenuItem FromDto(MenuItemResponse dto)
{
return new MenuItem()
{
Id = dto.Id,
Name = dto.Name
};
}

public static AddMenuItemRequest ToAddRequest(MenuItem menuItem)
{
return new AddMenuItemRequest()
{
Name = menuItem.Name
};
}

public static UpdateMenuItemRequest ToUpdateRequest(MenuItem menuItem)
{
return new UpdateMenuItemRequest()
{
Name = menuItem.Name
};
}
}
}
Loading
Loading