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

Add menu item management #32

Merged
merged 10 commits into from
Apr 9, 2024
44 changes: 22 additions & 22 deletions Shifty.Api/Generated/AnalogCoreV2/AnalogCoreV2.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ namespace Shifty.Api.Generated.AnalogCoreV2
using System = global::System;

[System.CodeDom.Compiler.GeneratedCode("NSwag", "13.18.0.0 (NJsonSchema v10.8.0.0 (Newtonsoft.Json v10.0.0.0))")]
public partial class AnalogCoreV2
public partial class AnalogCoreV2
{
private System.Net.Http.HttpClient _httpClient;
private System.Lazy<Newtonsoft.Json.JsonSerializerSettings> _settings;
Expand Down Expand Up @@ -795,24 +795,24 @@ public virtual async System.Threading.Tasks.Task<UserSearchResponse> ApiV2Accoun
ProcessResponse(client_, response_);

var status_ = (int)response_.StatusCode;
if (status_ == 401)
if (status_ == 200)
{
var objectResponse_ = await ReadObjectResponseAsync<ApiError>(response_, headers_, cancellationToken).ConfigureAwait(false);
var objectResponse_ = await ReadObjectResponseAsync<UserSearchResponse>(response_, headers_, cancellationToken).ConfigureAwait(false);
if (objectResponse_.Object == null)
{
throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null);
}
throw new ApiException<ApiError>(" Invalid credentials ", status_, objectResponse_.Text, headers_, objectResponse_.Object, null);
return objectResponse_.Object;
}
else
if (status_ == 200)
if (status_ == 401)
{
var objectResponse_ = await ReadObjectResponseAsync<UserSearchResponse>(response_, headers_, cancellationToken).ConfigureAwait(false);
var objectResponse_ = await ReadObjectResponseAsync<ApiError>(response_, headers_, cancellationToken).ConfigureAwait(false);
if (objectResponse_.Object == null)
{
throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null);
}
return objectResponse_.Object;
throw new ApiException<ApiError>(" Invalid credentials ", status_, objectResponse_.Text, headers_, objectResponse_.Object, null);
}
else
{
Expand Down Expand Up @@ -2867,16 +2867,16 @@ public virtual async System.Threading.Tasks.Task ApiV2WebhooksAccountsUserGroupA
return;
}
else
if (status_ == 401)
if (status_ == 400)
{
string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
throw new ApiException("Invalid credentials", status_, responseText_, headers_, null);
throw new ApiException("Bad request. See explanation", status_, responseText_, headers_, null);
}
else
if (status_ == 400)
if (status_ == 401)
{
string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
throw new ApiException("Bad request. See explanation", status_, responseText_, headers_, null);
throw new ApiException("Invalid credentials", status_, responseText_, headers_, null);
}
else
{
Expand Down Expand Up @@ -2970,7 +2970,7 @@ private string ConvertToString(object value, System.Globalization.CultureInfo cu
var field = System.Reflection.IntrospectionExtensions.GetTypeInfo(value.GetType()).GetDeclaredField(name);
if (field != null)
{
var attribute = System.Reflection.CustomAttributeExtensions.GetCustomAttribute(field, typeof(System.Runtime.Serialization.EnumMemberAttribute))
var attribute = System.Reflection.CustomAttributeExtensions.GetCustomAttribute(field, typeof(System.Runtime.Serialization.EnumMemberAttribute))
as System.Runtime.Serialization.EnumMemberAttribute;
if (attribute != null)
{
Expand All @@ -2982,7 +2982,7 @@ private string ConvertToString(object value, System.Globalization.CultureInfo cu
return converted == null ? string.Empty : converted;
}
}
else if (value is bool)
else if (value is bool)
{
return System.Convert.ToString((bool)value, cultureInfo).ToLowerInvariant();
}
Expand Down Expand Up @@ -3486,7 +3486,7 @@ public partial class MenuItemResponse
/// <summary>
/// Whether or not this menu item is active
/// </summary>
[Newtonsoft.Json.JsonProperty("active", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
[Newtonsoft.Json.JsonProperty("active", Required = Newtonsoft.Json.Required.Always)]
public bool Active { get; set; }

}
Expand Down Expand Up @@ -3528,7 +3528,7 @@ public partial class UpdateMenuItemRequest
}

/// <summary>
/// MobilePay webhook invocation request
/// MobilePay webhook invocation request
/// <br/>Code documentation based on MobilePay Developer: Webhooks
/// </summary>
[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.18.0.0 (NJsonSchema v10.8.0.0 (Newtonsoft.Json v10.0.0.0))")]
Expand All @@ -3543,18 +3543,18 @@ public partial class MobilePayWebhook
/// <summary>
/// Type of event
/// <br/>
/// <br/>
/// <br/>
/// <br/> payment.reserved
/// <br/> Published when payment has been approved by MobilePay user and is ready to be captured
/// <br/>
/// <br/>
/// <br/>
/// <br/>
/// <br/> payment.cancelled_by_user
/// <br/> Published when payment has been cancelled by user inside MobilePay app
/// <br/>
/// <br/>
/// <br/>
/// <br/>
/// <br/> payment.expired
/// <br/> Published when either initiated payment didn't have any user interactions for 5-10 minutes or payment was reserved, but 7 days have passed and the reservation has expired.
/// <br/>
/// <br/>
/// </summary>
[Newtonsoft.Json.JsonProperty("eventType", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
public string EventType { get; set; }
Expand Down Expand Up @@ -3632,7 +3632,7 @@ public partial class ProductResponse
public string Description { get; set; }

/// <summary>
/// Eligible due to a user perk privilege
/// Eligible due to a user perk privilege
/// </summary>
[Newtonsoft.Json.JsonProperty("isPerk", Required = Newtonsoft.Json.Required.Always)]
public bool IsPerk { get; set; }
Expand Down
19 changes: 19 additions & 0 deletions Shifty.App/Components/ConfirmDialog.razor
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<MudDialog>
<DialogContent>
<MudText>@ContentText</MudText>
</DialogContent>
<DialogActions>
<MudButton OnClick="Cancel">Cancel</MudButton>
<MudButton Color="Color.Primary" Variant="Variant.Filled" OnClick="Submit">@ButtonText</MudButton>
</DialogActions>
</MudDialog>
@code {
[CascadingParameter] MudDialogInstance MudDialog { get; set; }

[Parameter] public string ContentText { get; set; }

[Parameter] public string ButtonText { get; set; }

void Submit() => MudDialog.Close(DialogResult.Ok(true));
void Cancel() => MudDialog.Cancel();
}
187 changes: 186 additions & 1 deletion Shifty.App/Components/MenuItems.razor
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
@namespace Components
@using System.ComponentModel.DataAnnotations
@using System.Collections.ObjectModel
@using Shifty.App.Components
@using Shifty.App.Services
@using Shifty.Api.Generated.AnalogCoreV1
@using Shifty.Api.Generated.AnalogCoreV2
@using Shared
@using System
@using Shifty.App.DomainModels
@using LanguageExt.UnsafeValueAccess
@using Shifty.App.Repositories
@inject ISnackbar Snackbar
@inject IJSRuntime JSRuntime
@inject IMenuItemService MenuItemService
@inject IDialogService DialogService

<MudPaper Elevation="15" Style="margin: 2em; border-radius: 5px;">
@if (_loading)
Expand All @@ -16,13 +22,192 @@
<LoadingIndicator Height="400px" />
</MudContainer>
}
else
{
<MudDataGrid
@ref="_dataGrid"
T="MenuItem"
Items="@_menuItems"
ReadOnly="false"
EditTrigger="DataGridEditTrigger.Manual"
CommittedItemChanges="@CommittedItemChanges"
StartedEditingItem="@((item) => _editingItem = new MenuItem { Id = item.Id, Name = item.Name, Active = item.Active })"
FixedHeader="true"
Height="calc(100vh - 250px)"
RowStyleFunc="@RowStyleFunc"
Dense="true"
SortMode="MudBlazor.SortMode.None">
<Columns>
<TemplateColumn Title="Edit">
<CellTemplate>
<MudIconButton
Size="@Size.Medium"
Icon="@Icons.Material.Outlined.Edit"
Color="Color.Primary"
OnClick="@context.Actions.StartEditingItemAsync" />
</CellTemplate>
</TemplateColumn>
<PropertyColumn Property="x => x.Id" Title="Id" IsEditable="false" />
<PropertyColumn Property="x => x.Name" Title="Name" IsEditable="true" />
<PropertyColumn Property="x => x.Active" Title="Active" IsEditable="true" InitialDirection="SortDirection.Descending">
<CellTemplate>
@{
if (context.Item.Active)
{
<MudIconButton Size="@Size.Small" Color="Color.Dark" OnClick="@(() => ConfirmActiveToggle(context.Item))"
Icon="@Icons.Material.Filled.Visibility" />
}
else
{
<MudIconButton Size="@Size.Small" Style="@($"color:{Colors.Grey.Default};")"
Icon="@Icons.Material.Filled.VisibilityOff" OnClick="@(() => ConfirmActiveToggle(context.Item))" />
}
}
</CellTemplate>
<EditTemplate>
<MudSwitch Label="Active" Color="Color.Primary" @bind-Checked="context.Item.Active" />
</EditTemplate>
</PropertyColumn>
</Columns>
</MudDataGrid>

<MudToolBar>
<MudSpacer />
<MudButton
Color="Color.Primary"
Variant="Variant.Filled"
EndIcon="@Icons.Material.Outlined.Add"
OnClick="@AddItemToDataGrid">
Add Product
</MudButton>
</MudToolBar>
}
</MudPaper>

@code
{
{
private MudDataGrid<MenuItem> _dataGrid;
private bool _loading = true;
private ObservableCollection<MenuItem> _menuItems = new ObservableCollection<MenuItem>();
private MenuItem _editingItem;

protected override async Task OnInitializedAsync()
{
var result = await MenuItemService.GetMenuItems();
result.Match(
Succ: menuItems => {
_menuItems = new ObservableCollection<MenuItem>(menuItems);
},
Fail: error => {
Snackbar.Add(error.Message, Severity.Error);
}
);
Console.WriteLine("MenuItems: " + _menuItems.Count());
_loading = false;
}
async Task CommittedItemChanges(MenuItem item)
{
if (item.Id == 0)
{
var result = await addMenuItem(item);

result.Match(
Succ: menuItem =>
{
// Succesfully added product
Snackbar.Add("MenuItem added", Severity.Success);
_menuItems.Remove(item);
_menuItems.Add(menuItem);

},
Fail: error => {
Snackbar.Add(error.Message, Severity.Error);
}
);
}
else
{
var result = await updateMenuItem(item);

result.Match(
Succ: newItem =>
{
Snackbar.Add("MenuItem updated", Severity.Success);
item = _menuItems.FirstOrDefault(x => x.Id == newItem.Id);
item.Name = newItem.Name;
item.Active = newItem.Active;

},
Fail: error =>
{
Snackbar.Add(error.Message, Severity.Error);
MenuItem failedItem = _menuItems.FirstOrDefault(x => x.Id == item.Id);
failedItem.Name = _editingItem.Name;
failedItem.Active = _editingItem.Active;

}
);
}
StateHasChanged();
}
async Task<LanguageExt.Try<MenuItem>> updateMenuItem(MenuItem item)
{
return await MenuItemService.UpdateMenuItem(new UpdateMenuItemRequest{
Name = item.Name,
Active = item.Active
}, item.Id);
}
async Task<LanguageExt.Try<MenuItem>> addMenuItem(MenuItem item)
{
return await MenuItemService.AddMenuItem(new AddMenuItemRequest{
Name = item.Name
});
}
void AddItemToDataGrid()
{
_menuItems.Add(new MenuItem{
Name = "",
});
_dataGrid.SetEditingItemAsync(_menuItems.Last());
}
void ToggleItemActiveAsync(MenuItem item)
{
MenuItemService.ToggleMenuItemActive(item).Match(
Succ: menuItem =>
{
Snackbar.Add("MenuItem updated", Severity.Success);
_menuItems.FirstOrDefault(x => x.Id == menuItem.Id).Active = menuItem.Active;
StateHasChanged();
},
Fail: error =>
{
Snackbar.Add(error.Message, Severity.Error);
}
);
}

private async Task ConfirmActiveToggle(MenuItem item)
{
var parameters = new DialogParameters<ConfirmDialog>();
var actionWord = item.Active ? "deactivate" : "activate";
parameters.Add(x => x.ContentText, $"Are you sure you want to {actionWord} {item.Name}?");
parameters.Add(x => x.ButtonText, actionWord);

var dialog = await DialogService.ShowAsync<ConfirmDialog>("Confirm", parameters);
var result = await dialog.Result;

if (!result.Canceled)
{
ToggleItemActiveAsync(item);
}
}

private Func<MenuItem, int, string> RowStyleFunc => (x, i) =>
{
if (!x.Active)
{
return "background-color:#ebebeb;font-style:italic;font-color:#8a8686;";
}
return "";
};
}
Loading
Loading