Refactor signature input into popup modal
The signature input process has been refactored to use a `<DxPopup>` modal for better user experience. The `<canvas>` element for capturing the signature has been moved into the popup, which is dynamically displayed when the user interacts with the "Unterschrift hinzufügen" or "Unterschrift erneuern" button. Dynamic messages now provide clearer feedback based on whether a signature has been applied. Signature-related actions (renew, apply, close) have been consolidated into the popup's footer, decluttering the main interface. New properties (`SignaturePopupVisible`, `PopupValidationMessage`) and methods (`OpenSignaturePopupAsync`, `RenewSignatureAsync`, `CloseSignaturePopup`) have been added to manage the popup and its behavior. The `ApplySignatureAsync` method has been updated to handle popup-specific validation and close the popup after applying the signature. The `OnAfterRenderAsync` method has been removed, and signature pad initialization has been moved to `OpenSignaturePopupAsync`. The `ApplySignatureToReport` method has been removed, with its functionality integrated into `ApplySignatureAsync`. Minor layout adjustments and validation logic improvements have been made. The "Export Signed PDF" button is now disabled unless a signature has been applied.
This commit is contained in:
@@ -15,19 +15,47 @@
|
||||
<div class="card m-3">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Unterschrift</h5>
|
||||
<p class="card-text text-muted mb-2">Bitte fuegen Sie vor dem PDF-Export Ihre Unterschrift in das Feld unten ein.</p>
|
||||
<canvas id="receiver-signature-pad" width="420" height="150" class="border rounded bg-white w-100" style="max-width: 420px; touch-action: none;"></canvas>
|
||||
<p class="card-text text-muted mb-2">
|
||||
@if(SignatureApplied) {
|
||||
<span>Die Unterschrift wurde dem Bericht hinzugefuegt. Sie koennen die Unterschrift erneuern oder das signierte PDF exportieren.</span>
|
||||
} else {
|
||||
<span>Bitte fuegen Sie vor dem PDF-Export Ihre Unterschrift hinzu.</span>
|
||||
}
|
||||
</p>
|
||||
@if(!string.IsNullOrWhiteSpace(SignatureValidationMessage)) {
|
||||
<div class="text-danger mt-2">@SignatureValidationMessage</div>
|
||||
<div class="text-danger mb-2">@SignatureValidationMessage</div>
|
||||
}
|
||||
<div class="mt-3 d-flex gap-2 flex-wrap">
|
||||
<button class="btn btn-outline-secondary" @onclick="ClearSignatureAsync">Unterschrift loeschen</button>
|
||||
<button class="btn btn-primary" @onclick="ApplySignatureAsync">Unterschrift zum Bericht hinzufuegen</button>
|
||||
<div class="d-flex gap-2 flex-wrap">
|
||||
<button class="btn btn-primary" @onclick="OpenSignaturePopupAsync">
|
||||
@(SignatureApplied ? "Unterschrift erneuern" : "Unterschrift hinzufuegen")
|
||||
</button>
|
||||
<button class="btn btn-success" disabled="@(!SignatureApplied)" @onclick="ExportSignedPdfAsync">Signiertes PDF exportieren</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<DxPopup @bind-Visible="SignaturePopupVisible"
|
||||
HeaderText="Unterschrift erfassen"
|
||||
Width="520px"
|
||||
ShowFooter="true"
|
||||
CloseOnEscape="true"
|
||||
CloseOnOutsideClick="false">
|
||||
<BodyContentTemplate>
|
||||
<p class="text-muted mb-2">Bitte unterschreiben Sie im folgenden Feld.</p>
|
||||
<canvas id="receiver-signature-pad" width="420" height="150" class="border rounded bg-white w-100" style="max-width: 420px; touch-action: none;"></canvas>
|
||||
@if(!string.IsNullOrWhiteSpace(PopupValidationMessage)) {
|
||||
<div class="text-danger mt-2">@PopupValidationMessage</div>
|
||||
}
|
||||
</BodyContentTemplate>
|
||||
<FooterContentTemplate>
|
||||
<div class="d-flex gap-2 flex-wrap justify-content-end w-100">
|
||||
<button class="btn btn-outline-secondary" @onclick="RenewSignatureAsync">Unterschrift erneuern</button>
|
||||
<button class="btn btn-primary" @onclick="ApplySignatureAsync">Zum Bericht hinzufuegen</button>
|
||||
<button class="btn btn-secondary" @onclick="CloseSignaturePopup">Schliessen</button>
|
||||
</div>
|
||||
</FooterContentTemplate>
|
||||
</DxPopup>
|
||||
|
||||
@if(Report is not null) {
|
||||
<DxReportViewer @key="ViewerKey" @ref="reportViewer" Report="Report" RootCssClasses="w-100 h-100" />
|
||||
}
|
||||
@@ -36,7 +64,9 @@
|
||||
DxReportViewer reportViewer;
|
||||
XtraReport? Report;
|
||||
bool SignatureApplied;
|
||||
bool SignaturePopupVisible;
|
||||
string? SignatureValidationMessage;
|
||||
string? PopupValidationMessage;
|
||||
int ViewerKey;
|
||||
|
||||
protected override async Task OnInitializedAsync() {
|
||||
@@ -45,31 +75,38 @@
|
||||
await Task.CompletedTask;
|
||||
}
|
||||
|
||||
protected override async Task OnAfterRenderAsync(bool firstRender) {
|
||||
if(firstRender)
|
||||
await JSRuntime.InvokeVoidAsync("receiverSignature.initialize", "receiver-signature-pad");
|
||||
async Task OpenSignaturePopupAsync() {
|
||||
SignaturePopupVisible = true;
|
||||
SignatureValidationMessage = null;
|
||||
PopupValidationMessage = null;
|
||||
await InvokeAsync(StateHasChanged);
|
||||
await Task.Delay(50);
|
||||
await JSRuntime.InvokeVoidAsync("receiverSignature.initialize", "receiver-signature-pad");
|
||||
}
|
||||
|
||||
async Task ClearSignatureAsync() {
|
||||
async Task RenewSignatureAsync() {
|
||||
PopupValidationMessage = null;
|
||||
await JSRuntime.InvokeVoidAsync("receiverSignature.clear", "receiver-signature-pad");
|
||||
SignatureApplied = false;
|
||||
SignatureValidationMessage = null;
|
||||
Report = CreateReportInstance();
|
||||
ViewerKey++;
|
||||
}
|
||||
|
||||
void CloseSignaturePopup() {
|
||||
PopupValidationMessage = null;
|
||||
SignaturePopupVisible = false;
|
||||
}
|
||||
|
||||
async Task ApplySignatureAsync() {
|
||||
var signatureDataUrl = await JSRuntime.InvokeAsync<string?>("receiverSignature.getDataUrl", "receiver-signature-pad");
|
||||
|
||||
if(string.IsNullOrWhiteSpace(signatureDataUrl)) {
|
||||
SignatureApplied = false;
|
||||
SignatureValidationMessage = "Die Unterschrift ist fuer den PDF-Export erforderlich.";
|
||||
PopupValidationMessage = "Die Unterschrift ist fuer den PDF-Export erforderlich.";
|
||||
return;
|
||||
}
|
||||
|
||||
PopupValidationMessage = null;
|
||||
SignatureValidationMessage = null;
|
||||
Report = CreateSignedReportInstance(signatureDataUrl);
|
||||
SignatureApplied = true;
|
||||
SignaturePopupVisible = false;
|
||||
ViewerKey++;
|
||||
}
|
||||
|
||||
@@ -94,14 +131,6 @@
|
||||
return report;
|
||||
}
|
||||
|
||||
void ApplySignatureToReport(string signatureDataUrl) {
|
||||
Report ??= ReportStorage.TryGetReport("LargeDatasetReport", out var savedReport)
|
||||
? savedReport
|
||||
: PredefinedReports.ReportsFactory.GetReport("LargeDatasetReport");
|
||||
|
||||
AddSignature(Report, signatureDataUrl);
|
||||
}
|
||||
|
||||
static void AddSignature(XtraReport report, string signatureDataUrl) {
|
||||
var imageBytes = Convert.FromBase64String(signatureDataUrl[(signatureDataUrl.IndexOf(',') + 1)..]);
|
||||
using var imageStream = new MemoryStream(imageBytes);
|
||||
|
||||
Reference in New Issue
Block a user