diff --git a/EnvelopeGenerator.Server/EnvelopeGenerator.Server.Client/Pages/EnvelopeSenderPage.razor b/EnvelopeGenerator.Server/EnvelopeGenerator.Server.Client/Pages/EnvelopeSenderPage.razor index 3ee63ef5..78227ff6 100644 --- a/EnvelopeGenerator.Server/EnvelopeGenerator.Server.Client/Pages/EnvelopeSenderPage.razor +++ b/EnvelopeGenerator.Server/EnvelopeGenerator.Server.Client/Pages/EnvelopeSenderPage.razor @@ -34,7 +34,7 @@ else { - + } @@ -60,43 +60,47 @@
@@ -105,7 +109,8 @@
- @if (_isLoading && _allEnvelopes == null) { + @if (_isLoading && _allEnvelopes == null) + {
@@ -114,13 +119,15 @@

Umschläge werden geladen...

- } else if (_errorMessage != null) { + } + else if (_errorMessage != null) + {
- - + +
Fehler beim Laden der Umschläge
@@ -129,18 +136,22 @@
- } else { + } + else + {
@@ -151,12 +162,13 @@ @* Grid persistence hint — informs users their layout is auto-saved *@
- - + + Die Größe und Position der Spalten wird automatisch für Sie gespeichert.
- @if (_activeTab == "active") { + @if (_activeTab == "active") + { @{ var envelope = cellContext.DataItem as EnvelopeDto; - if (envelope != null) { + if (envelope != null) + { var statusInfo = GetStatusInfo(envelope.Status);
@@ -203,7 +216,8 @@ @{ var envelope = cellContext.DataItem as EnvelopeDto; - if (envelope != null) { + if (envelope != null) + { var receivers = envelope.EnvelopeReceivers?.ToList() ?? []; var signed = receivers.Count(r => r.Signed); var total = receivers.Count; @@ -211,7 +225,8 @@ @signed / @total unterschrieben - @if (total > 0) { + @if (total > 0) + {
@@ -219,7 +234,7 @@
} } - + @@ -233,20 +248,25 @@
Empfänger
@{ var envelope = detailContext.DataItem as EnvelopeDto; - if (envelope?.EnvelopeReceivers?.Any() == true) { + if (envelope?.EnvelopeReceivers?.Any() == true) + {
- @foreach (var receiver in envelope.EnvelopeReceivers) { + @foreach (var receiver in envelope.EnvelopeReceivers) + {
- @if (receiver.Signed) { + @if (receiver.Signed) + { - + Unterschrieben - } else { + } + else + { - - + + Ausstehend } @@ -258,14 +278,18 @@
}
- } else { + } + else + {

Keine Empfänger

} }
- } else { + } + else + { @{ var envelope = cellContext.DataItem as EnvelopeDto; - if (envelope != null) { + if (envelope != null) + { var statusInfo = GetStatusInfo(envelope.Status);
@@ -309,7 +334,8 @@ @{ var envelope = cellContext.DataItem as EnvelopeDto; - if (envelope != null) { + if (envelope != null) + { var receivers = envelope.EnvelopeReceivers?.ToList() ?? []; var signed = receivers.Count(r => r.Signed); var total = receivers.Count; @@ -317,7 +343,8 @@ @signed / @total unterschrieben - @if (total > 0) { + @if (total > 0) + {
@@ -339,20 +366,25 @@
Empfänger
@{ var envelope = detailContext.DataItem as EnvelopeDto; - if (envelope?.EnvelopeReceivers?.Any() == true) { + if (envelope?.EnvelopeReceivers?.Any() == true) + {
- @foreach (var receiver in envelope.EnvelopeReceivers) { + @foreach (var receiver in envelope.EnvelopeReceivers) + {
- @if (receiver.Signed) { + @if (receiver.Signed) + { - + Unterschrieben - } else { + } + else + { - - + + Ausstehend } @@ -364,7 +396,9 @@
}
- } else { + } + else + {

Keine Empfänger

} } @@ -395,7 +429,7 @@ private EnvelopeGenerator.Server.Client.Services.CustomImageDto? _companyLogo; // Stable keys used to store/restore each grid's layout in UserPreferences.GridLayouts - private const string GridKeyActive = "sender.active-envelopes"; + private const string GridKeyActive = "sender.active-envelopes"; private const string GridKeyCompleted = "sender.completed-envelopes"; protected override async Task OnInitializedAsync() @@ -415,7 +449,7 @@ // Load logo config — authenticated, so this should succeed var logos = await CustomImagesService.GetAsync(); - _appLogo = logos.App; + _appLogo = logos.App; _companyLogo = logos.Company; await LoadEnvelopesAsync(); @@ -430,7 +464,7 @@ 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(); diff --git a/EnvelopeGenerator.Server/EnvelopeGenerator.Server/Components/App.razor b/EnvelopeGenerator.Server/EnvelopeGenerator.Server/Components/App.razor index 4c61b9f4..b43f7aa6 100644 --- a/EnvelopeGenerator.Server/EnvelopeGenerator.Server/Components/App.razor +++ b/EnvelopeGenerator.Server/EnvelopeGenerator.Server/Components/App.razor @@ -30,31 +30,13 @@ - -
-
-
-
-
- + - diff --git a/EnvelopeGenerator.Server/EnvelopeGenerator.Server/Components/Pages/EnvelopeSenderEditorPage.razor b/EnvelopeGenerator.Server/EnvelopeGenerator.Server/Components/Pages/EnvelopeSenderEditorPage.razor index eb4bf201..b163b89f 100644 --- a/EnvelopeGenerator.Server/EnvelopeGenerator.Server/Components/Pages/EnvelopeSenderEditorPage.razor +++ b/EnvelopeGenerator.Server/EnvelopeGenerator.Server/Components/Pages/EnvelopeSenderEditorPage.razor @@ -81,8 +81,8 @@ @if (_signatureFields.Count > 0) { + background: #ede9fe; border-radius: 0.25rem; color: #6d28d9; + font-weight: 500; font-size: 0.7rem; white-space: nowrap;"> @_signatureFields.Count Signaturfeld@(_signatureFields.Count != 1 ? "er" : "") } @@ -118,8 +118,8 @@
@foreach (var receiver in _receivers) { -
+
@receiver.FullName
@@ -130,7 +130,7 @@
} @@ -436,7 +436,7 @@ // ── Constants ── // Signature field size in PDF points (fixed): 1.77" × 1.96" - const double SigWidthPt = 1.77 * 72; // 127.44 pt + const double SigWidthPt = 1.77 * 72; // 127.44 pt const double SigHeightPt = 1.96 * 72; // 141.12 pt // CssClass for DxPdfViewer — used by JS to locate page elements @@ -447,8 +447,8 @@ // ── State ── DxPdfViewer? _pdfViewer; - bool _pdfLoaded = false; - string _fileName = string.Empty; + bool _pdfLoaded = false; + string _fileName = string.Empty; string? _errorMessage; byte[]? _pdfBytes; // Current rendered PDF (original + placeholders burned in) byte[]? _originalPdfBytes; // Pristine upload — never modified, used as base for redraw @@ -457,25 +457,25 @@ ReceiverDraft? _pendingReceiverForPlacement; // Set when user clicks "Signatur hinzufügen" // ── Save state ── - bool _isSaving = false; - bool _savePopupVisible = false; - string? _saveErrorMessage = null; + bool _isSaving = false; + bool _savePopupVisible = false; + string? _saveErrorMessage = null; // ── Envelope metadata ── - string _envelopeTitle = string.Empty; + string _envelopeTitle = string.Empty; string _envelopeMessage = string.Empty; - bool _titleTouched = false; + bool _titleTouched = false; List _receivers = []; - bool _receiverPopupVisible; - string _receiverDraftName = string.Empty; - string _receiverDraftEmail = string.Empty; + bool _receiverPopupVisible; + string _receiverDraftName = string.Empty; + string _receiverDraftEmail = string.Empty; string _receiverDraftPhoneNumber = string.Empty; string? _selectedReceiverEmailSuggestion; string? _receiverPopupValidationMessage; - bool _isReceiverEmailSearchRunning; + bool _isReceiverEmailSearchRunning; List _receiverEmailSuggestions = []; - int _receiverEmailSearchVersion; + int _receiverEmailSearchVersion; static readonly System.ComponentModel.DataAnnotations.EmailAddressAttribute ReceiverEmailValidator = new(); @@ -512,12 +512,12 @@ && cached is not null) { _originalPdfBytes = cached.OriginalPdfBytes; - _signatureFields = cached.Fields; - _fileName = cached.FileName; - _pdfLoaded = _originalPdfBytes is { Length: > 0 }; - _receivers = cached.Receivers; - _envelopeTitle = cached.Title; - _envelopeMessage = cached.Message; + _signatureFields = cached.Fields; + _fileName = cached.FileName; + _pdfLoaded = _originalPdfBytes is { Length: > 0 }; + _receivers = cached.Receivers; + _envelopeTitle = cached.Title; + _envelopeMessage = cached.Message; // Redraw placeholders onto the original PDF if (_pdfLoaded) @@ -545,8 +545,8 @@ await file.OpenReadStream(maxBytes).CopyToAsync(ms); _originalPdfBytes = ms.ToArray(); - _fileName = file.Name; - _pdfLoaded = true; + _fileName = file.Name; + _pdfLoaded = true; _signatureFields.Clear(); _pendingReceiverForPlacement = null; @@ -597,12 +597,12 @@ double pageHeightPt; try { - using var ms = new System.IO.MemoryStream(_originalPdfBytes); - var doc = PdfSharp.Pdf.IO.PdfReader.Open(ms, PdfSharp.Pdf.IO.PdfDocumentOpenMode.Import); + using var ms = new System.IO.MemoryStream(_originalPdfBytes); + var doc = PdfSharp.Pdf.IO.PdfReader.Open(ms, PdfSharp.Pdf.IO.PdfDocumentOpenMode.Import); int pageIndex = Math.Max(0, Math.Min(coords.PageIndex, doc.PageCount - 1)); - var page = doc.Pages[pageIndex]; - pageWidthPt = page.Width.Point; - pageHeightPt = page.Height.Point; + var page = doc.Pages[pageIndex]; + pageWidthPt = page.Width.Point; + pageHeightPt = page.Height.Point; } catch (Exception ex) { @@ -614,17 +614,17 @@ double xPt = coords.NormX * pageWidthPt; double yPt = coords.NormY * pageHeightPt; - xPt = Math.Max(0, Math.Min(xPt, pageWidthPt - SigWidthPt)); + xPt = Math.Max(0, Math.Min(xPt, pageWidthPt - SigWidthPt)); yPt = Math.Max(0, Math.Min(yPt, pageHeightPt - SigHeightPt)); int page1Based = coords.PageIndex + 1; var field = new SignatureFieldDraft( - XPt: xPt, - YPt: yPt, - Page: page1Based, + XPt: xPt, + YPt: yPt, + Page: page1Based, ReceiverName: _pendingReceiverForPlacement.FullName, - Color: _pendingReceiverForPlacement.Color); + Color: _pendingReceiverForPlacement.Color); _signatureFields.Add(field); _pendingReceiverForPlacement = null; @@ -711,7 +711,7 @@ string.Join(", ", receiversWithoutField.Select(r => r.FullName))); } - _isSaving = true; + _isSaving = true; _saveErrorMessage = null; await InvokeAsync(StateHasChanged); @@ -728,16 +728,16 @@ var fields = _signatureFields .Where(f => f.ReceiverName == receiver.FullName) .Select(f => new DocReceiverElementCreateDto( - X: f.XPt / 72.0, - Y: f.YPt / 72.0, + X: f.XPt / 72.0, + Y: f.YPt / 72.0, Page: f.Page)) .ToList(); return new ReceiverGetOrCreateCommand { - EmailAddress = receiver.Email, - Salution = receiver.FullName, - PhoneNumber = string.IsNullOrWhiteSpace(receiver.PhoneNumber) + EmailAddress = receiver.Email, + Salution = receiver.FullName, + PhoneNumber = string.IsNullOrWhiteSpace(receiver.PhoneNumber) ? null : receiver.PhoneNumber, DocReceiverElements = fields, @@ -746,13 +746,13 @@ var command = new CreateEnvelopeReceiverCommand { - Title = _envelopeTitle.Trim(), - Message = string.IsNullOrWhiteSpace(_envelopeMessage) + Title = _envelopeTitle.Trim(), + Message = string.IsNullOrWhiteSpace(_envelopeMessage) ? "Bitte unterzeichnen Sie das beigefügte Dokument." : _envelopeMessage.Trim(), TFAEnabled = false, - Document = new DocumentCreateCommand { DataAsBase64 = docBase64 }, - Receivers = receiversCmd, + Document = new DocumentCreateCommand { DataAsBase64 = docBase64 }, + Receivers = receiversCmd, }; var result = await EnvelopeReceiverService.CreateAsync(command); @@ -784,11 +784,11 @@ var data = new EditorSessionData( OriginalPdfBytes: _originalPdfBytes ?? [], - Fields: [.. _signatureFields], - FileName: _fileName, - Receivers: [.. _receivers], - Title: _envelopeTitle, - Message: _envelopeMessage); + Fields: [.. _signatureFields], + FileName: _fileName, + Receivers: [.. _receivers], + Title: _envelopeTitle, + Message: _envelopeMessage); MemoryCache.Set(SessionKey, data, SessionTtl); } @@ -798,7 +798,7 @@ { if (fields.Count == 0) return originalPdf; - using var inputMs = new System.IO.MemoryStream(originalPdf); + using var inputMs = new System.IO.MemoryStream(originalPdf); using var outputMs = new System.IO.MemoryStream(); var document = PdfSharp.Pdf.IO.PdfReader.Open( @@ -819,11 +819,11 @@ var nameBrush = new PdfSharp.Drawing.XSolidBrush(HexToXColor(field.Color, alpha: 230)); var fontLabel = new PdfSharp.Drawing.XFont("Arial", 9, PdfSharp.Drawing.XFontStyleEx.Bold); - var fontName = new PdfSharp.Drawing.XFont("Arial", 7, PdfSharp.Drawing.XFontStyleEx.Regular); + var fontName = new PdfSharp.Drawing.XFont("Arial", 7, PdfSharp.Drawing.XFontStyleEx.Regular); var fmtCenter = new PdfSharp.Drawing.XStringFormat { - Alignment = PdfSharp.Drawing.XStringAlignment.Center, + Alignment = PdfSharp.Drawing.XStringAlignment.Center, LineAlignment = PdfSharp.Drawing.XLineAlignment.Center, }; @@ -861,11 +861,11 @@ // ── Receiver popup ── void OpenAddReceiverPopup() { - _receiverDraftName = string.Empty; - _receiverDraftEmail = string.Empty; + _receiverDraftName = string.Empty; + _receiverDraftEmail = string.Empty; _receiverDraftPhoneNumber = string.Empty; _selectedReceiverEmailSuggestion = null; - _receiverPopupValidationMessage = null; + _receiverPopupValidationMessage = null; _receiverEmailSuggestions.Clear(); _receiverPopupVisible = true; } @@ -873,9 +873,9 @@ void CloseAddReceiverPopup() { _receiverPopupVisible = false; - _receiverPopupValidationMessage = null; + _receiverPopupValidationMessage = null; _selectedReceiverEmailSuggestion = null; - _isReceiverEmailSearchRunning = false; + _isReceiverEmailSearchRunning = false; } void OnReceiverNameChanged(string? value) @@ -947,7 +947,7 @@ { _receiverDraftEmail = value?.Trim() ?? string.Empty; _selectedReceiverEmailSuggestion = _receiverDraftEmail; - _receiverPopupValidationMessage = null; + _receiverPopupValidationMessage = null; var searchVersion = ++_receiverEmailSearchVersion; @@ -955,7 +955,7 @@ { _receiverEmailSuggestions.Clear(); _selectedReceiverEmailSuggestion = null; - _isReceiverEmailSearchRunning = false; + _isReceiverEmailSearchRunning = false; return; } @@ -994,8 +994,8 @@ Task SaveReceiverAsync() { - var fullName = _receiverDraftName.Trim(); - var email = _receiverDraftEmail.Trim(); + var fullName = _receiverDraftName.Trim(); + var email = _receiverDraftEmail.Trim(); var phoneNumber = _receiverDraftPhoneNumber.Trim(); if (string.IsNullOrWhiteSpace(fullName)) @@ -1034,12 +1034,12 @@ record ReceiverDraft(Guid Id, string FullName, string Email, string PhoneNumber, string Color); record EditorSessionData( - byte[] OriginalPdfBytes, + byte[] OriginalPdfBytes, List Fields, - string FileName, - List Receivers, - string Title, - string Message); + string FileName, + List Receivers, + string Title, + string Message); // ── Receiver colour palette (cycles when > 8 receivers) ── static readonly string[] ReceiverPalette = diff --git a/EnvelopeGenerator.Server/EnvelopeGenerator.Server/wwwroot/css/app.css b/EnvelopeGenerator.Server/EnvelopeGenerator.Server/wwwroot/css/app.css index 74741102..f67a5d5f 100644 --- a/EnvelopeGenerator.Server/EnvelopeGenerator.Server/wwwroot/css/app.css +++ b/EnvelopeGenerator.Server/EnvelopeGenerator.Server/wwwroot/css/app.css @@ -56,42 +56,6 @@ article { color: red; } -/* ── WASM Boot Loading Overlay ───────────────────────────────────────────── */ -/* Shown immediately on page load, removed once Blazor circuit connects. */ -/* Prevents white/unstyled flash while WASM boots (~1-2s on first load). */ - -#sf-boot-overlay { - position: fixed; - inset: 0; - z-index: 9999; - display: flex; - align-items: center; - justify-content: center; - background: linear-gradient(135deg, #1e3c72 0%, #2a5298 50%, #7e22ce 100%); - transition: opacity 0.25s ease; - pointer-events: none; /* don't block clicks once fading out */ -} - -.sf-boot-spinner { - display: flex; - flex-direction: column; - align-items: center; - gap: 1.25rem; -} - -.sf-boot-ring { - width: 44px; - height: 44px; - border: 3px solid rgba(255, 255, 255, 0.2); - border-top-color: rgba(255, 255, 255, 0.85); - border-radius: 50%; - animation: sf-boot-spin 0.8s linear infinite; -} - -@keyframes sf-boot-spin { - to { transform: rotate(360deg); } -} - #blazor-error-ui { background: lightyellow; bottom: 0;