diff --git a/EnvelopeGenerator.ReceiverUI/Pages/EnvelopeViewer.razor b/EnvelopeGenerator.ReceiverUI/Pages/EnvelopeViewer.razor index 38df32f6..e4390286 100644 --- a/EnvelopeGenerator.ReceiverUI/Pages/EnvelopeViewer.razor +++ b/EnvelopeGenerator.ReceiverUI/Pages/EnvelopeViewer.razor @@ -5,6 +5,7 @@ @using Microsoft.Extensions.Options @using EnvelopeGenerator.ReceiverUI.Options @using Microsoft.JSInterop +@using DevExpress.Blazor @inject DocumentService DocumentService @inject NavigationManager Navigation @inject IOptions AppOptions @@ -18,6 +19,7 @@ +
@@ -177,7 +179,169 @@
+ + + + + @if(_activeSignatureTab == SignatureTabDraw) { +

Bitte unterschreiben Sie im folgenden Feld.

+ + } else if(_activeSignatureTab == SignatureTabText) { +

Geben Sie Ihre Unterschrift als Text ein und wählen Sie eine Schriftart.

+
+
+ +
+
+ +
+
+ + } else { +

Laden Sie ein Bild Ihrer Unterschrift hoch.

+ + + } + +
+
+
+ + +
+
+ + +
+
+ + +
+
+
+ + @if(!string.IsNullOrWhiteSpace(_popupValidationMessage)) { +
+ @_popupValidationMessage +
+ } +
+ +
+ + +
+
+
+ @code { +// Signature tab constants +const string SignatureTabDraw = "draw"; +const string SignatureTabText = "text"; +const string SignatureTabImage = "image"; +const string DrawCanvasId = "envelope-signature-pad"; +const string TypedCanvasId = "envelope-typed-signature-pad"; +const string ImageInputId = "envelope-signature-image-input"; +const string ImageCanvasId = "envelope-image-signature-pad"; + +readonly (string Text, string Value)[] TypedSignatureFonts = { + ("Brush Script", "'Brush Script MT', cursive"), + ("Segoe Script", "'Segoe Script', cursive"), + ("Lucida Handwriting", "'Lucida Handwriting', cursive"), + ("Comic Sans", "'Comic Sans MS', cursive"), + ("Cursive", "cursive") +}; + [Parameter] public string? EnvelopeKey { get; set; } bool _isLoading = true; @@ -191,6 +355,18 @@ bool _showThumbnails = true; DotNetObjectReference? _dotNetRef; IReadOnlyList _signatures = []; +// Signature state +record SignatureCapture(string DataUrl, string FullName, string Position, string Place); +SignatureCapture? _capturedSignature; +bool _signaturePopupVisible = false; +string? _popupValidationMessage; +string _activeSignatureTab = SignatureTabDraw; +string _typedSignatureText = string.Empty; +string _typedSignatureFont = "'Brush Script MT', cursive"; +string _signerFullName = string.Empty; +string _signerPosition = string.Empty; +string _signaturePlace = string.Empty; + // Resizable splitter state int _thumbnailWidth = 260; bool _isResizing = false; @@ -221,6 +397,11 @@ const int MaxThumbnailWidth = 400; await JSRuntime.InvokeVoidAsync("console.log", "Loaded signatures:", _signatures); + // Open signature popup on page load + _activeSignatureTab = SignatureTabDraw; + _signaturePopupVisible = true; + _popupValidationMessage = null; + } catch (Exception ex) { _errorMessage = $"Fehler: {ex.Message}"; } @@ -386,7 +567,100 @@ const int MaxThumbnailWidth = 400; [JSInvokable] public void OnSignatureButtonClick(int signatureId) { - Console.WriteLine($"Signature #{signatureId} signed"); + Console.WriteLine($"Signature #{signatureId} clicked"); + OpenSignaturePopup(); + } + + // Signature popup methods + void OpenSignaturePopup() { + _activeSignatureTab = SignatureTabDraw; + _signaturePopupVisible = true; + _popupValidationMessage = null; + } + + async Task OnPopupShownAsync() { + await InitializeActiveSignatureTabAsync(); + } + + async Task SetSignatureTabAsync(string tab) { + _activeSignatureTab = tab; + _popupValidationMessage = null; + await InvokeAsync(StateHasChanged); + await Task.Delay(50); + await InitializeActiveSignatureTabAsync(); + } + + async Task InitializeActiveSignatureTabAsync() { + if(_activeSignatureTab == SignatureTabDraw) { + await JSRuntime.InvokeVoidAsync("receiverSignature.initialize", DrawCanvasId); + } else if(_activeSignatureTab == SignatureTabText) { + await JSRuntime.InvokeVoidAsync("receiverSignature.initializeTyped", TypedCanvasId); + await RenderTypedSignatureAsync(); + } else { + await JSRuntime.InvokeVoidAsync("receiverSignature.initializeImage", ImageInputId, ImageCanvasId); + } + } + + async Task RenewSignatureAsync() { + _popupValidationMessage = null; + + if(_activeSignatureTab == SignatureTabDraw) { + await JSRuntime.InvokeVoidAsync("receiverSignature.clear", DrawCanvasId); + } else if(_activeSignatureTab == SignatureTabText) { + _typedSignatureText = string.Empty; + await JSRuntime.InvokeVoidAsync("receiverSignature.clearTyped", TypedCanvasId); + } else { + await JSRuntime.InvokeVoidAsync("receiverSignature.clearImage", ImageInputId, ImageCanvasId); + } + } + + async Task OnTypedSignatureChanged(Microsoft.AspNetCore.Components.ChangeEventArgs args) { + _typedSignatureText = args.Value?.ToString() ?? string.Empty; + await RenderTypedSignatureAsync(); + } + + async Task OnTypedSignatureFontChanged(Microsoft.AspNetCore.Components.ChangeEventArgs args) { + _typedSignatureFont = args.Value?.ToString() ?? _typedSignatureFont; + await RenderTypedSignatureAsync(); + } + + async Task RenderTypedSignatureAsync() { + await JSRuntime.InvokeVoidAsync("receiverSignature.renderTypedSignature", TypedCanvasId, _typedSignatureText, _typedSignatureFont); + } + + async Task SaveSignatureAsync() { + if (string.IsNullOrWhiteSpace(_signerFullName)) { + _popupValidationMessage = "Bitte geben Sie Vor- und Nachname ein."; + return; + } + if (string.IsNullOrWhiteSpace(_signaturePlace)) { + _popupValidationMessage = "Bitte geben Sie den Ort ein."; + return; + } + var signatureDataUrl = await GetActiveSignatureDataUrlAsync(); + if (string.IsNullOrWhiteSpace(signatureDataUrl)) { + _popupValidationMessage = "Die Unterschrift ist erforderlich."; + return; + } + + _popupValidationMessage = null; + _capturedSignature = new(signatureDataUrl, _signerFullName.Trim(), _signerPosition.Trim(), _signaturePlace.Trim()); + _signaturePopupVisible = false; + + await InvokeAsync(StateHasChanged); + Console.WriteLine($"Signature saved: {_signerFullName}, {_signaturePlace}"); + } + + async Task GetActiveSignatureDataUrlAsync() { + if(_activeSignatureTab == SignatureTabDraw) + return await JSRuntime.InvokeAsync("receiverSignature.getDataUrl", DrawCanvasId); + + if(_activeSignatureTab == SignatureTabText) { + await RenderTypedSignatureAsync(); + return await JSRuntime.InvokeAsync("receiverSignature.getTypedDataUrl", TypedCanvasId); + } + + return await JSRuntime.InvokeAsync("receiverSignature.getImageDataUrl", ImageCanvasId); } async Task RenderThumbnailsAsync() {