SF-74: EnvelopeSenderPage — ThemeService/UserPreferencesService inject, LoadFromServerAsync, grid layout persistence (LayoutAutoLoading/Saving)
This commit is contained in:
@@ -8,6 +8,8 @@
|
||||
@using EnvelopeGenerator.Application.Common.Dto
|
||||
@inject EnvelopeGenerator.Server.Client.Services.EnvelopeService EnvelopeService
|
||||
@inject EnvelopeGenerator.Server.Client.Services.AuthService AuthService
|
||||
@inject EnvelopeGenerator.Server.Client.Services.ThemeService ThemeService
|
||||
@inject EnvelopeGenerator.Server.Client.Services.UserPreferencesService UserPreferencesService
|
||||
@inject NavigationManager Navigation
|
||||
@inject IJSRuntime JSRuntime
|
||||
@inject AppVersionService AppVersion
|
||||
@@ -130,7 +132,9 @@
|
||||
SelectionMode="GridSelectionMode.Single"
|
||||
SelectedDataItem="@_selectedEnvelope"
|
||||
SelectedDataItemChanged="@OnSelectedEnvelopeChanged"
|
||||
CustomizeElement="OnCustomizeElement">
|
||||
CustomizeElement="OnCustomizeElement"
|
||||
LayoutAutoLoading="OnActiveGridLayoutAutoLoading"
|
||||
LayoutAutoSaving="OnActiveGridLayoutAutoSaving">
|
||||
<Columns>
|
||||
<DxGridDataColumn FieldName="Id" Caption="ID"
|
||||
SortIndex="0"
|
||||
@@ -228,7 +232,9 @@
|
||||
SelectionMode="GridSelectionMode.Single"
|
||||
SelectedDataItem="@_selectedEnvelope"
|
||||
SelectedDataItemChanged="@OnSelectedEnvelopeChanged"
|
||||
CustomizeElement="OnCustomizeElement">
|
||||
CustomizeElement="OnCustomizeElement"
|
||||
LayoutAutoLoading="OnCompletedGridLayoutAutoLoading"
|
||||
LayoutAutoSaving="OnCompletedGridLayoutAutoSaving">
|
||||
<Columns>
|
||||
<DxGridDataColumn FieldName="Id" Caption="ID"
|
||||
SortIndex="0"
|
||||
@@ -335,6 +341,10 @@
|
||||
private DxGrid? _gridActive;
|
||||
private DxGrid? _gridCompleted;
|
||||
|
||||
// Stable keys used to store/restore each grid's layout in UserPreferences.GridLayouts
|
||||
private const string GridKeyActive = "sender.active-envelopes";
|
||||
private const string GridKeyCompleted = "sender.completed-envelopes";
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
var hasAccess = await AuthService.CheckSenderAccessAsync();
|
||||
@@ -344,6 +354,12 @@
|
||||
return;
|
||||
}
|
||||
|
||||
// Load theme + DisplayName from server after authentication.
|
||||
// Non-fatal: if this fails the page still loads with default theme.
|
||||
// ThemeService.ScheduleSaveAsync() already logs errors internally.
|
||||
try { await ThemeService.LoadFromServerAsync(); }
|
||||
catch { /* swallow — default theme remains active */ }
|
||||
|
||||
await LoadEnvelopesAsync();
|
||||
}
|
||||
|
||||
@@ -361,13 +377,10 @@
|
||||
var envelopes = _allEnvelopes.ToList();
|
||||
_activeEnvelopes = envelopes.Where(e => ((EnvelopeStatus)e.Status).IsActive()).ToList();
|
||||
_completedEnvelopes = envelopes.Where(e => ((EnvelopeStatus)e.Status).IsCompleted()).ToList();
|
||||
|
||||
await JSRuntime.InvokeVoidAsync("console.log", $"Loaded {_activeEnvelopes.Count()} active and {_completedEnvelopes.Count()} completed envelopes");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_errorMessage = ex.Message;
|
||||
await JSRuntime.InvokeVoidAsync("console.error", "Fehler beim Laden der Umschläge:", ex.ToString());
|
||||
}
|
||||
finally
|
||||
{
|
||||
@@ -390,20 +403,19 @@
|
||||
{
|
||||
if (_selectedEnvelope == null) return;
|
||||
// TODO: Navigate to envelope editor
|
||||
JSRuntime.InvokeVoidAsync("console.log", $"Edit envelope {_selectedEnvelope.Id} clicked - not yet implemented");
|
||||
}
|
||||
|
||||
void DeleteEnvelope()
|
||||
{
|
||||
if (_selectedEnvelope == null) return;
|
||||
// TODO: Show delete confirmation dialog
|
||||
JSRuntime.InvokeVoidAsync("console.log", $"Delete envelope {_selectedEnvelope.Id} clicked - not yet implemented");
|
||||
}
|
||||
|
||||
async Task LogoutAsync()
|
||||
{
|
||||
_isLoggingOut = true;
|
||||
await InvokeAsync(StateHasChanged);
|
||||
UserPreferencesService.InvalidateCache();
|
||||
await AuthService.LogoutSenderAsync();
|
||||
Navigation.NavigateTo("/sender/login", forceLoad: true);
|
||||
}
|
||||
@@ -440,4 +452,45 @@
|
||||
{
|
||||
_selectedEnvelope = envelope as EnvelopeDto;
|
||||
}
|
||||
|
||||
// ── Grid Layout Persistence ───────────────────────────────────────────────
|
||||
// LayoutAutoLoading fires when the grid initializes — restore saved layout.
|
||||
// LayoutAutoSaving fires when the user changes column order/width/sort — persist it.
|
||||
// UserPreferencesService.GetAsync() uses the 1h in-memory cache → 0 HTTP on restore.
|
||||
// UserPreferencesService.SaveGridLayoutAsync() merges the single key → 1 PUT.
|
||||
|
||||
async Task OnActiveGridLayoutAutoLoading(GridPersistentLayoutEventArgs e)
|
||||
{
|
||||
// Use cached preferences only — avoid HTTP during grid initialization.
|
||||
// If cache is empty (LoadFromServerAsync failed), skip layout restore silently.
|
||||
var prefs = UserPreferencesService.GetCached();
|
||||
if (prefs is not null && prefs.GridLayouts.TryGetValue(GridKeyActive, out var json))
|
||||
e.Layout = JsonSerializer.Deserialize<GridPersistentLayout>(json);
|
||||
}
|
||||
|
||||
async Task OnActiveGridLayoutAutoSaving(GridPersistentLayoutEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
var json = JsonSerializer.Serialize(e.Layout);
|
||||
await UserPreferencesService.SaveGridLayoutAsync(GridKeyActive, json);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await JSRuntime.InvokeVoidAsync("console.warn", $"[Sender] Grid layout save failed: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
async Task OnCompletedGridLayoutAutoLoading(GridPersistentLayoutEventArgs e)
|
||||
{
|
||||
var prefs = UserPreferencesService.GetCached();
|
||||
if (prefs is not null && prefs.GridLayouts.TryGetValue(GridKeyCompleted, out var json))
|
||||
e.Layout = JsonSerializer.Deserialize<GridPersistentLayout>(json);
|
||||
}
|
||||
|
||||
async Task OnCompletedGridLayoutAutoSaving(GridPersistentLayoutEventArgs e)
|
||||
{
|
||||
var json = JsonSerializer.Serialize(e.Layout);
|
||||
await UserPreferencesService.SaveGridLayoutAsync(GridKeyCompleted, json);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user