From cfe9c2c3fd6bb9a6475fd395a07eba5afc8973e7 Mon Sep 17 00:00:00 2001 From: Loretta Date: Wed, 12 Nov 2025 17:19:03 +0100 Subject: [PATCH] improvements, fixes, etc... --- FruitBank.Common/Dtos/OrderDto.cs | 3 + FruitBank.Common/Dtos/OrderItemDto.cs | 10 ++ FruitBank.Common/Dtos/ProductDto.cs | 6 + FruitBank.Common/Entities/OrderItemPallet.cs | 3 + FruitBank.Common/FastObservableCollection.cs | 127 ++++++++++++++ .../ICustomOrderSignalREndpointCommon.cs | 2 +- FruitBank.Common/Interfaces/IProductDto.cs | 3 + FruitBank.Common/SignalRs/SignalRTags.cs | 5 +- .../Components/GridDetailOrderDto.razor | 55 +++++- .../Components/GridDetailOrderItemDto.razor | 90 ++++++++-- .../GridDetailOrderItemPallets.razor | 62 +++++-- .../Components/GridProductDtoTemplate.razor | 55 +++++- .../Components/GridShipping.razor | 34 +++- .../Components/GridShippingDocument.razor | 58 +++++-- .../Components/GridShippingItemPallets.razor | 47 ++++-- ...m.razor => GridShippingItemTemplate.razor} | 150 ++++++++--------- .../Components/Grids/FruitBankGrid.cs | 159 +++++++++++++++++- .../Grids/ShippingItems/GridShippingItem.cs | 4 +- .../Components/MgGridBase.cs | 7 +- .../Toolbars/FruitBankToolbarTemplate.razor | 98 +++++++++++ .../Components/Toolbars/ToolbarBase.cs | 17 ++ .../Databases/DatabaseClient.cs | 117 +++++++++++-- .../Layout/MainLayout.razor.cs | 35 ++-- FruitBankHybrid.Shared/Layout/NavMenu.razor | 6 +- .../Pages/MeasuringOut.razor | 88 ++++++---- .../Pages/MeasuringOut.razor.cs | 15 +- .../Pages/OrdersAdmin.razor | 7 +- .../Pages/OrdersAdmin.razor.cs | 46 +++-- .../Pages/ShippingsAdmin.razor | 17 +- .../Pages/ShippingsAdmin.razor.cs | 63 ++++--- .../SignalRs/FruitBankSignalRClient.cs | 4 +- .../Services/SignalRs/SignalRDataSource.cs | 2 +- .../FruitBankHybrid.Web.Client.csproj | 18 ++ .../FruitBankHybrid.Web.csproj | 3 + FruitBankHybrid/MauiProgram.cs | 1 + 35 files changed, 1131 insertions(+), 286 deletions(-) create mode 100644 FruitBank.Common/FastObservableCollection.cs rename FruitBankHybrid.Shared/Components/{GridShippingItem.razor => GridShippingItemTemplate.razor} (60%) create mode 100644 FruitBankHybrid.Shared/Components/Toolbars/FruitBankToolbarTemplate.razor create mode 100644 FruitBankHybrid.Shared/Components/Toolbars/ToolbarBase.cs diff --git a/FruitBank.Common/Dtos/OrderDto.cs b/FruitBank.Common/Dtos/OrderDto.cs index c5a4517..bad5f03 100644 --- a/FruitBank.Common/Dtos/OrderDto.cs +++ b/FruitBank.Common/Dtos/OrderDto.cs @@ -75,6 +75,9 @@ public class OrderDto : MgOrderDto, IOrderDto [NotColumn, JsonIgnore, System.Text.Json.Serialization.JsonIgnore] public bool IsAllOrderItemAudited => OrderItemDtos.Count > 0 && OrderItemDtos.All(oi => oi.IsAudited); + [NotColumn, JsonIgnore, System.Text.Json.Serialization.JsonIgnore] + public bool IsAllOrderItemAvgWeightValid => OrderItemDtos.All(oi => oi.AverageWeightIsValid); + [NotColumn, JsonIgnore, System.Text.Json.Serialization.JsonIgnore] public MeasuringStatus MeasuringStatus { diff --git a/FruitBank.Common/Dtos/OrderItemDto.cs b/FruitBank.Common/Dtos/OrderItemDto.cs index 535b3da..60f9a7c 100644 --- a/FruitBank.Common/Dtos/OrderItemDto.cs +++ b/FruitBank.Common/Dtos/OrderItemDto.cs @@ -84,6 +84,16 @@ public class OrderItemDto : MgOrderItemDto, IOrderItemDto } } + [NotColumn, JsonIgnore, System.Text.Json.Serialization.JsonIgnore] + public double AverageWeight => IsMeasurable && OrderItemPallets.Count > 0 ? double.Round(OrderItemPallets.Sum(oip => oip.AverageWeight) / OrderItemPallets.Count, 1) : 0d; + + [NotColumn, JsonIgnore, System.Text.Json.Serialization.JsonIgnore] + public double AverageWeightDifference => IsMeasurable ? double.Round(ProductDto!.AverageWeight - AverageWeight, 1) : 0; + + [NotColumn, JsonIgnore, System.Text.Json.Serialization.JsonIgnore] + public bool AverageWeightIsValid => !IsMeasurable || + (ProductDto!.AverageWeight > 0 && ((AverageWeightDifference / ProductDto!.AverageWeight) * 100) < ProductDto!.AverageWeightTreshold); + [NotColumn, JsonIgnore, System.Text.Json.Serialization.JsonIgnore] public bool IsAudited => OrderItemPallets.Count > 0 && OrderItemPallets.All(oip => oip.IsAudited); diff --git a/FruitBank.Common/Dtos/ProductDto.cs b/FruitBank.Common/Dtos/ProductDto.cs index fa27e67..fafd9f0 100644 --- a/FruitBank.Common/Dtos/ProductDto.cs +++ b/FruitBank.Common/Dtos/ProductDto.cs @@ -70,5 +70,11 @@ public class ProductDto : MgProductDto, IProductDto [NotColumn, JsonIgnore, System.Text.Json.Serialization.JsonIgnore] public int AvailableQuantity => StockQuantity + IncomingQuantity; + [NotColumn, JsonIgnore, System.Text.Json.Serialization.JsonIgnore] + public double AverageWeight => GenericAttributes.GetValueOrDefault(nameof(IProductDto.AverageWeight)); + + [NotColumn, JsonIgnore, System.Text.Json.Serialization.JsonIgnore] + public double AverageWeightTreshold => GenericAttributes.GetValueOrDefault(nameof(IProductDto.AverageWeightTreshold)); + public bool HasMeasuringValues() => Id > 0 && NetWeight != 0 && IsMeasurable; } \ No newline at end of file diff --git a/FruitBank.Common/Entities/OrderItemPallet.cs b/FruitBank.Common/Entities/OrderItemPallet.cs index 3a2cce5..7561870 100644 --- a/FruitBank.Common/Entities/OrderItemPallet.cs +++ b/FruitBank.Common/Entities/OrderItemPallet.cs @@ -2,6 +2,7 @@ using FruitBank.Common.Enums; using FruitBank.Common.Interfaces; using LinqToDB.Mapping; +using Newtonsoft.Json; using Nop.Core.Domain.Orders; namespace FruitBank.Common.Entities; @@ -30,6 +31,8 @@ public class OrderItemPallet : MeasuringItemPalletBase, IOrderItemPallet return OrderItemId > 0 && base.IsValidSafeMeasuringValues(); } + [NotColumn, JsonIgnore, System.Text.Json.Serialization.JsonIgnore] + public double AverageWeight => double.Round(NetWeight / TrayQuantity, 1); /// /// "Szigorúbb" mint az IsValidSafeMeasuringValues() /// diff --git a/FruitBank.Common/FastObservableCollection.cs b/FruitBank.Common/FastObservableCollection.cs new file mode 100644 index 0000000..c2944a0 --- /dev/null +++ b/FruitBank.Common/FastObservableCollection.cs @@ -0,0 +1,127 @@ +using System.Collections; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Collections.Specialized; +using System.ComponentModel; + +namespace FruitBank.Common +{ + public interface IFastObservableCollection + { + public void AddRange(IEnumerable other); + public void Replace(IEnumerable other); + public void RemoveRange(IEnumerable other); + public void Synchronize(NotifyCollectionChangedEventArgs args); + } + + public interface IFastObservableCollection: IFastObservableCollection + { + public void Replace(IEnumerable other); + public void Sort(IComparer comparer); + public void SortAndReplace(IEnumerable other, IComparer comparer); + } + + public class FastObservableCollection : ObservableCollection, IFastObservableCollection + { + private bool suppressChangedEvent = false; + + public void Replace(IEnumerable other) + { + suppressChangedEvent = true; + + Clear(); + AddRange(other); + } + + public void Replace(IEnumerable other) + { + suppressChangedEvent = true; + + Clear(); + foreach (T item in other) Add(item); + + suppressChangedEvent = false; + + OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); + OnPropertyChanged(new(nameof(Count))); + } + + public void AddRange(IEnumerable other) + { + suppressChangedEvent = true; + + foreach (object item in other) + { + if (item is T tItem) Add(tItem); + } + + suppressChangedEvent = false; + + OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); + OnPropertyChanged(new(nameof(Count))); + } + + public void RemoveRange(IEnumerable other) + { + suppressChangedEvent = true; + + foreach (object item in other) + { + if (item is T tItem) Remove(tItem); + } + + suppressChangedEvent = false; + + OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); + OnPropertyChanged(new(nameof(Count))); + } + + public void SortAndReplace(IEnumerable other, IComparer comparer) + { + List values = new(other); + + values.Sort(comparer); + Replace(values); + } + + public void Sort(IComparer comparer) + { + List values = new(this); + + values.Sort(comparer); + Replace(values); + } + + public void Synchronize(NotifyCollectionChangedEventArgs args) + { + if (args.Action == NotifyCollectionChangedAction.Add && args.NewItems != null) + { + AddRange(args.NewItems); + } + else if (args.Action == NotifyCollectionChangedAction.Remove && args.OldItems != null) + { + RemoveRange(args.OldItems); + } + else if (args.Action == NotifyCollectionChangedAction.Reset) + { + Clear(); + } + } + + protected override void OnPropertyChanged(PropertyChangedEventArgs e) + { + if (suppressChangedEvent) + return; + + base.OnPropertyChanged(e); + } + + protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e) + { + if (suppressChangedEvent) + return; + + base.OnCollectionChanged(e); + } + } +} \ No newline at end of file diff --git a/FruitBank.Common/Interfaces/ICustomOrderSignalREndpointCommon.cs b/FruitBank.Common/Interfaces/ICustomOrderSignalREndpointCommon.cs index 64c80ab..4afc353 100644 --- a/FruitBank.Common/Interfaces/ICustomOrderSignalREndpointCommon.cs +++ b/FruitBank.Common/Interfaces/ICustomOrderSignalREndpointCommon.cs @@ -8,7 +8,7 @@ public interface ICustomOrderSignalREndpointCommon { Task?> GetAllOrderDtos(); Task?> GetPendingOrderDtos(); - Task?> GetPendingOrderDtosForMeasuring(); + Task?> GetPendingOrderDtosForMeasuring(int lastDaysCount); Task?> GetAllOrderDtoByIds(int[] orderIds); Task GetOrderDtoById(int orderId); diff --git a/FruitBank.Common/Interfaces/IProductDto.cs b/FruitBank.Common/Interfaces/IProductDto.cs index 301ca27..9aaf8ad 100644 --- a/FruitBank.Common/Interfaces/IProductDto.cs +++ b/FruitBank.Common/Interfaces/IProductDto.cs @@ -4,4 +4,7 @@ namespace FruitBank.Common.Interfaces; public interface IProductDto : IMgProductDto, ITare, IIncomingQuantity, IAvailableQuantity, IMeasuringAttributeValues { + public double AverageWeight { get; } + + public double AverageWeightTreshold { get; } } \ No newline at end of file diff --git a/FruitBank.Common/SignalRs/SignalRTags.cs b/FruitBank.Common/SignalRs/SignalRTags.cs index 5721634..d926fdb 100644 --- a/FruitBank.Common/SignalRs/SignalRTags.cs +++ b/FruitBank.Common/SignalRs/SignalRTags.cs @@ -53,8 +53,9 @@ public class SignalRTags : AcSignalRTags public const int GetPendingOrderDtos = 114; public const int GetAllOrderDtoByProductId = 115; public const int GetPendingOrderDtosForMeasuring = 116; - public const int StartMeasuring = 117; - public const int SetOrderStatusToComplete = 118; + public const int GetOrderDatesForMeasuring = 117; + public const int StartMeasuring = 118; + public const int SetOrderStatusToComplete = 119; public const int GetOrderItemDtoById = 120; public const int GetAllOrderItemDtos = 121; diff --git a/FruitBankHybrid.Shared/Components/GridDetailOrderDto.razor b/FruitBankHybrid.Shared/Components/GridDetailOrderDto.razor index 796f8e2..858bbb6 100644 --- a/FruitBankHybrid.Shared/Components/GridDetailOrderDto.razor +++ b/FruitBankHybrid.Shared/Components/GridDetailOrderDto.razor @@ -1,11 +1,17 @@ -@using FruitBank.Common.Dtos +@using AyCode.Utils.Extensions +@using FruitBank.Common.Dtos +@using FruitBank.Common.Models +@using FruitBankHybrid.Shared.Components.Toolbars +@using FruitBankHybrid.Shared.Databases @using FruitBankHybrid.Shared.Services.SignalRs +@inject LoggedInModel LoggedInModel; @inject FruitBankSignalRClient FruitBankSignalRClient - @@ -14,9 +20,12 @@ - + + @* *@ + + @@ -24,7 +33,7 @@ - @if (IsMasterGrid) + @if (IsMasterGrid && LoggedInModel.IsDeveloper) { var orderDto = ((OrderDto)context.DataItem); @@ -35,13 +44,19 @@ @{ var orderItemPalletDtos = orderDto?.OrderItemDtos.SelectMany(oi => oi.OrderItemPallets).ToList() ?? []; - + } } + + @if (IsMasterGrid) + { + + } + ? OrderDtos { get; set; } - private int _activeTabIndex; - protected override void OnInitialized() + string GridCss => !IsMasterGrid ? "hide-toolbar" : string.Empty; + + MgGridBase Grid; + int _activeTabIndex; + protected override async Task OnInitializedAsync() { // if (OrderDto != null) // OrderItemDtos = OrderDto.OrderItemDtos; + + await ReloadDataFromDb(false); + } + + private async Task ReloadDataFromDb(bool forceReload = false) + { + LoadingPanelVisibility.Visible = true; + using (await ObjectLock.GetSemaphore().UseWaitAsync()) + { + if (OrderDtos == null) OrderDtos = await FruitBankSignalRClient.GetAllOrderDtos() ?? []; + else if (OrderDtos.Count == 0 || forceReload) + { + OrderDtos.Clear(); + OrderDtos.AddRange(await FruitBankSignalRClient.GetAllOrderDtos() ?? []); + } + } + + //if (forceReload) + Grid?.Reload(); + + LoadingPanelVisibility.Visible = false; } protected async Task OnActiveTabChanged(int activeTabIndex) diff --git a/FruitBankHybrid.Shared/Components/GridDetailOrderItemDto.razor b/FruitBankHybrid.Shared/Components/GridDetailOrderItemDto.razor index 4d13373..4cde8f1 100644 --- a/FruitBankHybrid.Shared/Components/GridDetailOrderItemDto.razor +++ b/FruitBankHybrid.Shared/Components/GridDetailOrderItemDto.razor @@ -1,16 +1,19 @@ -@using FruitBank.Common.Dtos +@using AyCode.Core.Helpers +@using AyCode.Utils.Extensions +@using FruitBank.Common.Dtos +@using FruitBank.Common.Models +@using FruitBankHybrid.Shared.Components.Toolbars +@using FruitBankHybrid.Shared.Databases @using FruitBankHybrid.Shared.Services.SignalRs +@inject LoggedInModel LoggedInModel; @inject FruitBankSignalRClient FruitBankSignalRClient -@*
- Contact Phone: @OrderDto.Email -
*@ - - @@ -34,15 +37,29 @@ - + - + + @* *@ + + + + - + @if (IsMasterGrid && LoggedInModel.IsDeveloper) + { + + } + + @if (IsMasterGrid) + { + + } + @code { + [Inject] public required DatabaseClient Database { get; set; } + [Parameter] public bool IsMasterGrid { get; set; } = false; //[Parameter] public OrderDto? OrderDto { get; set; } [Parameter] public List? OrderItemDtos { get; set; } - [Parameter] public List? ProductDtos { get; set; } + [Parameter] public IEnumerable? ProductDtos { get; set; } + + string GridCss => !IsMasterGrid ? "hide-toolbar" : string.Empty; + + public MgGridBase Grid; protected override async Task OnInitializedAsync() { - ProductDtos ??= await FruitBankSignalRClient.GetProductDtos(); - // if (OrderDto != null) - // OrderItemDtos = OrderDto.OrderItemDtos; + await ReloadDataFromDb(); + } + + private async Task ReloadDataFromDb(bool forceReload = false) + { + LoadingPanelVisibility.Visible = true; + //using (await ObjectLock.GetSemaphore().UseWaitAsync()) + { + // if (ProductDtos == null || !ProductDtos.Any()) + // { + // ProductDtos = await Database.ProductDtoTable.LoadDataAsync(!forceReload); + + // // Database.ProductDtoTable.LoadDataAsync(!forceReload).ContinueWith(x => + // // { + // // ProductDtos = x.Result; + // // }).Forget(); + // } + } + + if (!IsMasterGrid) return; + + using (await ObjectLock.GetSemaphore().UseWaitAsync()) + { + if (OrderItemDtos == null) OrderItemDtos = await FruitBankSignalRClient.GetAllOrderItemDtos() ?? []; + else if (OrderItemDtos.Count == 0 || forceReload) + { + OrderItemDtos.Clear(); + OrderItemDtos.AddRange(await FruitBankSignalRClient.GetAllOrderItemDtos() ?? []); + } + } + + //if (forceReload) + Grid?.Reload(); + + if (ProductDtos == null || !ProductDtos.Any() || forceReload) + { + //ProductDtos = await Database.ProductDtoTable.LoadDataAsync(!forceReload); + + Database.ProductDtoTable.LoadDataAsync(!forceReload).ContinueWith(x => + { + ProductDtos = x.Result; + }).Forget(); + } + LoadingPanelVisibility.Visible = false; } } \ No newline at end of file diff --git a/FruitBankHybrid.Shared/Components/GridDetailOrderItemPallets.razor b/FruitBankHybrid.Shared/Components/GridDetailOrderItemPallets.razor index a455a38..025854c 100644 --- a/FruitBankHybrid.Shared/Components/GridDetailOrderItemPallets.razor +++ b/FruitBankHybrid.Shared/Components/GridDetailOrderItemPallets.razor @@ -1,12 +1,18 @@ -@using FruitBank.Common.Dtos +@using AyCode.Utils.Extensions +@using FruitBank.Common.Dtos @using FruitBank.Common.Entities +@using FruitBank.Common.Models +@using FruitBankHybrid.Shared.Components.Toolbars +@using FruitBankHybrid.Shared.Databases @using FruitBankHybrid.Shared.Services.SignalRs +@inject LoggedInModel LoggedInModel; @inject FruitBankSignalRClient FruitBankSignalRClient @@ -22,11 +28,18 @@ + + + @if (IsMasterGrid) + { + + } + @code { - IGrid gridOrderItemPallet; + MgGridBase gridOrderItemPallet; [Parameter] public bool IsMasterGrid { get; set; } = false; [Parameter] public List? OrderItemPallets { get; set; } + string GridCss => !IsMasterGrid ? "hide-toolbar" : string.Empty; + protected override async Task OnInitializedAsync() { - if (OrderItemPallets == null) + await ReloadDataFromDb(false); + } + + public async Task ReloadDataFromDb(bool forceReload) + { + if (!IsMasterGrid) return; + + LoadingPanelVisibility.Visible = true; + using (await ObjectLock.GetSemaphore().UseWaitAsync()) { - OrderItemPallets = await FruitBankSignalRClient.GetAllOrderItemPallets(); - - if (OrderItemPallets != null && OrderItemPallets.Any(oip => oip.OrderItemDto?.ProductDto != null)) + if (OrderItemPallets == null) OrderItemPallets = await FruitBankSignalRClient.GetAllOrderItemPallets() ?? []; + else if (OrderItemPallets.Count == 0 || forceReload) { - gridOrderItemPallet.BeginUpdate(); - - gridOrderItemPallet.GetColumns().FirstOrDefault(x => x.Name == "ProductId")!.Visible = true; - gridOrderItemPallet.GetColumns().FirstOrDefault(x => x.Name == "ProductName")!.Visible = true; - - gridOrderItemPallet.EndUpdate(); + OrderItemPallets.Clear(); + OrderItemPallets.AddRange(await FruitBankSignalRClient.GetAllOrderItemPallets() ?? []); } - } + + if (OrderItemPallets != null && OrderItemPallets.Any(oip => oip.OrderItemDto?.ProductDto != null)) + { + gridOrderItemPallet.BeginUpdate(); + + gridOrderItemPallet.GetColumns().FirstOrDefault(x => x.Name == "ProductId")!.Visible = true; + gridOrderItemPallet.GetColumns().FirstOrDefault(x => x.Name == "ProductName")!.Visible = true; + + gridOrderItemPallet.EndUpdate(); + } + + if (forceReload) + gridOrderItemPallet?.Reload(); + + LoadingPanelVisibility.Visible = false; } protected override Task OnAfterRenderAsync(bool firstRender) @@ -69,10 +101,10 @@ // if (OrderItemPallets != null && OrderItemPallets.Any(oip => oip.OrderItemDto?.ProductDto != null)) // { // gridOrderItemPallet.BeginUpdate(); - + // gridOrderItemPallet.GetColumns().FirstOrDefault(x => x.Name == "ProductId")!.Visible = true; // gridOrderItemPallet.GetColumns().FirstOrDefault(x => x.Name == "ProductName")!.Visible = true; - + // gridOrderItemPallet.EndUpdate(); // } } diff --git a/FruitBankHybrid.Shared/Components/GridProductDtoTemplate.razor b/FruitBankHybrid.Shared/Components/GridProductDtoTemplate.razor index 2160a3d..df82299 100644 --- a/FruitBankHybrid.Shared/Components/GridProductDtoTemplate.razor +++ b/FruitBankHybrid.Shared/Components/GridProductDtoTemplate.razor @@ -1,12 +1,17 @@ @using AyCode.Core.Helpers +@using AyCode.Utils.Extensions @using DevExpress.Internal.About @using FruitBank.Common.Dtos +@using FruitBank.Common.Models +@using FruitBankHybrid.Shared.Components.Toolbars @using FruitBankHybrid.Shared.Databases @using FruitBankHybrid.Shared.Services.SignalRs +@inject LoggedInModel LoggedInModel; @inject FruitBankSignalRClient FruitBankSignalRClient - + @@ -16,10 +21,12 @@ + + - @if (IsMasterGrid) + @if (IsMasterGrid && LoggedInModel.IsDeveloper) { var productId = ((ProductDto)context.DataItem).Id; @@ -42,13 +49,20 @@ } - + + @if (IsMasterGrid) + { + + } + @code { [Inject] public required DatabaseClient Database { get; set; } + string GridCss => !IsMasterGrid ? "hide-toolbar" : string.Empty; + private int _activeTabIndex; private List? _currentOrderDtos; @@ -56,6 +70,7 @@ private readonly Dictionary> _orderDtosByProductId = new(); private readonly Dictionary> _orderItemDtosByProductId = new(); + public GridProductDto Grid { get; set; } [Parameter] public bool IsMasterGrid { get; set; } = false; [Parameter] public IEnumerable? ProductDtos { get; set; } @@ -64,12 +79,38 @@ protected override async Task OnInitializedAsync() { - ProductDtos ??= await Database.ProductDtoTable.LoadDataAsync(true); + // if (IsMasterGrid) + // { + // using (await ObjectLock.GetSemaphore().UseWaitAsync()) + // { + // ProductDtos ??= await Database.ProductDtoTable.LoadDataAsync(true); + // } + // //ProductDtos ??= await FruitBankSignalRClient.GetProductDtos(); - //ProductDtos ??= await FruitBankSignalRClient.GetProductDtos(); + // // if (ProductDtos is { Count: > 0 }) + // // _currentOrderDtos = await GetOrderDtosFromDbAsync(ProductDtos[0].Id); + // } - // if (ProductDtos is { Count: > 0 }) - // _currentOrderDtos = await GetOrderDtosFromDbAsync(ProductDtos[0].Id); + await ReloadDataFromDb(false); + } + + public async Task ReloadDataFromDb(bool forceReload) + { + if (!IsMasterGrid) return; + + LoadingPanelVisibility.Visible = true; + using (await ObjectLock.GetSemaphore().UseWaitAsync()) + { + if (ProductDtos == null || !ProductDtos.Any() || forceReload) ProductDtos = await Database.ProductDtoTable.LoadDataAsync(!forceReload); + } + + _orderDtosByProductId.Clear(); + _orderItemDtosByProductId.Clear(); + + // if (forceReload) + // Grid?.Reload(); + + LoadingPanelVisibility.Visible = false; } private async Task> GetOrderDtosFromDbAsync(int productId) diff --git a/FruitBankHybrid.Shared/Components/GridShipping.razor b/FruitBankHybrid.Shared/Components/GridShipping.razor index 065c605..8d55e6d 100644 --- a/FruitBankHybrid.Shared/Components/GridShipping.razor +++ b/FruitBankHybrid.Shared/Components/GridShipping.razor @@ -1,5 +1,7 @@ -@using FruitBank.Common.Dtos +@using AyCode.Utils.Extensions +@using FruitBank.Common.Dtos @using FruitBank.Common.Entities +@using FruitBankHybrid.Shared.Databases @using FruitBankHybrid.Shared.Services.SignalRs @inject FruitBankSignalRClient FruitBankSignalRClient @@ -34,7 +36,7 @@ - + } @@ -77,6 +79,9 @@ @code { + //[Inject] public required ObjectLock ObjectLock { get; set; } + [Inject] public required DatabaseClient Database { get; set; } + [Parameter] public bool IsMasterGrid { get; set; } = false; //[Parameter] public OrderDto? OrderDto { get; set; } [Parameter] public List? Shippings{ get; set; } @@ -85,13 +90,32 @@ string GridSearchText = ""; bool EditItemsEnabled { get; set; } int FocusedRowVisibleIndex { get; set; } - IGrid Grid { get; set; } + public MgGridBase Grid { get; set; } private int _activeTabIndex; protected override async Task OnInitializedAsync() { - Shippings ??= (await FruitBankSignalRClient.GetShippings()) ?? []; - // OrderItemDtos = OrderDto.OrderItemDtos; + await ReloadDataFromDb(false); + } + + private async Task ReloadDataFromDb(bool forceReload = false) + { + if (!IsMasterGrid) return; + + //ProductDtos ??= await FruitBankSignalRClient.GetProductDtos() ?? []; + //ProductDtos ??= await Database.ProductDtoTable.LoadDataAsync(true); + + using (await ObjectLock.GetSemaphore().UseWaitAsync()) + { + if (Shippings == null) Shippings = await FruitBankSignalRClient.GetShippings() ?? []; + else if (Shippings.Count == 0 || forceReload) + { + Shippings.Clear(); + Shippings.AddRange(await FruitBankSignalRClient.GetShippings() ?? []); + } + } + + if (forceReload) Grid?.Reload(); } async Task Grid_DataItemDeleting(GridDataItemDeletingEventArgs e) { diff --git a/FruitBankHybrid.Shared/Components/GridShippingDocument.razor b/FruitBankHybrid.Shared/Components/GridShippingDocument.razor index b801204..367a64e 100644 --- a/FruitBankHybrid.Shared/Components/GridShippingDocument.razor +++ b/FruitBankHybrid.Shared/Components/GridShippingDocument.razor @@ -1,4 +1,5 @@ -@using FruitBank.Common.Dtos +@using AyCode.Utils.Extensions +@using FruitBank.Common.Dtos @using FruitBank.Common.Entities @using FruitBankHybrid.Shared.Components.FileUploads @using FruitBankHybrid.Shared.Databases @@ -71,12 +72,12 @@ - + @{ var shippingItemPallets = shippingDocument?.ShippingItems?.SelectMany(oi => oi.ShippingItemPallets ?? []).ToList() ?? []; - // + } @@ -135,13 +136,14 @@ @code { + //[Inject] public required ObjectLock ObjectLock { get; set; } [Inject] public required DatabaseClient Database { get; set; } [Inject] public required LoggedInModel LoggedInModel { get; set; } [Parameter] public bool IsMasterGrid { get; set; } = false; [Parameter] public List? Shippings { get; set; } - [Parameter] public IEnumerable? Partners { get; set; } + [Parameter] public List? Partners { get; set; } [Parameter] public List? ShippingDocuments { get; set; } [Parameter] public Func?, Task>? OnUploadedFileParsed { get; set; } @@ -154,20 +156,54 @@ string GridSearchText = ""; bool EditItemsEnabled { get; set; } = true; int FocusedRowVisibleIndex { get; set; } - IGrid Grid { get; set; } + public MgGridBase Grid { get; set; } private int _activeTabIndex; + protected override async Task OnInitializedAsync() { _localStorageKey += LoggedInModel.CustomerDto!.Id; + await ReloadDataFromDb(); + } + + private async Task ReloadDataFromDb(bool forceReload = false) + { + if (!IsMasterGrid) return; - //ProductDtos ??= await Database.ProductDtoTable.LoadDataAsync(true); - Partners ??= await FruitBankSignalRClient.GetPartners() ?? []; - Shippings ??= await FruitBankSignalRClient.GetShippings() ?? []; //ProductDtos ??= await FruitBankSignalRClient.GetProductDtos() ?? []; - ShippingDocuments ??= await FruitBankSignalRClient.GetShippingDocuments() ?? []; - // if (OrderDto != null) - // OrderItemDtos = OrderDto.OrderItemDtos; + //ProductDtos ??= await Database.ProductDtoTable.LoadDataAsync(true); + + using (await ObjectLock.GetSemaphore().UseWaitAsync()) + { + if (Partners == null) Partners = await FruitBankSignalRClient.GetPartners() ?? []; + else if (Partners.Count == 0 || forceReload) + { + Partners.Clear(); + Partners.AddRange(await FruitBankSignalRClient.GetPartners() ?? []); + } + } + + using (await ObjectLock.GetSemaphore().UseWaitAsync()) + { + if (Shippings == null) Shippings = await FruitBankSignalRClient.GetShippings() ?? []; + else if (Shippings.Count == 0 || forceReload) + { + Shippings.Clear(); + Shippings.AddRange(await FruitBankSignalRClient.GetShippings() ?? []); + } + } + + using (await ObjectLock.GetSemaphore().UseWaitAsync()) + { + if (ShippingDocuments == null) ShippingDocuments = await FruitBankSignalRClient.GetShippingDocuments() ?? []; + else if (ShippingDocuments.Count == 0 || forceReload) + { + ShippingDocuments.Clear(); + ShippingDocuments.AddRange(await FruitBankSignalRClient.GetShippingDocuments() ?? []); + } + } + + if (forceReload) Grid?.Reload(); } private async Task OnFileUploaded(byte[] arg) diff --git a/FruitBankHybrid.Shared/Components/GridShippingItemPallets.razor b/FruitBankHybrid.Shared/Components/GridShippingItemPallets.razor index 9c1a735..7ba1e00 100644 --- a/FruitBankHybrid.Shared/Components/GridShippingItemPallets.razor +++ b/FruitBankHybrid.Shared/Components/GridShippingItemPallets.razor @@ -1,5 +1,7 @@ -@using FruitBank.Common.Dtos +@using AyCode.Utils.Extensions +@using FruitBank.Common.Dtos @using FruitBank.Common.Entities +@using FruitBankHybrid.Shared.Databases @using FruitBankHybrid.Shared.Services.SignalRs @inject FruitBankSignalRClient FruitBankSignalRClient @@ -37,29 +39,48 @@
@code { - IGrid gridOrderItemPallet; + public MgGridBase gridOrderItemPallet; + + [Inject] public required DatabaseClient Database { get; set; } + //[Inject] public required ObjectLock ObjectLock{ get; set; } [Parameter] public bool IsMasterGrid { get; set; } = false; [Parameter] public List? ShippingItemPallets { get; set; } protected override async Task OnInitializedAsync() { - if (ShippingItemPallets == null) + await ReloadDataFromDb(false); + } + + private async Task ReloadDataFromDb(bool forceReload = false) + { + if (!IsMasterGrid) return; + + using (await ObjectLock.GetSemaphore().UseWaitAsync()) { - //TODO: A ShippingItemPallet-eknek SignalR Endpoint! - J. - ShippingItemPallets = (await FruitBankSignalRClient.GetShippingItems())!.SelectMany(si => si.ShippingItemPallets!).ToList(); + ShippingItemPallets ??= []; - if (ShippingItemPallets != null && ShippingItemPallets.Any(sip => sip.ShippingItem?.ProductDto != null)) + if (ShippingItemPallets.Count == 0 || forceReload) { - gridOrderItemPallet.BeginUpdate(); - - gridOrderItemPallet.GetColumns().FirstOrDefault(x => x.Name == "ProductId")!.Visible = true; - gridOrderItemPallet.GetColumns().FirstOrDefault(x => x.Name == "ProductName")!.Visible = true; - - gridOrderItemPallet.EndUpdate(); - } + ShippingItemPallets.Clear(); + //TODO: A ShippingItemPallet-eknek SignalR Endpoint! - J. + ShippingItemPallets.AddRange((await FruitBankSignalRClient.GetShippingItems())?.SelectMany(si => si.ShippingItemPallets ?? []) ?? []); + + if (ShippingItemPallets.Any(sip => sip.ShippingItem?.ProductDto != null)) + { + gridOrderItemPallet.BeginUpdate(); + + gridOrderItemPallet.GetColumns().FirstOrDefault(x => x.Name == "ProductId")!.Visible = true; + gridOrderItemPallet.GetColumns().FirstOrDefault(x => x.Name == "ProductName")!.Visible = true; + + gridOrderItemPallet.EndUpdate(); + } + } } + + if (forceReload) + gridOrderItemPallet?.Reload(); } protected override Task OnAfterRenderAsync(bool firstRender) diff --git a/FruitBankHybrid.Shared/Components/GridShippingItem.razor b/FruitBankHybrid.Shared/Components/GridShippingItemTemplate.razor similarity index 60% rename from FruitBankHybrid.Shared/Components/GridShippingItem.razor rename to FruitBankHybrid.Shared/Components/GridShippingItemTemplate.razor index 4dedbed..f35ce9d 100644 --- a/FruitBankHybrid.Shared/Components/GridShippingItem.razor +++ b/FruitBankHybrid.Shared/Components/GridShippingItemTemplate.razor @@ -1,26 +1,38 @@ -@using AyCode.Core.Extensions +@using AyCode.Core.Loggers; +@using AyCode.Core.Extensions +@using AyCode.Core.Helpers +@using AyCode.Utils.Extensions @using FruitBank.Common.Dtos @using FruitBank.Common.Entities +@using FruitBankHybrid.Shared.Components.Grids.ShippingItems +@using FruitBankHybrid.Shared.Components.Toolbars @using FruitBankHybrid.Shared.Databases +@using FruitBankHybrid.Shared.Services.Loggers; @using FruitBankHybrid.Shared.Services.SignalRs +@inject IEnumerable LogWriters @inject FruitBankSignalRClient FruitBankSignalRClient -@*
- Contact Phone: @OrderDto.Email -
*@ +@* Data="ShippingItems" IsMasterGrid="IsMasterGrid" CssClass="@GridCss" AutoSaveLayoutName="GridShippingItem" +ValidationEnabled="false" EditMode="GridEditMode.EditRow" +EditModelSaving="Grid_EditModelSaving" +FocusedRowChanged="Grid_FocusedRowChanged" *@ - + @* + FocusedRowChanged="Grid_FocusedRowChanged"> *@ + ValueFieldName="Id" + TextFieldName="Name" + DropDownBodyCssClass="dd-body-class" + ListRenderMode="ListRenderMode.Entire" + SearchMode="ListSearchMode.AutoSearch" + SearchFilterCondition="ListSearchFilterCondition.Contains" + ClearButtonDisplayMode="DataEditorClearButtonDisplayMode.Auto"> @@ -73,7 +85,7 @@ - + @@ -88,28 +100,7 @@ @if (IsMasterGrid) { - - - - - - - - - - - - - - @* - - *@ - + } @@ -123,16 +114,18 @@ FieldName="MeasuredNetWeight" FooterColumnName="NetWeight" /> - + +@* *@ @code { + //[Inject] public required ObjectLock ObjectLock { get; set; } [Inject] public required DatabaseClient Database { get; set; } [Parameter] public bool IsMasterGrid { get; set; } = false; [Parameter] public IEnumerable? ProductDtos { get; set; } [Parameter] public List? ShippingItems { get; set; } - [Parameter] public IEnumerable? ShippingDocuments { get; set; } + [Parameter] public List? ShippingDocuments { get; set; } string GridCss => !IsMasterGrid ? "hide-toolbar" : string.Empty; @@ -142,15 +135,43 @@ string GridSearchText = ""; bool EditItemsEnabled { get; set; } = true; int FocusedRowVisibleIndex { get; set; } - IGrid Grid { get; set; } + + public GridShippingItemBase Grid { get; set; } + private LoggerClient _logger; protected override async Task OnInitializedAsync() { - ProductDtos ??= await Database.ProductDtoTable.LoadDataAsync(true); + _logger = new LoggerClient(LogWriters.ToArray()); - //ProductDtos ??= await FruitBankSignalRClient.GetProductDtos() ?? []; - ShippingItems ??= await FruitBankSignalRClient.GetShippingItems() ?? []; - ShippingDocuments ??= await FruitBankSignalRClient.GetShippingDocuments() ?? []; + await ReloadDataFromDb(false); + } + + public async Task ReloadDataFromDb(bool forceReload = false) + { + if (!IsMasterGrid) return; + + using (await ObjectLock.GetSemaphore().UseWaitAsync()) + { + if (ProductDtos == null || !ProductDtos.Any() || forceReload) ProductDtos = await Database.ProductDtoTable.LoadDataAsync(!forceReload); + } + + using (await ObjectLock.GetSemaphore().UseWaitAsync()) + { + if (ShippingDocuments == null) ShippingDocuments = await FruitBankSignalRClient.GetShippingDocuments() ?? []; + else if (ShippingDocuments.Count == 0 || forceReload) + { + ShippingDocuments.Clear(); + ShippingDocuments.AddRange(await FruitBankSignalRClient.GetShippingDocuments() ?? []); + } + } + + if (Grid == null) return; + + using (await ObjectLock.GetSemaphore().UseWaitAsync()) + if (forceReload) await Grid.ReloadDataSourceAsync(); + + if (forceReload) + Grid.Reload(); } async Task Grid_FocusedRowChanged(GridFocusedRowChangedEventArgs args) @@ -180,46 +201,9 @@ EditItemsEnabled = true; } - if (resultShippingItem != null) - ShippingItems!.UpdateCollection(resultShippingItem, false); + // if (resultShippingItem != null) + // ShippingItems!.UpdateCollection(resultShippingItem, false); EditItemsEnabled = true; } - - async Task NewItem_Click() - { - EditItemsEnabled = false; - await Grid.StartEditNewRowAsync(); - } - async Task EditItem_Click() - { - EditItemsEnabled = false; - await Grid.StartEditRowAsync(FocusedRowVisibleIndex); - } - void DeleteItem_Click() - { - EditItemsEnabled = false; - Grid.ShowRowDeleteConfirmation(FocusedRowVisibleIndex); - } - - void ColumnChooserItem_Click(ToolbarItemClickEventArgs e) - { - Grid.ShowColumnChooser(); - } - async Task ExportXlsxItem_Click() - { - await Grid.ExportToXlsxAsync(ExportFileName); - } - async Task ExportXlsItem_Click() - { - await Grid.ExportToXlsAsync(ExportFileName); - } - async Task ExportCsvItem_Click() - { - await Grid.ExportToCsvAsync(ExportFileName); - } - async Task ExportPdfItem_Click() - { - await Grid.ExportToPdfAsync(ExportFileName); - } } \ No newline at end of file diff --git a/FruitBankHybrid.Shared/Components/Grids/FruitBankGrid.cs b/FruitBankHybrid.Shared/Components/Grids/FruitBankGrid.cs index f677eaf..cbb8b00 100644 --- a/FruitBankHybrid.Shared/Components/Grids/FruitBankGrid.cs +++ b/FruitBankHybrid.Shared/Components/Grids/FruitBankGrid.cs @@ -1,13 +1,170 @@ using AyCode.Blazor.Components.Components.Grids; +using AyCode.Core.Extensions; using AyCode.Core.Interfaces; using AyCode.Interfaces.Entities; +using AyCode.Utils.Extensions; +using DevExpress.Blazor; +using FruitBank.Common.Models; using FruitBankHybrid.Shared.Services.Loggers; using FruitBankHybrid.Shared.Services.SignalRs; +using Microsoft.AspNetCore.Components; +using Microsoft.JSInterop; namespace FruitBankHybrid.Shared.Components.Grids; +//var a = new GridDevExtremeDataSource(DataSource.AsQueryable().Where(x=>x.IsMeasurable)); + public class FruitBankListGridBase : MgGridBase, TDataItem, int, LoggerClient> where TDataItem : class, IId -{ } +{ + [Inject] public required LoggedInModel LoggedInModel { get; set; } + [Inject] public required IJSRuntime JSRuntime { get; set; } + + [Parameter] public bool IsMasterGrid { get; set; } = false; + [Parameter] public string AutoSaveLayoutName { get; set; } + + private bool _isFirstInitializeParameterCore; + private bool _isFirstInitializeParameters; + public bool PreRendered { get; set; } + + //public virtual Task ReloadDataFromDb(bool forceReload = false) + //{ + // throw new NotImplementedException(); + //} + + protected void OnCustomizeElement(GridCustomizeElementEventArgs e) + { + //if (!IsMasterGrid) e.CssClass = "hideDetailButton"; + + if (IsMasterGrid && e.ElementType == GridElementType.DataRow && e.VisibleIndex % 2 == 1 && !e.Grid.IsRowSelected(e.VisibleIndex) && !e.Grid.IsRowFocused(e.VisibleIndex)) + { + e.CssClass = " alt-item"; + } + + if(e.ElementType == GridElementType.DataRow && !LoggedInModel.IsDeveloper) + { + e.CssClass = "hideDetailButton"; + } + + if (e.ElementType == GridElementType.HeaderCell) + { + e.Style = "background-color: #E6E6E6;"; + //e.CssClass = "header-bold"; + } + } + protected override async Task SetParametersAsyncCore(ParameterView parameters) + { + await base.SetParametersAsyncCore(parameters); + + if (!_isFirstInitializeParameterCore) + { + //if (typeof(TDataItem) is IId || typeof(TDataItem) is IId) + KeyFieldName = "Id"; + + //base.DataItemDeleting = EventCallback.Factory.Create(this, OnItemDeleting); + //base.EditModelSaving = EventCallback.Factory.Create(this, OnItemSaving); + + CustomizeElement += OnCustomizeElement; + + _isFirstInitializeParameterCore = true; + } + } + + + protected override void OnParametersSet() + { + base.OnParametersSet(); + + if (!_isFirstInitializeParameters) + { + SizeMode = DevExpress.Blazor.SizeMode.Small; + ShowGroupPanel = IsMasterGrid; + ShowSearchBox = IsMasterGrid; + ShowFilterRow = IsMasterGrid; + + FilterMenuButtonDisplayMode = (IsMasterGrid ? GridFilterMenuButtonDisplayMode.Never : GridFilterMenuButtonDisplayMode.Always); + + DetailRowDisplayMode = IsMasterGrid ? GridDetailRowDisplayMode.Auto : GridDetailRowDisplayMode.Never; + DetailExpandButtonDisplayMode = IsMasterGrid ? GridDetailExpandButtonDisplayMode.Auto : GridDetailExpandButtonDisplayMode.Never; + + TextWrapEnabled = false; + AllowSelectRowByClick = true; + HighlightRowOnHover = true; + AutoCollapseDetailRow = true; + AutoExpandAllGroupRows = false; + + PagerVisible = IsMasterGrid; + PageSize = IsMasterGrid ? (SizeMode == DevExpress.Blazor.SizeMode.Small ? 23 : 15) : 50; + + AllowColumnReorder = true; + AllowGroup = IsMasterGrid; + AllowSort = true; + + EditMode = GridEditMode.EditRow; + FocusedRowEnabled = true; + ColumnResizeMode = GridColumnResizeMode.NextColumn; + //VirtualScrollingEnabled = IsMasterGrid; + PageSizeSelectorVisible = true; + + if (IsMasterGrid && !AutoSaveLayoutName.IsNullOrWhiteSpace()) + { + LayoutAutoLoading = Grid_LayoutAutoLoading; + LayoutAutoSaving = Grid_LayoutAutoSaving; + } + + _isFirstInitializeParameters = true; + } + } + + protected override void OnAfterRender(bool firstRender) + { + base.OnAfterRender(firstRender); + + if (firstRender) + { + //PreRendered = true; + //StateHasChanged(); + } + + } + + async Task Grid_LayoutAutoLoading(GridPersistentLayoutEventArgs e) + { + e.Layout = await LoadLayoutFromLocalStorageAsync($"{AutoSaveLayoutName}_AutoSave_{LoggedInModel.CustomerDto?.Id ?? 0}"); + } + + private async Task Grid_LayoutAutoSaving(GridPersistentLayoutEventArgs e) + { + await SaveLayoutToLocalStorageAsync(e.Layout, $"{AutoSaveLayoutName}_AutoSave_{LoggedInModel.CustomerDto?.Id ?? 0}"); + } + + async Task LoadLayoutFromLocalStorageAsync(string localStorageKey) + { + try + { + var json = await JSRuntime.InvokeAsync("localStorage.getItem", localStorageKey); + + if (!json.IsNullOrWhiteSpace()) return json.JsonTo(); + } + catch + { + // Mute exceptions for the server prerender stage + } + + return null; + } + async Task SaveLayoutToLocalStorageAsync(GridPersistentLayout layout, string localStorageKey) + { + try + { + var json = layout.ToJson(); + await JSRuntime.InvokeVoidAsync("localStorage.setItem", localStorageKey, json); + } + catch + { + // Mute exceptions for the server prerender stage + } + } +} //public abstract class FruitBankObservableGridBase : MgGridBase, TDataItem, int, LoggerClient> where TDataItem : class, IId //{ } \ No newline at end of file diff --git a/FruitBankHybrid.Shared/Components/Grids/ShippingItems/GridShippingItem.cs b/FruitBankHybrid.Shared/Components/Grids/ShippingItems/GridShippingItem.cs index 865fe40..cf3a106 100644 --- a/FruitBankHybrid.Shared/Components/Grids/ShippingItems/GridShippingItem.cs +++ b/FruitBankHybrid.Shared/Components/Grids/ShippingItems/GridShippingItem.cs @@ -7,9 +7,9 @@ using Microsoft.AspNetCore.Components; namespace FruitBankHybrid.Shared.Components.Grids.ShippingItems; -public class GridShippingItem : FruitBankListGridBase, IGrid +public class GridShippingItemBase : FruitBankListGridBase, IGrid { - public GridShippingItem() : base() + public GridShippingItemBase() : base() { GetAllMessageTag = SignalRTags.GetShippingItems; AddMessageTag = SignalRTags.AddShippingItem; diff --git a/FruitBankHybrid.Shared/Components/MgGridBase.cs b/FruitBankHybrid.Shared/Components/MgGridBase.cs index 7a1c9fa..e14fa07 100644 --- a/FruitBankHybrid.Shared/Components/MgGridBase.cs +++ b/FruitBankHybrid.Shared/Components/MgGridBase.cs @@ -50,6 +50,11 @@ public class MgGridBase : DxGrid e.CssClass = " alt-item"; } + if(e.ElementType == GridElementType.DataRow && !LoggedInModel.IsDeveloper) + { + e.CssClass = "hideDetailButton"; + } + if (e.ElementType == GridElementType.HeaderCell) { e.Style = "background-color: #E6E6E6;"; @@ -104,7 +109,7 @@ public class MgGridBase : DxGrid EditMode = GridEditMode.EditRow; FocusedRowEnabled = true; - ColumnResizeMode = GridColumnResizeMode.ColumnsContainer; + ColumnResizeMode = GridColumnResizeMode.NextColumn; //VirtualScrollingEnabled = IsMasterGrid; PageSizeSelectorVisible = true; diff --git a/FruitBankHybrid.Shared/Components/Toolbars/FruitBankToolbarTemplate.razor b/FruitBankHybrid.Shared/Components/Toolbars/FruitBankToolbarTemplate.razor new file mode 100644 index 0000000..71c54ef --- /dev/null +++ b/FruitBankHybrid.Shared/Components/Toolbars/FruitBankToolbarTemplate.razor @@ -0,0 +1,98 @@ +@using AyCode.Core.Loggers; +@using AyCode.Core.Extensions +@using AyCode.Core.Helpers +@using AyCode.Utils.Extensions +@using FruitBank.Common.Dtos +@using FruitBank.Common.Entities +@using FruitBank.Common.Models +@using FruitBankHybrid.Shared.Components.Grids.ShippingItems +@using FruitBankHybrid.Shared.Databases +@using FruitBankHybrid.Shared.Services.Loggers; +@using FruitBankHybrid.Shared.Services.SignalRs + +@inject IEnumerable LogWriters +@inject FruitBankSignalRClient FruitBankSignalRClient +@inject LoggedInModel LoggedInModel; + + + + + + + + + + + + + + + + + + @* + + *@ + + +@code { + [Parameter] public IGrid Grid{ get; set; } + [Parameter] public EventCallback OnReloadDataClick { get; set; } + + public ToolbarBase Toolbar { get; set; } + const string ExportFileName = "ExportResult"; + public bool EditItemsEnabled { get; set; } = true; + private LoggerClient _logger; + + protected override async Task OnInitializedAsync() + { + _logger = new LoggerClient(LogWriters.ToArray()); + } + + async Task ReloadData_Click(ToolbarItemClickEventArgs e) + { + await OnReloadDataClick.InvokeAsync(); + } + + async Task NewItem_Click() + { + EditItemsEnabled = false; + await Grid.StartEditNewRowAsync(); + } + async Task EditItem_Click() + { + EditItemsEnabled = false; + await Grid.StartEditRowAsync(Grid.GetFocusedRowIndex()); + } + void DeleteItem_Click() + { + EditItemsEnabled = false; + Grid.ShowRowDeleteConfirmation(Grid.GetFocusedRowIndex()); + } + + void ColumnChooserItem_Click(ToolbarItemClickEventArgs e) + { + Grid.ShowColumnChooser(); + } + async Task ExportXlsxItem_Click() + { + await Grid.ExportToXlsxAsync(ExportFileName); + } + async Task ExportXlsItem_Click() + { + await Grid.ExportToXlsAsync(ExportFileName); + } + async Task ExportCsvItem_Click() + { + await Grid.ExportToCsvAsync(ExportFileName); + } + async Task ExportPdfItem_Click() + { + await Grid.ExportToPdfAsync(ExportFileName); + } +} \ No newline at end of file diff --git a/FruitBankHybrid.Shared/Components/Toolbars/ToolbarBase.cs b/FruitBankHybrid.Shared/Components/Toolbars/ToolbarBase.cs new file mode 100644 index 0000000..2b76633 --- /dev/null +++ b/FruitBankHybrid.Shared/Components/Toolbars/ToolbarBase.cs @@ -0,0 +1,17 @@ +using DevExpress.Blazor; +using DevExpress.Blazor.Navigation.Internal; +using Microsoft.AspNetCore.Components; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace FruitBankHybrid.Shared.Components.Toolbars +{ + public class ToolbarBase : DxToolbar + { + [Parameter] public IGrid Grid { get; set; } + [Parameter] public Func RefreshClick { get; set; } + } +} diff --git a/FruitBankHybrid.Shared/Databases/DatabaseClient.cs b/FruitBankHybrid.Shared/Databases/DatabaseClient.cs index 199583e..39adbb8 100644 --- a/FruitBankHybrid.Shared/Databases/DatabaseClient.cs +++ b/FruitBankHybrid.Shared/Databases/DatabaseClient.cs @@ -1,16 +1,31 @@ using AyCode.Core.Extensions; +using AyCode.Core.Interfaces; using AyCode.Interfaces.Entities; +using AyCode.Services.SignalRs; +using AyCode.Utils.Extensions; using AyCode.Utils.Wrappers; +using DevExpress.Blazor.Scheduler.Internal; +using FruitBank.Common; using FruitBank.Common.Dtos; +using FruitBank.Common.Entities; +using FruitBank.Common.SignalRs; using FruitBankHybrid.Shared.Services.SignalRs; using Nop.Core.Domain.Common; using Nop.Core.Domain.Orders; using System.Collections.Concurrent; using System.Collections.ObjectModel; -using AyCode.Utils.Extensions; +using System.Threading; namespace FruitBankHybrid.Shared.Databases; +public class ShippingTableItem : Shipping +{ } +public class ShippingDocumentTableItem : ShippingDocument +{ } +public class ShippingItemTableItem : ShippingItem +{ } +public class ShippingItemPalletTableItem : ShippingItemPallet +{ } public class ProductDtoTableItem : ProductDto { //[Newtonsoft.Json.JsonProperty] @@ -25,7 +40,22 @@ public class OrderDtoTableItem : OrderDto //public new ObservableCollection? OrderItemDtos { get; set; } } -public class ProductDtoTable(FruitBankSignalRClient fruitBankSignalRClient) : ObservableCollection +public class ShippingItemTable : SignalRDataSourceList +{ + private static readonly SignalRCrudTags SignalRCrudTags = new(SignalRTags.GetShippingItems, 0, SignalRTags.AddShippingItem, SignalRTags.UpdateShippingItem, 0); + + public ShippingItemTable(AcSignalRClientBase signalRClient, params object[]? contextIds) + : this(signalRClient, SignalRCrudTags, contextIds) + { + + } + + public ShippingItemTable(AcSignalRClientBase signalRClient, SignalRCrudTags signalRCrudTags, params object[]? contextIds) : base(signalRClient, signalRCrudTags, contextIds) + { + } +} + +public class ProductDtoTable(FruitBankSignalRClient fruitBankSignalRClient) : FastObservableCollection { private readonly SemaphoreSlim _semaphoreSlim = new(1); public async Task LoadDataAsync(bool onlyIfEmpty = true) @@ -34,21 +64,23 @@ public class ProductDtoTable(FruitBankSignalRClient fruitBankSignalRClient) : Ob using (await _semaphoreSlim.UseWaitAsync()) { - if (Count != 0) return this; + //Előfordulhat, h egy másik szálban már megtörtént a refresh... - J. + if (onlyIfEmpty && Count != 0) return this; var items = (await fruitBankSignalRClient.GetProductDtoTableItems() ?? []); - Clear(); - foreach (var productDto in items) - { - this.Add(productDto); - } + //Clear(); + this.Replace(items); + //foreach (var productDto in items) + //{ + // this.UpdateCollection(productDto, false); + //} } return this; } } -public class OrderDtoTable(FruitBankSignalRClient fruitBankSignalRClient) : ObservableCollection +public class OrderDtoTable(FruitBankSignalRClient fruitBankSignalRClient) : FastObservableCollection { private readonly SemaphoreSlim _semaphoreSlim = new(1); @@ -62,26 +94,81 @@ public class OrderDtoTable(FruitBankSignalRClient fruitBankSignalRClient) : Obse var items = (await fruitBankSignalRClient.GetAllOrderDtoTableItems() ?? []); - Clear(); - foreach (var orderDto in items) - { - this.Add(orderDto); - } + //Clear(); + this.Replace(items); + //foreach (var orderDto in items) + //{ + // this.UpdateCollection(orderDto, false); + //} } return this; } } +public abstract class DatabaseTableBase : SignalRDataSourceObservable where TDataItem : class, IId +{ + protected DatabaseTableBase(AcSignalRClientBase signalRClient, SignalRCrudTags signalRCrudTags, params object[]? contextIds) : base(signalRClient, signalRCrudTags, contextIds) + { + } + + //protected readonly SemaphoreSlim _semaphoreSlim = new(1); + + //public async Task LoadDataAsync(bool onlyIfEmpty = true) + //{ + // if (onlyIfEmpty && Count != 0) return this; + + // using (await _semaphoreSlim.UseWaitAsync()) + // { + // if (Count != 0) return this; + + // var items = (await fruitBankSignalRClient.GetAllOrderDtoTableItems() ?? []); + + // Clear(); + // foreach (var orderDto in items) + // { + // this.Add(orderDto); + // } + // } + + // return this; + //} +} + +public static class LoadingPanelVisibility +{ + public static bool Visible =false; +} + +public static class ObjectLock +{ + private static readonly Dictionary SemaphoresByType = new(); + + public static SemaphoreSlim GetSemaphore() + { + lock (SemaphoresByType) + { + if (!SemaphoresByType.TryGetValue(typeof(TObject), out var semaphore)) + { + semaphore = new SemaphoreSlim(1); + SemaphoresByType[typeof(TObject)] = semaphore; + } + + return semaphore; + } + } +} + public class DatabaseClient : DatabaseClientBase { - private FruitBankSignalRClient _fruitBankSignalRClient; + private readonly FruitBankSignalRClient _fruitBankSignalRClient; public DatabaseClient(FruitBankSignalRClient fruitBankSignalRClient) { _fruitBankSignalRClient = fruitBankSignalRClient; AddTable(new ProductDtoTable(_fruitBankSignalRClient)); + AddTable(new ShippingItemTable(_fruitBankSignalRClient)); AddTable(new OrderDtoTable(_fruitBankSignalRClient)); } diff --git a/FruitBankHybrid.Shared/Layout/MainLayout.razor.cs b/FruitBankHybrid.Shared/Layout/MainLayout.razor.cs index a868768..a132d20 100644 --- a/FruitBankHybrid.Shared/Layout/MainLayout.razor.cs +++ b/FruitBankHybrid.Shared/Layout/MainLayout.razor.cs @@ -2,6 +2,7 @@ using AyCode.Core.Extensions; using AyCode.Core.Loggers; using AyCode.Services.SignalRs; +using AyCode.Utils.Extensions; using DevExpress.Blazor; using FruitBank.Common.Dtos; using FruitBank.Common.Models; @@ -31,7 +32,7 @@ public partial class MainLayout : LayoutComponentBase // Toast fields private DxToast orderNotificationToast; private string toastTitle = "Értesítő!"; - private string toastMessage = ""; + private string? toastMessage; private string? toastOrderNumber; private DateTime? toastDateOfReceipt; @@ -59,21 +60,29 @@ public partial class MainLayout : LayoutComponentBase return; } + toastOrderNumber = null; + toastDateOfReceipt = null; + + toastMessage = notificationMessage.Message; + var orderDto = notificationMessage.Content; - if ((orderDto?.HasMeasuringAccess(LoggedInModel.CustomerDto!.Id, LoggedInModel.IsRevisor) ?? LoggedInModel.IsRevisor) || orderDto?.MeasurementOwnerId == 0) + var hasPermission = orderDto == null || (orderDto.HasMeasuringAccess(LoggedInModel.CustomerDto!.Id, LoggedInModel.IsRevisor) || orderDto.MeasurementOwnerId == 0); + + if (orderDto != null && hasPermission) { - toastMessage = notificationMessage.Message; - toastOrderNumber = orderDto?.CustomOrderNumber; - toastDateOfReceipt = orderDto?.DateOfReceipt; - - _logger.Debug($"NotificationMessage received. {toastMessage}"); - - await InvokeAsync(() => - { - orderNotificationToast?.Show(); - StateHasChanged(); - }); + toastOrderNumber = orderDto.CustomOrderNumber; + toastDateOfReceipt = orderDto.DateOfReceipt; } + + if (!hasPermission) return; + + _logger.Debug($"NotificationMessage received. {toastMessage}"); + + await InvokeAsync(() => + { + orderNotificationToast?.Show(); + StateHasChanged(); + }); } private void OnLogoutClick() diff --git a/FruitBankHybrid.Shared/Layout/NavMenu.razor b/FruitBankHybrid.Shared/Layout/NavMenu.razor index 65edb22..da7c360 100644 --- a/FruitBankHybrid.Shared/Layout/NavMenu.razor +++ b/FruitBankHybrid.Shared/Layout/NavMenu.razor @@ -37,14 +37,16 @@ - @if (LoggedInModel.IsDeveloper) + @if (LoggedInModel.IsAdministrator) { - + } + @if (LoggedInModel.IsDeveloper) + {