Introduced the ability to share envelopes in read-only mode and view them via a dedicated page. Added `ShareEnvelopeReadOnlyAsync` in `AuthService.cs` to handle sharing logic. Updated `ReceiverPage.razor` with a "Share" button, popup UI, and validation for sharing inputs. Created `ReceiverReadOnlyPage.razor` for read-only document viewing with error handling and lifecycle management. Added `EnvelopeKeyRedirectController.cs` to support legacy link redirection. Enhanced `ReadOnlyController.cs` to support envelope sharing with improved logging and `IMediator` integration. Improved state management, validation, and error handling across components. Performed general code cleanup and UI enhancements for better user experience.
189 lines
6.6 KiB
Plaintext
189 lines
6.6 KiB
Plaintext
@page "/envelope/readonly/{ReadOnlyKey}"
|
|
@rendermode InteractiveServer
|
|
@using DevExpress.Blazor.Reporting
|
|
@using DevExpress.XtraReports.UI
|
|
@using EnvelopeGenerator.Application.Common.Dto.EnvelopeReceiverReadOnly
|
|
@using EnvelopeGenerator.Application.Common.Extensions
|
|
@using EnvelopeGenerator.Application.Common.Interfaces.Services
|
|
@using EnvelopeGenerator.Domain.Constants
|
|
@inject EnvelopeGenerator.Server.Client.Services.AppVersionService AppVersion
|
|
@inject ILogger<ReceiverReadOnlyPage> Logger
|
|
@inject IEnvelopeReceiverReadOnlyService ReadOnlyService
|
|
@inject IEnvelopeReceiverService EnvelopeReceiverService
|
|
@inject IEnvelopeHistoryService HistoryService
|
|
@implements IDisposable
|
|
|
|
<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="@AppVersion.GetVersionedUrl("css/envelope-viewer.css")" rel="stylesheet" />
|
|
|
|
<div class="envelope-viewer-layout">
|
|
<div class="envelope-action-bar">
|
|
<div class="envelope-action-bar__inner" style="padding: 0.5rem 1.25rem;">
|
|
<div style="display:flex; align-items:center; justify-content:space-between; gap:1rem;">
|
|
<div style="font-weight:600; color:#1f2937;">Dokumentansicht (Nur Lesen)</div>
|
|
@if (_readOnly is not null)
|
|
{
|
|
<div style="font-size:0.8rem; color:#6b7280;">Gultig bis: @_readOnly.DateValid.ToString("dd.MM.yyyy")</div>
|
|
}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="envelope-content" style="padding:0; overflow:hidden;">
|
|
@if (_isLoading)
|
|
{
|
|
<div class="d-flex justify-content-center align-items-center h-100">
|
|
<div class="text-center">
|
|
<div class="spinner-border text-white mb-3" style="width:3.5rem; height:3.5rem;" role="status"></div>
|
|
<p class="text-white fw-semibold">Dokument wird geladen...</p>
|
|
</div>
|
|
</div>
|
|
}
|
|
else if (!string.IsNullOrWhiteSpace(_errorMessage))
|
|
{
|
|
<div class="error-container">
|
|
<div class="alert alert-danger shadow-lg mb-0">
|
|
<h5 class="mb-2">Dokument nicht verfugbar</h5>
|
|
<p class="mb-0">@_errorMessage</p>
|
|
</div>
|
|
</div>
|
|
}
|
|
else if (_isExpired)
|
|
{
|
|
<div class="error-container">
|
|
<div class="alert alert-warning shadow-lg mb-0">
|
|
<h5 class="mb-2">Freigabe abgelaufen</h5>
|
|
<p class="mb-0">Der Zeitraum fur diese Nur-Lesen-Freigabe ist abgelaufen.</p>
|
|
</div>
|
|
</div>
|
|
}
|
|
else if (_report is not null)
|
|
{
|
|
<DxReportViewer @ref="_reportViewer"
|
|
Report="_report"
|
|
RootCssClasses="w-100 h-100" />
|
|
}
|
|
</div>
|
|
</div>
|
|
|
|
@code {
|
|
[Parameter] public string? ReadOnlyKey { get; set; }
|
|
|
|
bool _isLoading = true;
|
|
bool _isExpired = false;
|
|
string? _errorMessage;
|
|
EnvelopeReceiverReadOnlyDto? _readOnly;
|
|
|
|
DxReportViewer? _reportViewer;
|
|
XtraReport? _report;
|
|
|
|
protected override async Task OnInitializedAsync()
|
|
{
|
|
if (string.IsNullOrWhiteSpace(ReadOnlyKey))
|
|
{
|
|
_errorMessage = "Freigabe-Schlussel fehlt.";
|
|
_isLoading = false;
|
|
return;
|
|
}
|
|
|
|
if (!ReadOnlyKey.TryDecode(out var decodedKeys) || decodedKeys.GetEncodeType() != EncodeType.EnvelopeReceiverReadOnly)
|
|
{
|
|
_errorMessage = "Ungultiger Freigabe-Link.";
|
|
_isLoading = false;
|
|
return;
|
|
}
|
|
|
|
try
|
|
{
|
|
var readOnlyId = decodedKeys.ParseReadOnlyId();
|
|
var readOnlyRes = await ReadOnlyService.ReadByIdAsync(readOnlyId);
|
|
if (readOnlyRes.IsFailed)
|
|
{
|
|
_errorMessage = "Freigabe konnte nicht geladen werden.";
|
|
_isLoading = false;
|
|
return;
|
|
}
|
|
|
|
_readOnly = readOnlyRes.Data;
|
|
|
|
if (DateTime.Now > _readOnly.DateValid)
|
|
{
|
|
_isExpired = true;
|
|
_isLoading = false;
|
|
return;
|
|
}
|
|
|
|
if (_readOnly.Envelope is null || _readOnly.Receiver is null)
|
|
{
|
|
_errorMessage = "Freigabe ist unvollstandig.";
|
|
_isLoading = false;
|
|
return;
|
|
}
|
|
|
|
var erRes = await EnvelopeReceiverService.ReadByUuidSignatureAsync(_readOnly.Envelope.Uuid, _readOnly.Receiver.Signature);
|
|
if (erRes.IsFailed)
|
|
{
|
|
_errorMessage = "Dokument wurde nicht gefunden.";
|
|
_isLoading = false;
|
|
return;
|
|
}
|
|
|
|
var envelopeReceiver = erRes.Data;
|
|
var documentBytes = envelopeReceiver.Envelope?.Documents?.FirstOrDefault()?.ByteData;
|
|
if (documentBytes is not { Length: > 0 })
|
|
{
|
|
_errorMessage = "Dokumentdaten konnten nicht geladen werden.";
|
|
_isLoading = false;
|
|
return;
|
|
}
|
|
|
|
_report = BuildReport(documentBytes);
|
|
|
|
try
|
|
{
|
|
var historyResult = await HistoryService.RecordAsync((int)_readOnly.EnvelopeId, _readOnly.AddedWho, EnvelopeStatus.EnvelopeViewed);
|
|
if (historyResult.IsFailed)
|
|
Logger.LogWarning("Failed to record EnvelopeViewed history for read-only key {ReadOnlyKey}", ReadOnlyKey);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Logger.LogWarning(ex, "Failed to record read-only history for {ReadOnlyKey}", ReadOnlyKey);
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Logger.LogError(ex, "Unexpected error in read-only page for {ReadOnlyKey}", ReadOnlyKey);
|
|
_errorMessage = "Beim Laden ist ein unerwarteter Fehler aufgetreten.";
|
|
}
|
|
|
|
_isLoading = false;
|
|
}
|
|
|
|
static XtraReport BuildReport(byte[] pdfBytes)
|
|
{
|
|
var report = new XtraReport
|
|
{
|
|
PaperKind = DevExpress.Drawing.Printing.DXPaperKind.A4,
|
|
Landscape = false,
|
|
Margins = new System.Drawing.Printing.Margins(0, 0, 0, 0)
|
|
};
|
|
|
|
var detail = new DetailBand { HeightF = 0f };
|
|
report.Bands.Add(detail);
|
|
|
|
detail.Controls.Add(new XRPdfContent
|
|
{
|
|
Source = pdfBytes,
|
|
GenerateOwnPages = true
|
|
});
|
|
|
|
return report;
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
_report?.Dispose();
|
|
}
|
|
}
|