From bfd1a9d060fd3abc2baa976e4dcf5847b20d5678 Mon Sep 17 00:00:00 2001 From: TekH Date: Thu, 25 Jun 2026 13:22:09 +0200 Subject: [PATCH] Enhance EnvelopeSenderPage with new layout and features Redesigned `EnvelopeSenderPage.razor` to include a structured dashboard layout with a sender action bar and dynamic content area. Added authorization enforcement with the `@attribute` directive and dependency injection for services like `EnvelopeService` and `AuthService`. Introduced a tabbed interface for managing "Active" and "Completed" envelopes, with a `DxGrid` component for displaying envelope details. Added support for filtering, searching, and row selection, along with detailed row templates for receiver information. Implemented methods for loading, refreshing, creating, editing, and deleting envelopes, as well as logging out. Enhanced error handling and state management, and added console logging for debugging. Integrated external stylesheets for improved UI. --- .../Pages/EnvelopeSenderPage.razor | 441 +++++++++++++++++- 1 file changed, 437 insertions(+), 4 deletions(-) diff --git a/EnvelopeGenerator.Server/EnvelopeGenerator.Server.Client/Pages/EnvelopeSenderPage.razor b/EnvelopeGenerator.Server/EnvelopeGenerator.Server.Client/Pages/EnvelopeSenderPage.razor index 77316281..e1117038 100644 --- a/EnvelopeGenerator.Server/EnvelopeGenerator.Server.Client/Pages/EnvelopeSenderPage.razor +++ b/EnvelopeGenerator.Server/EnvelopeGenerator.Server.Client/Pages/EnvelopeSenderPage.razor @@ -1,8 +1,441 @@ -@page "/sender" -@rendermode InteractiveWebAssembly +@page "/sender" +@attribute [Microsoft.AspNetCore.Authorization.Authorize(Policy = "Sender")] -

EnvelopeSender

+@using System.Text.Json +@using EnvelopeGenerator.Server.Client.Models +@using DevExpress.Blazor +@using EnvelopeGenerator.Server.Client.Services +@inject EnvelopeGenerator.Server.Client.Services.EnvelopeService EnvelopeService +@inject EnvelopeGenerator.Server.Client.Services.AuthService AuthService +@inject NavigationManager Navigation +@inject IJSRuntime JSRuntime +@inject AppVersionService AppVersion + + + + + +
+
+
+
+ +
Umschlag-Übersicht
+
+ +
+ + + + + + + + + +
+
+
+ +
+ @if (_isLoading && _allEnvelopes == null) { +
+
+
+ Lädt... +
+

Umschläge werden geladen...

+
+
+ } else if (_errorMessage != null) { +
+
+
+ + + + +
+
Fehler beim Laden der Umschläge
+

@_errorMessage

+
+
+
+
+ } else { +
+
+ + +
+ +
+ @if (_activeTab == "active") { + + + + + @((cellContext.DataItem as EnvelopeDto)?.Id) + + + + + @((cellContext.DataItem as EnvelopeDto)?.Title) + + + + + @{ + var envelope = cellContext.DataItem as EnvelopeDto; + if (envelope != null) { + var statusInfo = GetStatusInfo(envelope.Status); +
+ + @statusInfo.Label +
+ } + } +
+
+ + + @{ + var envelope = cellContext.DataItem as EnvelopeDto; + if (envelope != null) { + var receivers = envelope.EnvelopeReceivers ?? new List(); + var signed = receivers.Count(r => r.Signed); + var total = receivers.Count; +
+ + @signed / @total unterschrieben + + @if (total > 0) { +
+
+
+ } +
+ } + } +
+
+
+ +
+
Empfänger
+ @{ + var envelope = detailContext.DataItem as EnvelopeDto; + if (envelope?.EnvelopeReceivers?.Any() == true) { +
+ @foreach (var receiver in envelope.EnvelopeReceivers) { +
+ + @if (receiver.Signed) { + + + + Unterschrieben + } else { + + + + + Ausstehend + } + +
+ @receiver.Name + @receiver.Email +
+
+ } +
+ } else { +

Keine Empfänger

+ } + } +
+
+
+ } else { + + + + + @((cellContext.DataItem as EnvelopeDto)?.Id) + + + + + @((cellContext.DataItem as EnvelopeDto)?.Title) + + + + + @{ + var envelope = cellContext.DataItem as EnvelopeDto; + if (envelope != null) { + var statusInfo = GetStatusInfo(envelope.Status); +
+ + @statusInfo.Label +
+ } + } +
+
+ + + @{ + var envelope = cellContext.DataItem as EnvelopeDto; + if (envelope != null) { + var receivers = envelope.EnvelopeReceivers ?? new List(); + var signed = receivers.Count(r => r.Signed); + var total = receivers.Count; +
+ + @signed / @total unterschrieben + + @if (total > 0) { +
+
+
+ } +
+ } + } +
+
+
+ +
+
Empfänger
+ @{ + var envelope = detailContext.DataItem as EnvelopeDto; + if (envelope?.EnvelopeReceivers?.Any() == true) { +
+ @foreach (var receiver in envelope.EnvelopeReceivers) { +
+ + @if (receiver.Signed) { + + + + Unterschrieben + } else { + + + + + Ausstehend + } + +
+ @receiver.Name + @receiver.Email +
+
+ } +
+ } else { +

Keine Empfänger

+ } + } +
+
+
+ } +
+
+ } +
+
@code { + private IEnumerable? _allEnvelopes; + private IEnumerable? _activeEnvelopes; + private IEnumerable? _completedEnvelopes; + private EnvelopeDto? _selectedEnvelope; + private string _activeTab = "active"; + private bool _isLoading = true; + private bool _isLoggingOut = false; + private string? _errorMessage; + private DxGrid? _gridActive; + private DxGrid? _gridCompleted; -} + protected override async Task OnInitializedAsync() + { + var hasAccess = await AuthService.CheckSenderAsync(); + if (!hasAccess) + { + Navigation.NavigateTo($"/sender/login"); + return; + } + + await LoadEnvelopesAsync(); + } + + async Task LoadEnvelopesAsync() + { + _isLoading = true; + _errorMessage = null; + await InvokeAsync(StateHasChanged); + + try + { + _allEnvelopes = await EnvelopeService.GetAsync() ?? []; + + // Split into active and completed based on status + 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 + { + _isLoading = false; + await InvokeAsync(StateHasChanged); + } + } + + async Task RefreshEnvelopes() + { + await LoadEnvelopesAsync(); + } + + void CreateEnvelope() + { + // TODO: Navigate to envelope creation page + JSRuntime.InvokeVoidAsync("console.log", "Create envelope clicked - not yet implemented"); + } + + void EditEnvelope() + { + 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); + await AuthService.LogoutSenderAsync(); + Navigation.NavigateTo("/sender/login", forceLoad: true); + } + + bool IsEnvelopeSent(EnvelopeDto envelope) + { + var status = (EnvelopeStatus)envelope.Status; + return status >= EnvelopeStatus.EnvelopeQueued; + } + + (string Label, string CssClass, string DotColor) GetStatusInfo(int statusCode) + { + var status = (EnvelopeStatus)statusCode; + return status switch + { + EnvelopeStatus.EnvelopePartlySigned => ("Teilweise unterschrieben", "partly-signed", "green"), + EnvelopeStatus.EnvelopeQueued => ("In Warteschlange", "queued", "orange"), + EnvelopeStatus.EnvelopeSent => ("Gesendet", "sent", "orange"), + EnvelopeStatus.EnvelopeCompletelySigned => ("Vollständig unterschrieben", "completed", "green"), + EnvelopeStatus.EnvelopeDeleted => ("Gelöscht", "deleted", "red"), + EnvelopeStatus.EnvelopeRejected => ("Abgelehnt", "rejected", "red"), + EnvelopeStatus.EnvelopeWithdrawn => ("Zurückgezogen", "withdrawn", "red"), + EnvelopeStatus.EnvelopeCreated => ("Erstellt", "created", "blue"), + EnvelopeStatus.EnvelopeSaved => ("Gespeichert", "saved", "blue"), + _ => ("Unbekannt", "unknown", "blue") + }; + } + + void OnCustomizeElement(GridCustomizeElementEventArgs e) + { + // Future: Add custom row coloring based on status if needed + } + + void OnSelectedEnvelopeChanged(object envelope) + { + _selectedEnvelope = envelope as EnvelopeDto; + } +} \ No newline at end of file