diff --git a/EstateManagementUI.BlazorServer/Components/Pages/Reporting/TransactionDetail.razor b/EstateManagementUI.BlazorServer/Components/Pages/Reporting/TransactionDetail.razor index 2776ccb7..ea87017d 100644 --- a/EstateManagementUI.BlazorServer/Components/Pages/Reporting/TransactionDetail.razor +++ b/EstateManagementUI.BlazorServer/Components/Pages/Reporting/TransactionDetail.razor @@ -210,9 +210,6 @@ - @@ -225,6 +222,9 @@ + @@ -232,26 +232,25 @@ Status @GetSortIcon(nameof(TransactionDetailModel.TransactionStatus)) - @foreach (var item in pagedData) { - + - } diff --git a/EstateManagementUI.BlazorServer/Components/Pages/Reporting/TransactionDetail.razor.cs b/EstateManagementUI.BlazorServer/Components/Pages/Reporting/TransactionDetail.razor.cs index 9f4379d4..f8816eeb 100644 --- a/EstateManagementUI.BlazorServer/Components/Pages/Reporting/TransactionDetail.razor.cs +++ b/EstateManagementUI.BlazorServer/Components/Pages/Reporting/TransactionDetail.razor.cs @@ -266,9 +266,6 @@ private void SortBy(string columnName) detailData.Transactions = columnName switch { - nameof(TransactionModels.TransactionDetailModel.TransactionId) => _sortAscending - ? detailData.Transactions.OrderBy(t => t.Id).ToList() - : detailData.Transactions.OrderByDescending(t => t.Id).ToList(), nameof(TransactionModels.TransactionDetailModel.TransactionDateTime) => _sortAscending ? detailData.Transactions.OrderBy(t => t.DateTime).ToList() : detailData.Transactions.OrderByDescending(t => t.DateTime).ToList(), @@ -281,6 +278,9 @@ private void SortBy(string columnName) nameof(TransactionModels.TransactionDetailModel.ProductName) => _sortAscending ? detailData.Transactions.OrderBy(t => t.Product).ToList() : detailData.Transactions.OrderByDescending(t => t.Product).ToList(), + nameof(TransactionModels.TransactionDetailModel.TransactionNumber) => _sortAscending + ? detailData.Transactions.OrderBy(t => t.TransactionNumber).ToList() + : detailData.Transactions.OrderByDescending(t => t.TransactionNumber).ToList(), nameof(TransactionModels.TransactionDetailModel.TransactionType) => _sortAscending ? detailData.Transactions.OrderBy(t => t.Type).ToList() : detailData.Transactions.OrderByDescending(t => t.Type).ToList(), @@ -293,9 +293,9 @@ private void SortBy(string columnName) nameof(TransactionModels.TransactionDetailModel.FeesCommission) => _sortAscending ? detailData.Transactions.OrderBy(t => t.TotalFees).ToList() : detailData.Transactions.OrderByDescending(t => t.TotalFees).ToList(), - //nameof(TransactionDetailModel.NetAmount) => _sortAscending - // ? detailData.Transactions.OrderBy(t => t.NetAmount).ToList() - // : detailData.Transactions.OrderByDescending(t => t.NetAmount).ToList(), + nameof(TransactionModels.TransactionDetailModel.NetAmount) => _sortAscending + ? detailData.Transactions.OrderBy(t => t.NetAmount).ToList() + : detailData.Transactions.OrderByDescending(t => t.NetAmount).ToList(), _ => detailData.Transactions }; @@ -310,12 +310,6 @@ private string GetSortIcon(string columnName) return _sortAscending ? "↑" : "↓"; } - private string GetShortId(Guid transactionId) - { - var idString = transactionId.ToString(); - return idString.Length >= 8 ? $"{idString.Substring(0, 8)}..." : idString; - } - private string GetTypeBadgeClass(string? type) { return type switch @@ -347,12 +341,12 @@ private async Task ExportToCSV() var csv = new StringBuilder(); // Header - csv.AppendLine("Transaction ID,Transaction Date & Time,Merchant,Operator,Product,Transaction Type,Transaction Status,Gross Amount,Fees/Commission,Settlement Reference"); + csv.AppendLine("Transaction Date & Time,Merchant,Operator,Product,Txn No,Transaction Type,Transaction Status,Gross Amount,Fees/Commission,Net Amount"); // Data rows foreach (var item in detailData.Transactions) { - csv.AppendLine($"\"{item.Id}\",\"{item.DateTime:yyyy-MM-dd HH:mm:ss}\",\"{item.Merchant}\",\"{item.Operator}\",\"{item.Product}\",\"{item.Type}\",\"{item.Status}\",{item.Value},{item.TotalFees},\"{item.SettlementReference ?? ""}\""); + csv.AppendLine($"\"{item.DateTime:yyyy-MM-dd HH:mm:ss}\",\"{item.Merchant}\",\"{item.Operator}\",\"{item.Product}\",{item.TransactionNumber},\"{item.Type}\",\"{item.Status}\",{item.Value},{item.TotalFees},{item.NetAmount}"); } var fileName = $"transaction-detail-{DateTime.Now:yyyyMMdd-HHmmss}.csv"; diff --git a/EstateManagementUI.BlazorServer/Components/Shared/MultiSelectDropdown.razor b/EstateManagementUI.BlazorServer/Components/Shared/MultiSelectDropdown.razor index 06df890e..4d57ebf9 100644 --- a/EstateManagementUI.BlazorServer/Components/Shared/MultiSelectDropdown.razor +++ b/EstateManagementUI.BlazorServer/Components/Shared/MultiSelectDropdown.razor @@ -1,5 +1,7 @@ @typeparam TItem @using System.Linq.Expressions +@inject IJSRuntime JSRuntime +@implements IAsyncDisposable
@@ -38,7 +40,8 @@ + class="h-4 w-4 rounded border-gray-300 cursor-pointer" + style="accent-color: var(--color-admin-primary);" /> @GetItemText(item) } @@ -54,6 +57,7 @@ @code { private ElementReference dropdownRef; private bool isOpen = false; + private DotNetObjectReference>? _dotNetRef; [Parameter] public List? Items { get; set; } @@ -84,6 +88,25 @@ } } + protected override async Task OnAfterRenderAsync(bool firstRender) + { + if (firstRender) + { + _dotNetRef = DotNetObjectReference.Create(this); + await JSRuntime.InvokeVoidAsync("registerClickOutsideHandler", dropdownRef, _dotNetRef); + } + } + + [JSInvokable] + public void CloseDropdown() + { + if (isOpen) + { + isOpen = false; + StateHasChanged(); + } + } + private void ToggleDropdown() { isOpen = !isOpen; @@ -103,6 +126,20 @@ await SelectedItemsChanged.InvokeAsync(SelectedItems); } - // Close dropdown when clicking outside (would need JS interop for full implementation) - // For now, we'll keep it simple and let users close by clicking the button again + public async ValueTask DisposeAsync() + { + try + { + await JSRuntime.InvokeVoidAsync("unregisterClickOutsideHandler", dropdownRef); + } + catch (JSDisconnectedException) + { + // Circuit has already been disconnected — safe to ignore + } + catch (TaskCanceledException) + { + // Component disposed during navigation — safe to ignore + } + _dotNetRef?.Dispose(); + } } diff --git a/EstateManagementUI.BlazorServer/Factories/ModelFactory.cs b/EstateManagementUI.BlazorServer/Factories/ModelFactory.cs index 0fd5f2d4..d88e36b9 100644 --- a/EstateManagementUI.BlazorServer/Factories/ModelFactory.cs +++ b/EstateManagementUI.BlazorServer/Factories/ModelFactory.cs @@ -480,6 +480,7 @@ public static List ConvertFrom(List() }; diff --git a/EstateManagmentUI.BusinessLogic/Models/TransactionModels.cs b/EstateManagmentUI.BusinessLogic/Models/TransactionModels.cs index cf619203..1b4c8c8e 100644 --- a/EstateManagmentUI.BusinessLogic/Models/TransactionModels.cs +++ b/EstateManagmentUI.BusinessLogic/Models/TransactionModels.cs @@ -29,6 +29,7 @@ public class TransactionDetail public Int32 ProductReportingId { get; set; } public String Type { get; set; } public String Status { get; set; } + public Int32 TransactionNumber { get; set; } public Decimal Value { get; set; } public Decimal TotalFees { get; set; } public String SettlementReference { get; set; }
- Transaction ID @GetSortIcon(nameof(TransactionDetailModel.TransactionId)) - Date & Time @GetSortIcon(nameof(TransactionDetailModel.TransactionDateTime)) Product @GetSortIcon(nameof(TransactionDetailModel.ProductName)) + Txn No @GetSortIcon(nameof(TransactionDetailModel.TransactionNumber)) + Type @GetSortIcon(nameof(TransactionDetailModel.TransactionType)) - Gross Amount @GetSortIcon(nameof(TransactionDetailModel.GrossAmount)) + Gross @GetSortIcon(nameof(TransactionDetailModel.GrossAmount)) Fees @GetSortIcon(nameof(TransactionDetailModel.FeesCommission)) - Net Amount @GetSortIcon(nameof(TransactionDetailModel.NetAmount)) + Net @GetSortIcon(nameof(TransactionDetailModel.NetAmount)) Settlement Ref
@GetShortId(item.Id) @item.DateTime.ToString("yyyy-MM-dd HH:mm:ss") @item.Merchant @item.Operator @item.Product@item.TransactionNumber @item.Type @@ -265,7 +264,6 @@ @item.Value.ToString("C") @item.TotalFees.ToString("C") @item.NetAmount.ToString("C")@(item.SettlementReference ?? "-")