PR U-4a: Home refreshes in place instead of forceLoad

SplitBankTransactionAsync ended with NavigateTo(forceLoad: true), which
tore down the SignalR circuit and re-ran every repo constructor just
to refresh the pending-bookings list. Extract data loading into a
LoadDataAsync helper called from OnInitializedAsync, SplitBank
TransactionAsync, and OnCompletedAsync — the page refreshes in-circuit,
scoped caches survive, and the NavigationManager injection can go.

Also flags the plan: U-4 is split into U-4a (this) and U-4b (persist
settings + drop MyHeader's forceLoad, touching ~15 pages).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Claudio Schaad 2026-07-04 09:39:03 +02:00
parent 93bfcae2a0
commit 577d63c0fa
2 changed files with 18 additions and 14 deletions

View file

@ -31,9 +31,6 @@ public partial class Home : ComponentBase
[Inject]
private ITransactionRepository transactionRepository { get; set; } = null!;
[Inject]
private NavigationManager Navigation { get; set; } = null!;
private List<Transaction>? matchingBankTransactions;
private IReadOnlyList<Account> accounts = [];
private IReadOnlyList<string> bookingTexts = [];
@ -45,11 +42,16 @@ public partial class Home : ComponentBase
Dictionary<int, string> Files = new();
protected override async Task OnInitializedAsync()
{
await LoadDataAsync();
await base.OnInitializedAsync();
}
private async Task LoadDataAsync()
{
matchingBankTransactions = await viewService.MatchOpenBankTransactionsAsync();
accounts = await viewService.GetAccountViewListAsync();
bookingTexts = (await bookingTextRepository.GetBookingTextListAsync()).Select(b => b.Text).ToArray();
await base.OnInitializedAsync();
}
async Task OnProgressChangeAsync(FluentInputFileEventArgs file)
@ -96,7 +98,10 @@ public partial class Home : ComponentBase
File.Delete(file.Value);
}
matchingBankTransactions = await viewService.MatchOpenBankTransactionsAsync();
// Imports may update the bank-account balance and add new bank transactions
// — reload everything so the pending list, account balances, and booking-text
// suggestions stay consistent.
await LoadDataAsync();
}
private async Task ImportXmlAndShowResultAsync(string fileName)
@ -174,14 +179,10 @@ public partial class Home : ComponentBase
var result = await dialog.Result;
if (!result.Cancelled && result.Data != null)
{
ReloadPage();
await Task.CompletedTask;
// Re-run the auto-matcher in-place so the newly created split
// transactions disappear from the pending list. No forceLoad — the
// SignalR circuit stays up and the scoped RepositoryCache survives.
await LoadDataAsync();
}
}
private void ReloadPage()
{
var uri = Navigation.Uri;
Navigation.NavigateTo(uri, forceLoad: true); // forceLoad = true does a full reload
}
}

View file

@ -157,7 +157,10 @@ Sequenced by value / risk. Each is one PR unless noted.
### Phase 2 — The forceLoad/singleton trap (biggest single improvement)
- **U-4** Persist year and mandator to a cookie *and* keep them in the URL as query params. `SettingsService` becomes `Scoped`, reading initial state from query params (fallback: cookie, fallback: config default). Header switching becomes an in-place update — no `forceLoad`, no circuit teardown, no state loss.
Split into two PRs on delivery because the header path touches ~15 pages.
- **U-4a** Fix `Home.ReloadPage()` — the single non-settings `forceLoad` in the app. `SplitBankTransactionAsync` and `OnCompletedAsync` (statement import) now call a shared `LoadDataAsync()` that re-runs the auto-matcher, re-fetches accounts and booking texts in place, and keeps the SignalR circuit + scoped `RepositoryCache` alive. No cross-cutting scaffolding needed.
- **U-4b** Persist year and mandator (cookie + URL query params), make `SettingsService` `Scoped`, add an event or `LocationChanged` subscription so every page refreshes on year/mandator change, and drop `MyHeader`'s `forceLoad`. This is the big one — it touches every routable page.
### Phase 3 — Loading and error UX consistency