diff --git a/src/Data/Repositories/Interfaces/IWalletRepository.cs b/src/Data/Repositories/Interfaces/IWalletRepository.cs index b552700f..dd60dfee 100644 --- a/src/Data/Repositories/Interfaces/IWalletRepository.cs +++ b/src/Data/Repositories/Interfaces/IWalletRepository.cs @@ -27,6 +27,19 @@ public interface IWalletRepository Task GetById(int id); Task> GetAll(); + + Task<(List wallets, int totalCount)> GetPaginatedAsync( + int pageNumber, + int pageSize, + string? nameFilter = null, + string? statusFilter = null, + bool archivedFilter = false, + bool compromisedFilter = false, + bool hotWalletFilter = false, + bool coldWalletFilter = false, + bool finalisedFilter = false, + DateTimeOffset? fromDate = null, + DateTimeOffset? toDate = null); Task> GetAvailableByType(WALLET_TYPE type); diff --git a/src/Data/Repositories/WalletRepository.cs b/src/Data/Repositories/WalletRepository.cs index 2144ef93..7b2d4460 100644 --- a/src/Data/Repositories/WalletRepository.cs +++ b/src/Data/Repositories/WalletRepository.cs @@ -70,6 +70,90 @@ public async Task> GetAll() return await applicationDbContext.Wallets.Include(x => x.InternalWallet).Include(x => x.Keys).ToListAsync(); } + public async Task<(List wallets, int totalCount)> GetPaginatedAsync( + int pageNumber, + int pageSize, + string? nameFilter = null, + string? statusFilter = null, + bool archivedFilter = false, + bool compromisedFilter = false, + bool hotWalletFilter = false, + bool coldWalletFilter = false, + bool finalisedFilter = false, + DateTimeOffset? fromDate = null, + DateTimeOffset? toDate = null) + { + await using var applicationDbContext = await _dbContextFactory.CreateDbContextAsync(); + + var query = applicationDbContext.Wallets + .Include(x => x.InternalWallet) + .Include(x => x.Keys) + .AsQueryable(); + + if (!string.IsNullOrWhiteSpace(nameFilter)) + { + query = query.Where(w => w.Name.Contains(nameFilter)); + } + + switch (statusFilter) + { + case "Finalised": + query = query.Where(w => w.IsFinalised); + break; + case "Not Finalised": + query = query.Where(w => !w.IsFinalised); + break; + case "Archived": + query = query.Where(w => w.IsArchived); + break; + case "Not Archived": + query = query.Where(w => !w.IsArchived); + break; + } + + if (fromDate.HasValue) + { + query = query.Where(w => w.CreationDatetime >= fromDate.Value); + } + + if (toDate.HasValue) + { + query = query.Where(w => w.CreationDatetime <= toDate.Value); + } + + if (!archivedFilter && statusFilter != "Archived") + { + query = query.Where(w => !w.IsArchived); + } + + if (!compromisedFilter) + { + query = query.Where(w => !w.IsCompromised); + } + + var anyPropertyFilter = archivedFilter || compromisedFilter || hotWalletFilter || coldWalletFilter || finalisedFilter; + if (anyPropertyFilter) + { + query = query.Where(w => + (archivedFilter && w.IsArchived) || + (compromisedFilter && w.IsCompromised) || + (hotWalletFilter && w.IsHotWallet) || + (coldWalletFilter && !w.IsHotWallet) || + (finalisedFilter && w.IsFinalised)); + } + + query = query.OrderByDescending(w => w.CreationDatetime); + + var totalCount = await query.CountAsync(); + + var wallets = await query + .Skip((pageNumber - 1) * pageSize) + .Take(pageSize) + .ToListAsync(); + + return (wallets, totalCount); + } + public async Task> GetAvailableByType(WALLET_TYPE type) { await using var applicationDbContext = await _dbContextFactory.CreateDbContextAsync(); diff --git a/src/Pages/Wallets.razor b/src/Pages/Wallets.razor index a4febb82..1fd22826 100644 --- a/src/Pages/Wallets.razor +++ b/src/Pages/Wallets.razor @@ -2,6 +2,7 @@ @using System.Security.Claims @using System.Linq; @using Blazorise.Extensions +@using Blazorise.Components @using NodeGuard.Jobs @using Humanizer @using NBitcoin @@ -31,10 +32,64 @@

Treasury Wallets

+ + + + Name + + + + + + Properties + + Select + +
+ 🔥 Hot Wallet + ❄️ Cold Wallet + 🏁 Finalised + 📂 Archived + ⛔️ Compromised +
+
+
+
+
+ + + From + + + + + + To + + + + + + +
+ >

@(context.EditState) wallet

@@ -130,21 +185,7 @@ - - - - Select - -
- 🔥 Hot Wallet - ❄️ Cold Wallet - 🏁 finalised - 📂 Archived - ⛔️ Compromised -
-
-
-
+ Wallet Properties @@ -828,7 +869,14 @@ OnSubmit="TransferFundsHotWallet"/> private bool _finalisedWalletFilter = false; private bool _archivedWalletFilter = false; private bool _compromisedWalletFilter = false; + private string _nameFilter = string.Empty; + private List _walletNameOptions = new(); + private string _walletStatusFilter = "All"; + private DateTime? _fromDateFilter; + private DateTime? _toDateFilter; + private int _filtersResetKey; private DataGrid _walletsDataGrid; + private int _totalItems; private ColumnLayout WalletsColumnLayout; private Dictionary WalletsColumns = new(); @@ -888,16 +936,72 @@ OnSubmit="TransferFundsHotWallet"/> private async Task GetData() { - _wallets = await WalletRepository.GetAll(); var financeManagers = (await ApplicationUserRepository.GetUsersInRole(ApplicationUserRole.FinanceManager)); _financeManagers = financeManagers.Where(x => x.Keys.Any()).ToList(); + if (_walletNameOptions.Count == 0) + { + var walletNames = await WalletRepository.GetAll(); + _walletNameOptions = walletNames + .Select(wallet => wallet.Name) + .Where(name => !string.IsNullOrWhiteSpace(name)) + .Distinct() + .OrderBy(name => name) + .ToList(); + } + if (_financeManagers.Any()) _selectedFinanceManager = financeManagers.FirstOrDefault(); if (_selectedFinanceManager?.Keys != null) _selectedFinanceManagerAvailableKeys = await FilterKeys(_selectedFinanceManager.Keys); } + private async Task OnReadData(DataGridReadDataEventArgs e) + { + var fromDate = _fromDateFilter.HasValue + ? new DateTimeOffset(DateTime.SpecifyKind(_fromDateFilter.Value.Date, DateTimeKind.Local)).ToUniversalTime() + : (DateTimeOffset?)null; + var toDate = _toDateFilter.HasValue + ? new DateTimeOffset(DateTime.SpecifyKind(_toDateFilter.Value.Date.AddDays(1).AddTicks(-1), DateTimeKind.Local)).ToUniversalTime() + : (DateTimeOffset?)null; + + var (wallets, totalCount) = await WalletRepository.GetPaginatedAsync( + e.Page, + e.PageSize, + nameFilter: _nameFilter, + statusFilter: _walletStatusFilter, + archivedFilter: _archivedWalletFilter, + compromisedFilter: _compromisedWalletFilter, + hotWalletFilter: _hotWalletFilter, + coldWalletFilter: _coldWalletFilter, + finalisedFilter: _finalisedWalletFilter, + fromDate: fromDate, + toDate: toDate); + + _wallets = wallets; + _totalItems = totalCount; + } + + private async Task OnFiltersChanged() + { + await _walletsDataGrid.Reload(); + } + + private async Task ClearAllFilters() + { + _hotWalletFilter = false; + _coldWalletFilter = false; + _finalisedWalletFilter = false; + _archivedWalletFilter = false; + _compromisedWalletFilter = false; + _nameFilter = string.Empty; + _walletStatusFilter = "All"; + _fromDateFilter = null; + _toDateFilter = null; + _filtersResetKey++; + await _walletsDataGrid.Reload(); + } + private async Task OnRowInserted(SavedRowItem> arg) { @@ -917,7 +1021,8 @@ OnSubmit="TransferFundsHotWallet"/> AuditObjectType.Wallet, arg.Item.Id.ToString(), new { Name = arg.Item.Name, IsHotWallet = arg.Item.IsHotWallet, MofN = arg.Item.MofN }); - await GetData(); + AddWalletNameOption(arg.Item.Name); + await _walletsDataGrid.Reload(); } else { @@ -963,7 +1068,7 @@ OnSubmit="TransferFundsHotWallet"/> AuditObjectType.Wallet, arg.Item.Id.ToString(), new { Name = arg.Item.Name }); - await GetData(); + await _walletsDataGrid.Reload(); } } } @@ -1000,6 +1105,7 @@ OnSubmit="TransferFundsHotWallet"/> AuditObjectType.Wallet, arg.Item.Id.ToString(), new { Name = arg.Item.Name, IsHotWallet = arg.Item.IsHotWallet }); + AddWalletNameOption(arg.Item.Name); } else { @@ -1012,7 +1118,7 @@ OnSubmit="TransferFundsHotWallet"/> new { Name = arg.Item.Name, Error = updateResult.Item2 }); } - await GetData(); + await _walletsDataGrid.Reload(); } private async Task CloseModal() @@ -1091,7 +1197,7 @@ OnSubmit="TransferFundsHotWallet"/> CleanModal(); - await GetData(); + await _walletsDataGrid.Reload(); await _modalRef.Close(CloseReason.UserClosing); } @@ -1320,7 +1426,7 @@ OnSubmit="TransferFundsHotWallet"/> await _finaliseModalRef.Close(CloseReason.UserClosing); - await GetData(); + await _walletsDataGrid.Reload(); } private async Task CloseAndCleanFinaliseModal() @@ -1403,7 +1509,7 @@ OnSubmit="TransferFundsHotWallet"/> } //Load data - await GetData(); + await _walletsDataGrid.Reload(); //Success ToastService.ShowSuccess("Wallet imported successfully"); @@ -1725,17 +1831,20 @@ OnSubmit="TransferFundsHotWallet"/> await CloseTextModal(); } - private bool OnWalletCustomFilter(Wallet wallet) + private void AddWalletNameOption(string? name) { - bool anyCheck = _archivedWalletFilter || _compromisedWalletFilter || _hotWalletFilter || _coldWalletFilter || _finalisedWalletFilter; - if (!anyCheck) - return true; + if (string.IsNullOrWhiteSpace(name)) + { + return; + } - return _archivedWalletFilter && wallet.IsArchived - || _compromisedWalletFilter && wallet.IsCompromised - || _hotWalletFilter && wallet.IsHotWallet - || _coldWalletFilter && !wallet.IsHotWallet - || _finalisedWalletFilter && wallet.IsFinalised; + if (_walletNameOptions.Contains(name)) + { + return; + } + + _walletNameOptions.Add(name); + _walletNameOptions = _walletNameOptions.OrderBy(option => option).ToList(); } private void OnColumnLayoutUpdate() @@ -1754,7 +1863,7 @@ OnSubmit="TransferFundsHotWallet"/> private Task OnCheckedChanged(bool value) { - return _walletsDataGrid.Reload(); + return Task.CompletedTask; } private async Task ValidateOutputDescriptor(ValidatorEventArgs arg1, CancellationToken arg2)