Compare commits

...

7 Commits

Author SHA1 Message Date
33c52bcef8 Add signature panel and layout updates for ReportViewer
Enhanced `ReportViewer.razor` with a new layout structure:
- Added `receiver-page-layout` with `receiver-signature-panel` and `receiver-viewer-wrapper` for better organization.
- Introduced a button to export signed PDFs, conditionally enabled based on `SignatureApplied`.
- Added a `DxPopup` for capturing signatures with a "Close" button.

Updated `MainLayout.razor` to remove unnecessary padding from `<article>`.

Refined `app.css`:
- Defined styles for `receiver-page-layout`, `receiver-signature-panel`, and `receiver-viewer-wrapper` to improve layout flexibility.
- Adjusted `article` to use flexbox and ensure hidden overflow.
2026-05-28 23:37:20 +02:00
40c5e1d044 Update navigation and remove sidebar in MainLayout
Updated the `OnAfterRenderAsync` method in `Index.razor` to navigate to `/receiver` instead of `/reportviewer`. Removed the sidebar containing the `<NavMenu />` component in `MainLayout.razor` and adjusted the `<main>` tag to directly contain the content.
2026-05-28 23:36:22 +02:00
533d646211 Update routes and navigation links for sender/receiver UI
Updated the `@page` directives in `ReportDesigner.razor` and
`ReportViewer.razor` to change routes from `/reportdesigner`
to `/sender` and `/reportviewer` to `/receiver`, respectively.

Modified `NavMenu.razor` to update navigation links to reflect
the new routes. Updated the displayed text for the links to
"Empfänger-UI" (Receiver UI) and "Umschlag-UI" (Envelope UI).
2026-05-28 20:17:42 +02:00
7aa08cf8e9 Enable Wasm native build and refactor signature layout
Updated EnvelopeGenerator.ReceiverUI.csproj to enable native WebAssembly builds and load all globalization data for improved localization support.

Refactored ReportViewer.razor to enhance layout calculations for the signature section:
- Introduced constants for better readability and maintainability.
- Dynamically adjusted band height and padding to fit content without overlap.
- Updated control positioning and sizing using calculated values.
- Changed font style of the signature label to regular and reordered control additions for clarity.
2026-05-28 19:43:03 +02:00
4144d2abde Disable native Wasm build in ReceiverUI project
The `<WasmBuildNative>` property in the `EnvelopeGenerator.ReceiverUI.csproj` file was changed from `true` to `false`. This disables the native WebAssembly (Wasm) build, potentially simplifying the build process, reducing build time, or addressing compatibility issues.
2026-05-28 19:42:47 +02:00
2a8fed166b Adjust signature layout and bottom margin height
Increased the `bottomMargin` height from 140F to 175F to provide additional space. Updated the `signatureInformation` format to simplify text structure, remove redundant labels, and use a short date format.

Modified the `XRLabel` to enable multiline text, adjusted its height to 70F, and changed text alignment to `TopLeft`. Updated the `XRPictureBox` position by shifting its Y-coordinate to 80F for better alignment with the new layout.
2026-05-28 17:08:18 +02:00
60f01565da Add user input fields and enhance signature details
Added input fields for "Full Name," "Position," and "Place" in `ReportViewer.razor` to collect additional user details. Introduced validation for required fields ("Full Name" and "Place") in `ApplySignatureAsync`. Updated `CreateSignedReportInstance` and `AddSignature` to include these details in the signature label, which now dynamically displays full name, position (if provided), place, and date. Adjusted layout and bounds for proper alignment and spacing in the report.
2026-05-28 16:57:27 +02:00
6 changed files with 109 additions and 26 deletions

View File

@@ -35,6 +35,6 @@
return; return;
await Task.Delay(1200); await Task.Delay(1200);
NavigationManager.NavigateTo("/reportviewer"); NavigationManager.NavigateTo("/receiver");
} }
} }

View File

@@ -1,4 +1,4 @@
@page "/reportdesigner" @page "/sender"
@using DevExpress.DataAccess.Json; @using DevExpress.DataAccess.Json;
@using EnvelopeGenerator.ReceiverUI.Services; @using EnvelopeGenerator.ReceiverUI.Services;

View File

@@ -1,4 +1,4 @@
@page "/reportviewer/" @page "/receiver"
@using System.Drawing @using System.Drawing
@using DevExpress.Drawing @using DevExpress.Drawing
@using DevExpress.Utils @using DevExpress.Utils
@@ -17,6 +17,9 @@
<link href="_content/DevExpress.Blazor.Themes/blazing-berry.bs5.min.css" rel="stylesheet" /> <link href="_content/DevExpress.Blazor.Themes/blazing-berry.bs5.min.css" rel="stylesheet" />
<link href="_content/DevExpress.Blazor.Reporting.Viewer/css/dx-blazor-reporting-components.bs5.css" rel="stylesheet" /> <link href="_content/DevExpress.Blazor.Reporting.Viewer/css/dx-blazor-reporting-components.bs5.css" rel="stylesheet" />
<div class="receiver-page-layout">
<div class="receiver-signature-panel">
<div class="card m-3"> <div class="card m-3">
<div class="card-body"> <div class="card-body">
<h5 class="card-title">Unterschrift</h5> <h5 class="card-title">Unterschrift</h5>
@@ -38,6 +41,7 @@
</div> </div>
</div> </div>
</div> </div>
</div>
<DxPopup @bind-Visible="SignaturePopupVisible" <DxPopup @bind-Visible="SignaturePopupVisible"
HeaderText="Unterschrift erfassen" HeaderText="Unterschrift erfassen"
@@ -82,6 +86,25 @@
<canvas id="receiver-image-signature-pad" width="520" height="160" class="border rounded bg-white w-100" style="max-width: 520px;"></canvas> <canvas id="receiver-image-signature-pad" width="520" height="160" class="border rounded bg-white w-100" style="max-width: 520px;"></canvas>
} }
<div class="border-top mt-3 pt-3">
<p class="text-muted mb-2">Bitte geben Sie die folgenden Angaben ein. Das Datum wird automatisch hinzugefuegt.</p>
<div class="row g-2">
<div class="col-12 col-md-6">
<label class="form-label" for="receiver-signer-name">Vor- und Nachname *</label>
<input id="receiver-signer-name" class="form-control" value="@SignerFullName" @oninput="args => SignerFullName = args.Value?.ToString() ?? string.Empty" />
</div>
<div class="col-12 col-md-6">
<label class="form-label" for="receiver-signer-position">Position</label>
<input id="receiver-signer-position" class="form-control" value="@SignerPosition" @oninput="args => SignerPosition = args.Value?.ToString() ?? string.Empty" />
</div>
<div class="col-12 col-md-6">
<label class="form-label" for="receiver-signature-place">Ort *</label>
<input id="receiver-signature-place" class="form-control" value="@SignaturePlace" @oninput="args => SignaturePlace = args.Value?.ToString() ?? string.Empty" />
</div>
</div>
</div>
@if(!string.IsNullOrWhiteSpace(PopupValidationMessage)) { @if(!string.IsNullOrWhiteSpace(PopupValidationMessage)) {
<div class="text-danger mt-2">@PopupValidationMessage</div> <div class="text-danger mt-2">@PopupValidationMessage</div>
} }
@@ -95,9 +118,13 @@
</FooterContentTemplate> </FooterContentTemplate>
</DxPopup> </DxPopup>
<div class="receiver-viewer-wrapper">
@if(Report is not null) { @if(Report is not null) {
<DxReportViewer @key="ViewerKey" @ref="reportViewer" Report="Report" RootCssClasses="w-100 h-100" /> <DxReportViewer @key="ViewerKey" @ref="reportViewer" Report="Report" RootCssClasses="w-100 h-100" />
} }
</div>
</div>
@code { @code {
const string SignatureTabDraw = "draw"; const string SignatureTabDraw = "draw";
@@ -125,6 +152,9 @@
string ActiveSignatureTab = SignatureTabDraw; string ActiveSignatureTab = SignatureTabDraw;
string TypedSignatureText = string.Empty; string TypedSignatureText = string.Empty;
string TypedSignatureFont = "'Brush Script MT', cursive"; string TypedSignatureFont = "'Brush Script MT', cursive";
string SignerFullName = string.Empty;
string SignerPosition = string.Empty;
string SignaturePlace = string.Empty;
int ViewerKey; int ViewerKey;
protected override async Task OnInitializedAsync() { protected override async Task OnInitializedAsync() {
@@ -195,6 +225,16 @@
} }
async Task ApplySignatureAsync() { async Task ApplySignatureAsync() {
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(); var signatureDataUrl = await GetActiveSignatureDataUrlAsync();
if(string.IsNullOrWhiteSpace(signatureDataUrl)) { if(string.IsNullOrWhiteSpace(signatureDataUrl)) {
@@ -204,7 +244,7 @@
PopupValidationMessage = null; PopupValidationMessage = null;
SignatureValidationMessage = null; SignatureValidationMessage = null;
Report = CreateSignedReportInstance(signatureDataUrl); Report = CreateSignedReportInstance(signatureDataUrl, SignerFullName.Trim(), SignerPosition.Trim(), SignaturePlace.Trim());
SignatureApplied = true; SignatureApplied = true;
SignaturePopupVisible = false; SignaturePopupVisible = false;
ViewerKey++; ViewerKey++;
@@ -242,13 +282,13 @@
: PredefinedReports.ReportsFactory.GetReport("LargeDatasetReport"); : PredefinedReports.ReportsFactory.GetReport("LargeDatasetReport");
} }
XtraReport CreateSignedReportInstance(string signatureDataUrl) { XtraReport CreateSignedReportInstance(string signatureDataUrl, string signerFullName, string signerPosition, string signaturePlace) {
var report = CreateReportInstance(); var report = CreateReportInstance();
AddSignature(report, signatureDataUrl); AddSignature(report, signatureDataUrl, signerFullName, signerPosition, signaturePlace);
return report; return report;
} }
static void AddSignature(XtraReport report, string signatureDataUrl) { static void AddSignature(XtraReport report, string signatureDataUrl, string signerFullName, string signerPosition, string signaturePlace) {
var imageBytes = Convert.FromBase64String(signatureDataUrl[(signatureDataUrl.IndexOf(',') + 1)..]); var imageBytes = Convert.FromBase64String(signatureDataUrl[(signatureDataUrl.IndexOf(',') + 1)..]);
using var imageStream = new MemoryStream(imageBytes); using var imageStream = new MemoryStream(imageBytes);
var imageSource = new ImageSource(DXImage.FromStream(imageStream)); var imageSource = new ImageSource(DXImage.FromStream(imageStream));
@@ -259,28 +299,53 @@
report.Bands.Add(bottomMargin); report.Bands.Add(bottomMargin);
} }
bottomMargin.HeightF = Math.Max(bottomMargin.HeightF, 120F);
RemoveExistingSignature(bottomMargin); RemoveExistingSignature(bottomMargin);
var signatureLabel = new XRLabel { // Layout constants
Name = "receiverSignatureLabel", const float sigX = 390F;
Text = $"Empfaengerunterschrift - {DateTime.Now:g}", const float sigWidth = 230F;
BoundsF = new RectangleF(390F, 6F, 230F, 18F), const float sigImgHeight = 70F;
Font = new DXFont("Open Sans", 8F, DXFontStyle.Bold), const float infoHeight = 65F; // up to 4 lines at 8pt
ForeColor = System.Drawing.Color.FromArgb(73, 80, 87), const float innerGap = 5F;
TextAlignment = TextAlignment.MiddleLeft const float bottomPad = 6F;
}; const float defaultTopPad = 8F;
const float maxBandHeight = 210F;
float requiredHeight = defaultTopPad + sigImgHeight + innerGap + infoHeight + bottomPad;
// Grow band if needed, but cap at maxBandHeight to avoid overlapping page content
bottomMargin.HeightF = Math.Min(maxBandHeight, Math.Max(bottomMargin.HeightF, requiredHeight));
// If band is tighter than required, compress top padding so content still fits
float topPad = Math.Max(0F, bottomMargin.HeightF - bottomPad - infoHeight - innerGap - sigImgHeight);
float imageY = topPad;
float labelY = imageY + sigImgHeight + innerGap;
var signatureInformation = string.IsNullOrWhiteSpace(signerPosition)
? $"Empfaengerunterschrift\n{signerFullName}\n{signaturePlace}, {DateTime.Now:d}"
: $"Empfaengerunterschrift\n{signerFullName}\n{signerPosition}\n{signaturePlace}, {DateTime.Now:d}";
var signature = new XRPictureBox { var signature = new XRPictureBox {
Name = "receiverSignatureImage", Name = "receiverSignatureImage",
ImageSource = imageSource, ImageSource = imageSource,
BoundsF = new RectangleF(390F, 28F, 230F, 70F), BoundsF = new RectangleF(sigX, imageY, sigWidth, sigImgHeight),
Sizing = ImageSizeMode.ZoomImage, Sizing = ImageSizeMode.ZoomImage,
Borders = BorderSide.Bottom, Borders = BorderSide.Bottom,
BorderColor = System.Drawing.Color.FromArgb(73, 80, 87) BorderColor = System.Drawing.Color.FromArgb(73, 80, 87)
}; };
bottomMargin.Controls.AddRange(new XRControl[] { signatureLabel, signature }); var signatureLabel = new XRLabel {
Name = "receiverSignatureLabel",
Text = signatureInformation,
Multiline = true,
BoundsF = new RectangleF(sigX, labelY, sigWidth, infoHeight),
Font = new DXFont("Open Sans", 8F, DXFontStyle.Regular),
ForeColor = System.Drawing.Color.FromArgb(73, 80, 87),
TextAlignment = TextAlignment.TopLeft
};
bottomMargin.Controls.AddRange(new XRControl[] { signature, signatureLabel });
} }
static void RemoveExistingSignature(BottomMarginBand bottomMargin) { static void RemoveExistingSignature(BottomMarginBand bottomMargin) {

View File

@@ -2,16 +2,12 @@
@inherits LayoutComponentBase @inherits LayoutComponentBase
<div class="page"> <div class="page">
<div class="sidebar">
<NavMenu />
</div>
<main> <main>
<div class="top-row px-4"> <div class="top-row px-4">
<a href="https://docs.microsoft.com/aspnet/" target="_blank">About</a> <a href="https://docs.microsoft.com/aspnet/" target="_blank">About</a>
</div> </div>
<article class="content px-4"> <article class="content">
@Body @Body
</article> </article>
</main> </main>

View File

@@ -22,12 +22,12 @@
</div> </div>
*@ *@
<div class="nav-item px-3"> <div class="nav-item px-3">
<NavLink class="nav-link" href="reportviewer"> <NavLink class="nav-link" href="receiver">
<span class="oi oi-plus" aria-hidden="true"></span> Empfänger-UI <span class="oi oi-plus" aria-hidden="true"></span> Empfänger-UI
</NavLink> </NavLink>
</div> </div>
<div class="nav-item px-3"> <div class="nav-item px-3">
<NavLink class="nav-link" href="reportdesigner"> <NavLink class="nav-link" href="sender">
<span class="oi oi-plus" aria-hidden="true"></span> Umschlag-UI <span class="oi oi-plus" aria-hidden="true"></span> Umschlag-UI
</NavLink> </NavLink>
</div> </div>

View File

@@ -12,6 +12,28 @@ html, body {
article { article {
height: calc(100vh - 70px); height: calc(100vh - 70px);
display: flex;
flex-direction: column;
overflow: hidden;
padding-left: 0 !important;
padding-right: 0 !important;
}
.receiver-page-layout {
display: flex;
flex-direction: column;
height: 100%;
overflow: hidden;
}
.receiver-signature-panel {
flex: 0 0 auto;
}
.receiver-viewer-wrapper {
flex: 1 1 0;
min-height: 0;
overflow: hidden;
} }
.valid.modified:not([type=checkbox]) { .valid.modified:not([type=checkbox]) {