Added new localized strings for "Recently used recipients" and "Skip" in German, English, and French resource files. Updated the `CreateEnvelopeWizardPopup.razor` to enhance the "Add Receiver" button with a primary render style and a new CSS class. Introduced styles for the button in `sender-page.css` to improve its appearance with a minimum width, bold font, and box shadow.
745 lines
26 KiB
Plaintext
745 lines
26 KiB
Plaintext
@using EnvelopeGenerator.Application.Common.Dto
|
|
@using EnvelopeGenerator.Application.Common.Dto.Receiver
|
|
@using EnvelopeGenerator.Application.Resources
|
|
@using EnvelopeGenerator.Domain.Resources
|
|
@using EnvelopeGenerator.Server.Client.Services
|
|
@using Microsoft.AspNetCore.Components.Forms
|
|
@using Microsoft.Extensions.Localization
|
|
@inject IStringLocalizer<Model> ModelLocalizer
|
|
@inject IStringLocalizer<Resource> UiLocalizer
|
|
@inject ReceiverService ReceiverService
|
|
|
|
<DxPopup Visible="@_isVisible"
|
|
VisibleChanged="OnPopupVisibleChangedAsync"
|
|
HeaderText="@L("SenderWizard_Header", "Neuen Umschlag erstellen")"
|
|
Width="860px"
|
|
MaxWidth="96vw"
|
|
ShowFooter="true"
|
|
CloseOnOutsideClick="false"
|
|
ShowCloseButton="true"
|
|
CloseOnEscape="true"
|
|
ShowHeader="true"
|
|
CssClass="sender-create-wizard-popup">
|
|
<BodyContentTemplate>
|
|
<div class="sender-create-wizard"
|
|
tabindex="0"
|
|
@onkeydown="OnWizardKeyDownAsync">
|
|
<div class="sender-create-wizard__progress">
|
|
<div class="sender-create-wizard__progress-track"></div>
|
|
@for (var step = 0; step < TotalSteps; step++)
|
|
{
|
|
var isActive = step == _currentStep;
|
|
var isDone = step < _currentStep;
|
|
<div class="sender-create-wizard__step @(isActive ? "sender-create-wizard__step--active" : string.Empty) @(isDone ? "sender-create-wizard__step--done" : string.Empty)">
|
|
<span class="sender-create-wizard__step-index">@(step + 1)</span>
|
|
</div>
|
|
}
|
|
</div>
|
|
|
|
<div class="sender-create-wizard__meta">
|
|
<div class="sender-create-wizard__title">@CurrentStepTitle</div>
|
|
<div class="sender-create-wizard__description">@CurrentStepDescription</div>
|
|
</div>
|
|
|
|
@if (!string.IsNullOrWhiteSpace(_validationMessage))
|
|
{
|
|
<div class="sender-create-wizard__validation">@_validationMessage</div>
|
|
}
|
|
|
|
@if (_currentStep == 0)
|
|
{
|
|
<div class="sender-create-wizard__form-grid">
|
|
<div class="sender-create-wizard__field">
|
|
<label class="sender-create-wizard__label">
|
|
@L("Title", "Titel") <span class="sender-create-wizard__required">*</span>
|
|
</label>
|
|
<DxTextBox Text="@_title"
|
|
TextChanged="OnTitleChanged"
|
|
BindValueMode="BindValueMode.OnInput"
|
|
NullText='@L("SenderEditor_Title_Placeholder", "z.B. Arbeitsvertrag 2025")'
|
|
CssClass="w-100" />
|
|
</div>
|
|
|
|
<div class="sender-create-wizard__field">
|
|
<label class="sender-create-wizard__label">
|
|
@L("EnvelopeType", "Umschlagtyp") <span class="sender-create-wizard__required">*</span>
|
|
</label>
|
|
<select value="@(_selectedEnvelopeTypeId?.ToString() ?? string.Empty)"
|
|
@onchange="OnEnvelopeTypeChanged"
|
|
class="sender-create-wizard__select">
|
|
@foreach (var type in EnvelopeTypes)
|
|
{
|
|
<option value="@type.Id">@type.Title</option>
|
|
}
|
|
</select>
|
|
</div>
|
|
</div>
|
|
}
|
|
else if (_currentStep == 1)
|
|
{
|
|
<div class="sender-create-wizard__form-grid">
|
|
<div class="sender-create-wizard__field sender-create-wizard__field--full">
|
|
<label class="sender-create-wizard__label">
|
|
@L("Message", "Nachricht") <span class="sender-create-wizard__optional">(@L("Optional", "optional"))</span>
|
|
</label>
|
|
<DxMemo Text="@_message"
|
|
TextChanged="OnMessageChanged"
|
|
Rows="5"
|
|
MaxLength="500"
|
|
NullText='@L("SenderEditor_Message_Placeholder", "Bitte unterzeichnen Sie das beigefügte Dokument.")'
|
|
CssClass="w-100" />
|
|
</div>
|
|
|
|
<div class="sender-create-wizard__field">
|
|
<label class="sender-create-wizard__label">
|
|
@L("Language", "Sprache")
|
|
</label>
|
|
<select @bind="_language" class="sender-create-wizard__select">
|
|
<option value="de-DE">Deutsch (de-DE)</option>
|
|
<option value="en-US">English (en-US)</option>
|
|
<option value="de">Deutsch (de)</option>
|
|
<option value="en">English (en)</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
}
|
|
else if (_currentStep == 2)
|
|
{
|
|
<div class="sender-create-wizard__suggestions">
|
|
<div class="sender-create-wizard__suggestions-title">@L("SenderWizard_RecentReceivers", "Zuletzt verwendete Empfänger")</div>
|
|
|
|
@if (_isLoadingRecentSuggestions)
|
|
{
|
|
<div class="sender-create-wizard__empty-list">@L("Loading", "Lädt...")</div>
|
|
}
|
|
else if (_recentReceiverSuggestions.Count > 0)
|
|
{
|
|
<div class="sender-create-wizard__suggestion-list">
|
|
@foreach (var suggestion in _recentReceiverSuggestions)
|
|
{
|
|
<button type="button"
|
|
class="sender-create-wizard__suggestion-item"
|
|
@onclick="() => ApplyRecentSuggestion(suggestion)"
|
|
disabled="@IsActionLocked">
|
|
<span class="sender-create-wizard__suggestion-name">@suggestion.FullName</span>
|
|
<span class="sender-create-wizard__suggestion-email">@suggestion.EmailAddress</span>
|
|
</button>
|
|
}
|
|
</div>
|
|
}
|
|
</div>
|
|
|
|
<div class="sender-create-wizard__form-grid">
|
|
<div class="sender-create-wizard__field">
|
|
<label class="sender-create-wizard__label">
|
|
@L("FullName", "Vor- und Nachname") <span class="sender-create-wizard__required">*</span>
|
|
</label>
|
|
<DxTextBox Text="@_receiverName"
|
|
TextChanged="OnReceiverNameChanged"
|
|
BindValueMode="BindValueMode.OnInput"
|
|
NullText="Max Mustermann"
|
|
CssClass="w-100" />
|
|
</div>
|
|
|
|
<div class="sender-create-wizard__field">
|
|
<label class="sender-create-wizard__label">
|
|
@L("EmailAddress", "E-Mail-Adresse") <span class="sender-create-wizard__required">*</span>
|
|
</label>
|
|
<DxTextBox Text="@_receiverEmail"
|
|
TextChanged="OnReceiverEmailChanged"
|
|
BindValueMode="BindValueMode.OnInput"
|
|
NullText="name@beispiel.de"
|
|
CssClass="w-100" />
|
|
</div>
|
|
</div>
|
|
|
|
<div class="sender-create-wizard__receiver-actions">
|
|
<DxButton Text='@L("AddReceiver", "Empfänger hinzufügen")'
|
|
RenderStyle="ButtonRenderStyle.Primary"
|
|
CssClass="sender-create-wizard__add-receiver-btn"
|
|
Click="AddReceiver"
|
|
Enabled="@(!IsActionLocked)" />
|
|
</div>
|
|
|
|
@if (_receivers.Count == 0)
|
|
{
|
|
<div class="sender-create-wizard__empty-list">
|
|
@L("SenderEditor_NoReceiversAdded", "Noch keine Empfänger hinzugefügt.")
|
|
</div>
|
|
}
|
|
else
|
|
{
|
|
<div class="sender-create-wizard__receiver-list">
|
|
@foreach (var receiver in _receivers)
|
|
{
|
|
<div class="sender-create-wizard__receiver-item">
|
|
<div>
|
|
<div class="sender-create-wizard__receiver-name">@receiver.FullName</div>
|
|
<div class="sender-create-wizard__receiver-email">@receiver.EmailAddress</div>
|
|
</div>
|
|
<button type="button"
|
|
class="sender-create-wizard__receiver-remove"
|
|
@onclick="() => RemoveReceiver(receiver)"
|
|
disabled="@IsActionLocked">
|
|
@L("Delete", "Löschen")
|
|
</button>
|
|
</div>
|
|
}
|
|
</div>
|
|
}
|
|
}
|
|
else
|
|
{
|
|
<div class="sender-create-wizard__upload-stage">
|
|
<label class="sender-create-wizard__upload-btn @(IsActionLocked ? "sender-create-wizard__upload-btn--disabled" : string.Empty)">
|
|
@if (_documentBytes is null)
|
|
{
|
|
<span>@L("UploadPdf", "PDF hochladen")</span>
|
|
}
|
|
else
|
|
{
|
|
<span>@L("SenderWizard_ReplacePdf", "PDF ersetzen")</span>
|
|
}
|
|
<InputFile OnChange="OnDocumentSelectedAsync"
|
|
accept=".pdf"
|
|
disabled="@IsActionLocked"
|
|
class="sender-create-wizard__hidden-input" />
|
|
</label>
|
|
|
|
@if (_documentBytes is not null)
|
|
{
|
|
<div class="sender-create-wizard__document-meta">
|
|
<div class="sender-create-wizard__document-name">@_documentFileName</div>
|
|
<div class="sender-create-wizard__document-size">@_documentSizeText</div>
|
|
</div>
|
|
}
|
|
else
|
|
{
|
|
<div class="sender-create-wizard__empty-list">
|
|
@L("SenderWizard_DocumentRequiredHint", "Bitte laden Sie ein PDF-Dokument hoch, um fortzufahren.")
|
|
</div>
|
|
}
|
|
</div>
|
|
}
|
|
</div>
|
|
</BodyContentTemplate>
|
|
<FooterContentTemplate>
|
|
<div class="sender-create-wizard__footer">
|
|
<DxButton Text="@L("Cancel", "Abbrechen")"
|
|
RenderStyle="ButtonRenderStyle.Secondary"
|
|
Click="CloseAsync"
|
|
Enabled="@(!IsActionLocked)" />
|
|
|
|
@if (CanSkipCurrentStep)
|
|
{
|
|
<DxButton Text="@L("Skip", "Überspringen")"
|
|
RenderStyle="ButtonRenderStyle.Secondary"
|
|
Click="SkipOptionalStep"
|
|
Enabled="@(!IsActionLocked)" />
|
|
}
|
|
|
|
<DxButton Text="@L("Back", "Zurück")"
|
|
RenderStyle="ButtonRenderStyle.Secondary"
|
|
Click="MoveBack"
|
|
Enabled="@(!IsFirstStep && !IsActionLocked)" />
|
|
|
|
@if (!IsLastStep)
|
|
{
|
|
<DxButton Text="@L("Next", "Weiter")"
|
|
RenderStyle="ButtonRenderStyle.Primary"
|
|
Click="MoveNextAsync"
|
|
Enabled="@(!IsActionLocked)" />
|
|
}
|
|
else
|
|
{
|
|
<DxButton Text="@L("Start", "Editor öffnen")"
|
|
RenderStyle="ButtonRenderStyle.Primary"
|
|
Click="FinishAsync"
|
|
Enabled="@(!IsActionLocked)" />
|
|
}
|
|
</div>
|
|
</FooterContentTemplate>
|
|
</DxPopup>
|
|
|
|
@code {
|
|
[Parameter]
|
|
public bool Visible { get; set; }
|
|
|
|
[Parameter]
|
|
public EventCallback<bool> VisibleChanged { get; set; }
|
|
|
|
[Parameter]
|
|
public EventCallback<CreateEnvelopeWizardResult> StartEditorRequested { get; set; }
|
|
|
|
[Parameter]
|
|
public IReadOnlyList<EnvelopeTypeDto> EnvelopeTypes { get; set; } = [];
|
|
|
|
private const int TotalSteps = 4;
|
|
private static readonly System.ComponentModel.DataAnnotations.EmailAddressAttribute EmailValidator = new();
|
|
|
|
private bool _isVisible;
|
|
private bool _previousVisible;
|
|
private int _currentStep;
|
|
|
|
private string _title = string.Empty;
|
|
private int? _selectedEnvelopeTypeId;
|
|
private string _message = string.Empty;
|
|
private string _language = "de-DE";
|
|
|
|
private string _receiverName = string.Empty;
|
|
private string _receiverEmail = string.Empty;
|
|
private readonly List<CreateEnvelopeWizardReceiver> _receivers = [];
|
|
private readonly List<RecentReceiverSuggestionDto> _recentReceiverSuggestions = [];
|
|
private bool _isLoadingRecentSuggestions;
|
|
private bool _recentSuggestionsLoaded;
|
|
|
|
private byte[]? _documentBytes;
|
|
private string? _documentFileName;
|
|
private string _documentSizeText = string.Empty;
|
|
private bool _isDocumentUploading;
|
|
private bool _isStepActionRunning;
|
|
private bool _isFinishing;
|
|
|
|
private string? _validationMessage;
|
|
|
|
private bool IsActionLocked => _isDocumentUploading || _isStepActionRunning || _isFinishing;
|
|
|
|
private bool IsFirstStep => _currentStep <= 0;
|
|
private bool IsLastStep => _currentStep >= TotalSteps - 1;
|
|
private bool CanSkipCurrentStep => _currentStep == 1;
|
|
|
|
private string CurrentStepTitle => _currentStep switch
|
|
{
|
|
0 => L("SenderWizard_Step_Basics", "Grunddaten"),
|
|
1 => L("SenderWizard_Step_Message", "Nachricht und Optionen"),
|
|
2 => L("SenderWizard_Step_Receivers", "Empfänger"),
|
|
3 => L("SenderWizard_Step_Document", "Dokument"),
|
|
_ => L("SenderWizard_Step_Basics", "Grunddaten")
|
|
};
|
|
|
|
private string CurrentStepDescription => _currentStep switch
|
|
{
|
|
0 => L("SenderWizard_Step_Basics_Desc", "Starten Sie mit den Pflichtangaben für den Umschlag."),
|
|
1 => L("SenderWizard_Step_Message_Desc", "Fügen Sie optionale Nachricht und Einstellungen hinzu."),
|
|
2 => L("SenderWizard_Step_Receivers_Desc", "Definieren Sie die Empfänger für den Signaturprozess."),
|
|
3 => L("SenderWizard_Step_Document_Desc", "Laden Sie das Dokument hoch und platzieren Sie Signaturfelder."),
|
|
_ => L("SenderWizard_Step_Basics_Desc", "Starten Sie mit den Pflichtangaben für den Umschlag.")
|
|
};
|
|
|
|
protected override void OnParametersSet()
|
|
{
|
|
_isVisible = Visible;
|
|
|
|
if (Visible && !_previousVisible)
|
|
ResetWizardState();
|
|
|
|
_previousVisible = Visible;
|
|
}
|
|
|
|
private Task OnTitleChanged(string? value)
|
|
{
|
|
_title = value ?? string.Empty;
|
|
_validationMessage = null;
|
|
return Task.CompletedTask;
|
|
}
|
|
|
|
private Task OnMessageChanged(string? value)
|
|
{
|
|
_message = value ?? string.Empty;
|
|
_validationMessage = null;
|
|
return Task.CompletedTask;
|
|
}
|
|
|
|
private Task OnReceiverNameChanged(string? value)
|
|
{
|
|
_receiverName = value ?? string.Empty;
|
|
_validationMessage = null;
|
|
return Task.CompletedTask;
|
|
}
|
|
|
|
private Task OnReceiverEmailChanged(string? value)
|
|
{
|
|
_receiverEmail = value ?? string.Empty;
|
|
_validationMessage = null;
|
|
return Task.CompletedTask;
|
|
}
|
|
|
|
private Task OnEnvelopeTypeChanged(ChangeEventArgs args)
|
|
{
|
|
_validationMessage = null;
|
|
var raw = args.Value?.ToString();
|
|
if (int.TryParse(raw, out var id) && id > 0)
|
|
{
|
|
_selectedEnvelopeTypeId = id;
|
|
return Task.CompletedTask;
|
|
}
|
|
|
|
_selectedEnvelopeTypeId = null;
|
|
return Task.CompletedTask;
|
|
}
|
|
|
|
private Task AddReceiver()
|
|
{
|
|
if (IsActionLocked)
|
|
return Task.CompletedTask;
|
|
|
|
var fullName = _receiverName.Trim();
|
|
var email = _receiverEmail.Trim();
|
|
|
|
if (string.IsNullOrWhiteSpace(fullName))
|
|
{
|
|
_validationMessage = L("SenderEditor_Validation_FullNameRequired", "Bitte geben Sie einen Vor- und Nachnamen ein.");
|
|
return Task.CompletedTask;
|
|
}
|
|
|
|
if (string.IsNullOrWhiteSpace(email))
|
|
{
|
|
_validationMessage = L("SenderEditor_Validation_EmailRequired", "Bitte geben Sie eine E-Mail-Adresse ein.");
|
|
return Task.CompletedTask;
|
|
}
|
|
|
|
if (!EmailValidator.IsValid(email))
|
|
{
|
|
_validationMessage = L("SenderEditor_Validation_EmailInvalid", "Bitte geben Sie eine gültige E-Mail-Adresse ein.");
|
|
return Task.CompletedTask;
|
|
}
|
|
|
|
if (_receivers.Any(x => string.Equals(x.EmailAddress, email, StringComparison.OrdinalIgnoreCase)))
|
|
{
|
|
_validationMessage = L("SenderEditor_Validation_EmailDuplicate", "Diese E-Mail-Adresse wurde bereits hinzugefügt.");
|
|
return Task.CompletedTask;
|
|
}
|
|
|
|
_receivers.Add(new CreateEnvelopeWizardReceiver(fullName, email));
|
|
_receiverName = string.Empty;
|
|
_receiverEmail = string.Empty;
|
|
_validationMessage = null;
|
|
return Task.CompletedTask;
|
|
}
|
|
|
|
private Task RemoveReceiver(CreateEnvelopeWizardReceiver receiver)
|
|
{
|
|
if (IsActionLocked)
|
|
return Task.CompletedTask;
|
|
|
|
_receivers.Remove(receiver);
|
|
_validationMessage = null;
|
|
return Task.CompletedTask;
|
|
}
|
|
|
|
private async Task OnDocumentSelectedAsync(InputFileChangeEventArgs args)
|
|
{
|
|
if (IsActionLocked)
|
|
return;
|
|
|
|
_validationMessage = null;
|
|
var file = args.File;
|
|
if (file is null)
|
|
return;
|
|
|
|
if (!file.Name.EndsWith(".pdf", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
_validationMessage = L("SenderEditor_SelectPdf", "Bitte wählen Sie eine PDF-Datei aus.");
|
|
return;
|
|
}
|
|
|
|
try
|
|
{
|
|
_isDocumentUploading = true;
|
|
|
|
const long maxBytes = 50 * 1024 * 1024;
|
|
await using var stream = file.OpenReadStream(maxBytes);
|
|
using var ms = new System.IO.MemoryStream();
|
|
await stream.CopyToAsync(ms);
|
|
|
|
_documentBytes = ms.ToArray();
|
|
_documentFileName = file.Name;
|
|
_documentSizeText = FormatSize(_documentBytes.Length);
|
|
}
|
|
finally
|
|
{
|
|
_isDocumentUploading = false;
|
|
}
|
|
}
|
|
|
|
private Task MoveBack()
|
|
{
|
|
if (IsActionLocked)
|
|
return Task.CompletedTask;
|
|
|
|
_validationMessage = null;
|
|
|
|
if (!IsFirstStep)
|
|
_currentStep--;
|
|
|
|
return Task.CompletedTask;
|
|
}
|
|
|
|
private async Task MoveNextAsync()
|
|
{
|
|
if (IsActionLocked)
|
|
return;
|
|
|
|
_isStepActionRunning = true;
|
|
try
|
|
{
|
|
if (!ValidateCurrentStep())
|
|
return;
|
|
|
|
_validationMessage = null;
|
|
|
|
if (!IsLastStep)
|
|
{
|
|
_currentStep++;
|
|
|
|
if (_currentStep == 2)
|
|
await EnsureRecentSuggestionsLoadedAsync();
|
|
}
|
|
}
|
|
finally
|
|
{
|
|
_isStepActionRunning = false;
|
|
}
|
|
|
|
await Task.CompletedTask;
|
|
}
|
|
|
|
private async Task SkipOptionalStep()
|
|
{
|
|
if (IsActionLocked)
|
|
return;
|
|
|
|
if (!CanSkipCurrentStep)
|
|
return;
|
|
|
|
_message = string.Empty;
|
|
_validationMessage = null;
|
|
await MoveNextAsync();
|
|
}
|
|
|
|
private async Task CloseAsync()
|
|
{
|
|
if (IsActionLocked)
|
|
return;
|
|
|
|
await CloseCoreAsync();
|
|
}
|
|
|
|
private async Task CloseCoreAsync()
|
|
{
|
|
ResetWizardState();
|
|
await OnPopupVisibleChangedAsync(false);
|
|
}
|
|
|
|
private async Task FinishAsync()
|
|
{
|
|
if (IsActionLocked)
|
|
return;
|
|
|
|
_isFinishing = true;
|
|
try
|
|
{
|
|
if (!ValidateCurrentStep())
|
|
return;
|
|
|
|
var result = new CreateEnvelopeWizardResult(
|
|
Title: _title.Trim(),
|
|
Message: _message.Trim(),
|
|
EnvelopeTypeId: _selectedEnvelopeTypeId,
|
|
Language: string.IsNullOrWhiteSpace(_language) ? "de-DE" : _language,
|
|
Receivers: _receivers.ToList(),
|
|
DocumentBytes: _documentBytes,
|
|
DocumentFileName: _documentFileName);
|
|
|
|
await CloseCoreAsync();
|
|
|
|
if (StartEditorRequested.HasDelegate)
|
|
await StartEditorRequested.InvokeAsync(result);
|
|
}
|
|
finally
|
|
{
|
|
_isFinishing = false;
|
|
}
|
|
}
|
|
|
|
private async Task OnWizardKeyDownAsync(KeyboardEventArgs args)
|
|
{
|
|
if (!_isVisible)
|
|
return;
|
|
|
|
if (string.Equals(args.Key, "Escape", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
await CloseAsync();
|
|
return;
|
|
}
|
|
|
|
if (!string.Equals(args.Key, "Enter", StringComparison.OrdinalIgnoreCase))
|
|
return;
|
|
|
|
if (_currentStep == 1)
|
|
return;
|
|
|
|
if (_currentStep == 2 && (!string.IsNullOrWhiteSpace(_receiverName) || !string.IsNullOrWhiteSpace(_receiverEmail)))
|
|
{
|
|
await AddReceiver();
|
|
return;
|
|
}
|
|
|
|
if (IsLastStep)
|
|
{
|
|
await FinishAsync();
|
|
return;
|
|
}
|
|
|
|
await MoveNextAsync();
|
|
}
|
|
|
|
private async Task OnPopupVisibleChangedAsync(bool value)
|
|
{
|
|
_isVisible = value;
|
|
|
|
if (!value)
|
|
ResetWizardState();
|
|
|
|
if (VisibleChanged.HasDelegate)
|
|
await VisibleChanged.InvokeAsync(value);
|
|
}
|
|
|
|
private async Task EnsureRecentSuggestionsLoadedAsync()
|
|
{
|
|
if (_recentSuggestionsLoaded || _isLoadingRecentSuggestions)
|
|
return;
|
|
|
|
_isLoadingRecentSuggestions = true;
|
|
try
|
|
{
|
|
var suggestions = await ReceiverService.GetRecentReceiverSuggestionsAsync();
|
|
_recentReceiverSuggestions.Clear();
|
|
_recentReceiverSuggestions.AddRange(suggestions);
|
|
_recentSuggestionsLoaded = true;
|
|
}
|
|
catch
|
|
{
|
|
_recentReceiverSuggestions.Clear();
|
|
_recentSuggestionsLoaded = true;
|
|
}
|
|
finally
|
|
{
|
|
_isLoadingRecentSuggestions = false;
|
|
await InvokeAsync(StateHasChanged);
|
|
}
|
|
}
|
|
|
|
private void ApplyRecentSuggestion(RecentReceiverSuggestionDto suggestion)
|
|
{
|
|
if (IsActionLocked)
|
|
return;
|
|
|
|
_receiverName = suggestion.FullName;
|
|
_receiverEmail = suggestion.EmailAddress;
|
|
_validationMessage = null;
|
|
}
|
|
|
|
private bool ValidateCurrentStep()
|
|
{
|
|
if (_currentStep == 0)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(_title))
|
|
{
|
|
_validationMessage = L("SenderEditor_Validation_TitleRequired", "Bitte geben Sie einen Titel ein.");
|
|
return false;
|
|
}
|
|
|
|
if (!_selectedEnvelopeTypeId.HasValue || _selectedEnvelopeTypeId.Value <= 0)
|
|
{
|
|
_validationMessage = L("SenderWizard_Validation_EnvelopeTypeRequired", "Bitte wählen Sie einen Umschlagtyp aus.");
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
if (_currentStep == 2)
|
|
{
|
|
if (_receivers.Count == 0)
|
|
{
|
|
_validationMessage = L("SenderEditor_Validation_ReceiverRequired", "Bitte fügen Sie mindestens einen Empfänger hinzu.");
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
if (_currentStep == 3)
|
|
{
|
|
if (_documentBytes is null || _documentBytes.Length == 0)
|
|
{
|
|
_validationMessage = L("SenderEditor_Validation_UploadPdf", "Bitte laden Sie zuerst ein PDF-Dokument hoch.");
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
private static string FormatSize(long bytes)
|
|
{
|
|
const double kb = 1024;
|
|
const double mb = kb * 1024;
|
|
|
|
if (bytes >= mb)
|
|
return $"{bytes / mb:0.##} MB";
|
|
|
|
if (bytes >= kb)
|
|
return $"{bytes / kb:0.##} KB";
|
|
|
|
return $"{bytes} B";
|
|
}
|
|
|
|
private void ResetWizardState()
|
|
{
|
|
_currentStep = 0;
|
|
_validationMessage = null;
|
|
|
|
_title = string.Empty;
|
|
_selectedEnvelopeTypeId = GetDefaultEnvelopeTypeId();
|
|
_message = string.Empty;
|
|
_language = "de-DE";
|
|
|
|
_receiverName = string.Empty;
|
|
_receiverEmail = string.Empty;
|
|
_receivers.Clear();
|
|
_recentReceiverSuggestions.Clear();
|
|
_isLoadingRecentSuggestions = false;
|
|
_recentSuggestionsLoaded = false;
|
|
|
|
_documentBytes = null;
|
|
_documentFileName = null;
|
|
_documentSizeText = string.Empty;
|
|
}
|
|
|
|
private int? GetDefaultEnvelopeTypeId()
|
|
{
|
|
if (EnvelopeTypes.Count == 0)
|
|
return null;
|
|
|
|
var handwrittenType = EnvelopeTypes.FirstOrDefault(x =>
|
|
!string.IsNullOrWhiteSpace(x.Title)
|
|
&& x.Title.Contains("Handschriftliche Unterschrift", StringComparison.OrdinalIgnoreCase));
|
|
|
|
return handwrittenType?.Id ?? EnvelopeTypes[0].Id;
|
|
}
|
|
|
|
private string L(string key, string fallback)
|
|
{
|
|
var modelValue = ModelLocalizer[key];
|
|
if (!modelValue.ResourceNotFound)
|
|
return modelValue.Value;
|
|
|
|
var uiValue = UiLocalizer[key];
|
|
return uiValue.ResourceNotFound ? fallback : uiValue.Value;
|
|
}
|
|
}
|