Updated `CreateEnvelopeWizardPopup.razor` to enforce consistent popup dimensions by setting height properties to `85vh` and disabling scrolling. Enhanced `sender-page.css` with new classes to manage flexible layouts and scrolling behavior for the wizard's stepper and step content. Removed fixed height and scrolling constraints from `.sender-create-wizard__receiver-existing-list` for better layout flexibility. These changes improve the user experience by ensuring consistent dimensions, reducing unnecessary scrolling, and maintaining a structured layout.
1179 lines
64 KiB
Plaintext
1179 lines
64 KiB
Plaintext
@using EnvelopeGenerator.Application.Common.Dto
|
|
@using EnvelopeGenerator.Application.Common.Dto.Receiver
|
|
@using EnvelopeGenerator.Application.Resources
|
|
@using EnvelopeGenerator.Domain.Constants
|
|
@using EnvelopeGenerator.Domain.Resources
|
|
@using EnvelopeGenerator.Server.Client.Components.Sender.ReceiverSuggestionFilter
|
|
@using EnvelopeGenerator.Server.Client.Services
|
|
@using MudBlazor
|
|
@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="90vw"
|
|
MaxWidth="90vw"
|
|
Height="85vh"
|
|
MinHeight="85vh"
|
|
MaxHeight="85vh"
|
|
Scrollable="false"
|
|
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__body-layout">
|
|
<MudPaper Class="sender-create-wizard__stepper-shell" Elevation="0">
|
|
<MudStepper Vertical="true"
|
|
NonLinear="false"
|
|
ShowResetButton="false"
|
|
CurrentStepColor="Color.Info"
|
|
CompletedStepColor="Color.Success"
|
|
ErrorStepColor="Color.Error"
|
|
StepCompleteIcon="@Icons.Material.Filled.CheckCircle"
|
|
ActiveIndex="@_currentStep"
|
|
Class="sender-create-wizard__stepper">
|
|
<ChildContent>
|
|
@for (var step = 0; step < TotalSteps; step++)
|
|
{
|
|
var stepIndex = step;
|
|
|
|
<MudStep Title="@GetStepTitle(stepIndex)"
|
|
Completed="@_completedSteps.Contains(stepIndex)"
|
|
Skippable="false">
|
|
<div class="sender-create-wizard__stepper-description">@GetStepDescription(stepIndex)</div>
|
|
|
|
@if (stepIndex == _currentStep)
|
|
{
|
|
<div class="sender-create-wizard__step-content">
|
|
<div class="sender-create-wizard__step-layout">
|
|
<div class="sender-create-wizard__step-main">
|
|
@if (_currentStep == 0)
|
|
{
|
|
<div class="sender-create-wizard__form-grid">
|
|
<div class="sender-create-wizard__field">
|
|
<label class="sender-create-wizard__label sender-create-wizard__label-row">
|
|
<span>@L("Title", "Titel") <span class="sender-create-wizard__required">*</span></span>
|
|
<MudTooltip Text='@L("SenderWizard_Help_Title", "Ein kurzer, eindeutiger Titel hilft beim schnellen Wiederfinden des Umschlags.")'>
|
|
<MudIconButton Icon="@Icons.Material.Filled.Info" Color="Color.Tertiary" Size="Size.Small" Class="sender-create-wizard__help-icon" aria-label='@L("SenderWizard_HelpAria_Title", "Hilfe zum Feld Titel")' />
|
|
</MudTooltip>
|
|
</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 sender-create-wizard__label-row">
|
|
<span>@L("EnvelopeType", "Umschlagtyp") <span class="sender-create-wizard__required">*</span></span>
|
|
<MudTooltip Text='@L("SenderWizard_Help_EnvelopeType", "Der Umschlagtyp kann Standardwerte wie Sprache, Erinnerungen und Sicherheit vorbelegen.")'>
|
|
<MudIconButton Icon="@Icons.Material.Filled.Info" Color="Color.Tertiary" Size="Size.Small" Class="sender-create-wizard__help-icon" aria-label='@L("SenderWizard_HelpAria_EnvelopeType", "Hilfe zum Feld Umschlagtyp")' />
|
|
</MudTooltip>
|
|
</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 == 3)
|
|
{
|
|
<div class="sender-create-wizard__form-grid">
|
|
<div class="sender-create-wizard__field sender-create-wizard__field--full">
|
|
<label class="sender-create-wizard__label sender-create-wizard__label-row">
|
|
<span>@L("Message", "Nachricht") <span class="sender-create-wizard__optional">(@L("Optional", "optional"))</span></span>
|
|
<MudTooltip Text='@L("SenderWizard_Help_Message", "Diese Nachricht wird den Empfaengern in der E-Mail und im Signaturprozess angezeigt.")'>
|
|
<MudIconButton Icon="@Icons.Material.Filled.Info" Color="Color.Tertiary" Size="Size.Small" Class="sender-create-wizard__help-icon" aria-label='@L("SenderWizard_HelpAria_Message", "Hilfe zum Feld Nachricht")' />
|
|
</MudTooltip>
|
|
</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 sender-create-wizard__label-row">
|
|
<span>@L("Language", "Sprache")</span>
|
|
<MudTooltip Text='@L("SenderWizard_Help_Language", "Legt die Sprache fuer Hinweise, E-Mails und Oberflaechentexte fest.")'>
|
|
<MudIconButton Icon="@Icons.Material.Filled.Info" Color="Color.Tertiary" Size="Size.Small" Class="sender-create-wizard__help-icon" aria-label='@L("SenderWizard_HelpAria_Language", "Hilfe zum Feld Sprache")' />
|
|
</MudTooltip>
|
|
</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 class="sender-create-wizard__field sender-create-wizard__field--full">
|
|
<div class="sender-create-wizard__stage">
|
|
<p>@L("SenderWizard_FinalUploadHint", "Letzte Moeglichkeit im Wizard: Bitte laden Sie jetzt Ihr PDF ueber den rechten Upload-Bereich hoch. Im Editor koennen Sie spaeter ebenfalls ein Dokument hochladen oder ersetzen.")</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
}
|
|
else if (_currentStep == 2)
|
|
{
|
|
<div class="sender-create-wizard__settings-grid">
|
|
<div class="sender-create-wizard__settings-group">
|
|
<div class="sender-create-wizard__settings-title">
|
|
@L("SenderEditor_EnvelopeSettings", "Envelope-Einstellungen")
|
|
</div>
|
|
|
|
<div class="sender-create-wizard__form-grid">
|
|
<div class="sender-create-wizard__field">
|
|
<label class="sender-create-wizard__label sender-create-wizard__label-row">
|
|
<span>@L("CertificationType", "Zertifizierung")</span>
|
|
<MudTooltip Text='@L("SenderWizard_Help_CertificationType", "Bestimmt das Signaturniveau fuer diesen Umschlag.")'>
|
|
<MudIconButton Icon="@Icons.Material.Filled.Info" Color="Color.Tertiary" Size="Size.Small" Class="sender-create-wizard__help-icon" aria-label='@L("SenderWizard_HelpAria_CertificationType", "Hilfe zum Feld Zertifizierung")' />
|
|
</MudTooltip>
|
|
</label>
|
|
<select @bind="_certificationType" @bind:after="OnCertificationTypeChanged" class="sender-create-wizard__select">
|
|
<option value="@CertificationType.AdvancedElectronicSignature">@L("AdvancedElectronicSignature", "Advanced Electronic Signature")</option>
|
|
<option value="@CertificationType.ElectronicSignature">@L("ElectronicSignature", "Electronic Signature")</option>
|
|
</select>
|
|
</div>
|
|
|
|
<div class="sender-create-wizard__field">
|
|
<label class="sender-create-wizard__label sender-create-wizard__label-row">
|
|
<span>@L("FinalEmailToCreator", "Abgeschlossenes Dokument an Ersteller")</span>
|
|
<MudTooltip Text='@L("SenderWizard_Help_FinalEmailToCreator", "Steuert, ob der Ersteller nach Abschluss eine finale E-Mail erhaelt und ob das Dokument angehaengt wird.")'>
|
|
<MudIconButton Icon="@Icons.Material.Filled.Info" Color="Color.Tertiary" Size="Size.Small" Class="sender-create-wizard__help-icon" aria-label='@L("SenderWizard_HelpAria_FinalEmailToCreator", "Hilfe zum Feld Abgeschlossenes Dokument an Ersteller")' />
|
|
</MudTooltip>
|
|
</label>
|
|
<select @bind="_finalEmailToCreator" class="sender-create-wizard__select">
|
|
<option value="0">@L("No", "Nein")</option>
|
|
<option value="1">@L("Yes", "Ja")</option>
|
|
<option value="2">@L("YesWithAttachment", "Ja, mit Anhang")</option>
|
|
</select>
|
|
</div>
|
|
|
|
<div class="sender-create-wizard__field">
|
|
<label class="sender-create-wizard__label sender-create-wizard__label-row">
|
|
<span>@L("FinalEmailToReceivers", "Abgeschlossenes Dokument an Empfänger")</span>
|
|
<MudTooltip Text='@L("SenderWizard_Help_FinalEmailToReceivers", "Steuert, ob Empfaenger nach Abschluss eine finale E-Mail erhalten und ob das Dokument angehaengt wird.")'>
|
|
<MudIconButton Icon="@Icons.Material.Filled.Info" Color="Color.Tertiary" Size="Size.Small" Class="sender-create-wizard__help-icon" aria-label='@L("SenderWizard_HelpAria_FinalEmailToReceivers", "Hilfe zum Feld Abgeschlossenes Dokument an Empfaenger")' />
|
|
</MudTooltip>
|
|
</label>
|
|
<select @bind="_finalEmailToReceivers" class="sender-create-wizard__select">
|
|
<option value="0">@L("No", "Nein")</option>
|
|
<option value="1">@L("Yes", "Ja")</option>
|
|
<option value="2">@L("YesWithAttachment", "Ja, mit Anhang")</option>
|
|
</select>
|
|
</div>
|
|
|
|
<div class="sender-create-wizard__field sender-create-wizard__field--full">
|
|
<div class="sender-create-wizard__settings-toggles">
|
|
<label class="sender-create-wizard__settings-toggle">
|
|
<input type="checkbox" checked="@_tfaEnabled" @onchange="OnTfaChanged" disabled="@IsFesSelected" />
|
|
<span>@L("TFAEnabled", "2FA aktiviert")</span>
|
|
<MudTooltip Text='@L("SenderWizard_Help_TfaEnabled", "Wenn aktiviert, ist die Signaturfreigabe nur mit zusaetzlicher Verifizierung moeglich.")'>
|
|
<MudIconButton Icon="@Icons.Material.Filled.Info" Color="Color.Tertiary" Size="Size.Small" Class="sender-create-wizard__help-icon" aria-label='@L("SenderWizard_HelpAria_TfaEnabled", "Hilfe zur Option 2FA")' />
|
|
</MudTooltip>
|
|
</label>
|
|
<label class="sender-create-wizard__settings-toggle">
|
|
<input type="checkbox" checked="@_useAccessCode" @onchange="OnUseAccessCodeChanged" disabled="@_tfaEnabled" />
|
|
<span>@L("UseAccessCode", "Zugriffscode verwenden")</span>
|
|
<MudTooltip Text='@L("SenderWizard_Help_UseAccessCode", "Empfaenger muessen einen Zugriffscode eingeben. Bei aktivem 2FA bleibt diese Option immer aktiv.")'>
|
|
<MudIconButton Icon="@Icons.Material.Filled.Info" Color="Color.Tertiary" Size="Size.Small" Class="sender-create-wizard__help-icon" aria-label='@L("SenderWizard_HelpAria_UseAccessCode", "Hilfe zur Option Zugriffscode verwenden")' />
|
|
</MudTooltip>
|
|
</label>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="sender-create-wizard__settings-group">
|
|
<div class="sender-create-wizard__settings-title">
|
|
@L("SendReminderEmails", "Erinnerungs-E-Mails senden")
|
|
</div>
|
|
|
|
<div class="sender-create-wizard__form-grid">
|
|
<div class="sender-create-wizard__field sender-create-wizard__field--full">
|
|
<label class="sender-create-wizard__settings-toggle">
|
|
<input type="checkbox" checked="@_sendReminderEmails" @onchange="OnSendReminderEmailsChanged" />
|
|
<span>@L("SendReminderEmails", "Erinnerungs-E-Mails senden")</span>
|
|
<MudTooltip Text='@L("SenderWizard_Help_SendReminderEmails", "Aktiviert automatische Erinnerungsmails fuer noch offene Signaturen.")'>
|
|
<MudIconButton Icon="@Icons.Material.Filled.Info" Color="Color.Tertiary" Size="Size.Small" Class="sender-create-wizard__help-icon" aria-label='@L("SenderWizard_HelpAria_SendReminderEmails", "Hilfe zur Option Erinnerungs-E-Mails senden")' />
|
|
</MudTooltip>
|
|
</label>
|
|
</div>
|
|
|
|
<div class="sender-create-wizard__field">
|
|
<label class="sender-create-wizard__label sender-create-wizard__label-row">
|
|
<span>@L("FirstReminderDays", "Erste Erinnerung (Tage)")</span>
|
|
<MudTooltip Text='@L("SenderWizard_Help_FirstReminderDays", "Anzahl Tage nach Versand bis zur ersten Erinnerung.")'>
|
|
<MudIconButton Icon="@Icons.Material.Filled.Info" Color="Color.Tertiary" Size="Size.Small" Class="sender-create-wizard__help-icon" aria-label='@L("SenderWizard_HelpAria_FirstReminderDays", "Hilfe zum Feld Erste Erinnerung")' />
|
|
</MudTooltip>
|
|
</label>
|
|
<InputNumber @bind-Value="_firstReminderDays" class="form-control form-control-sm" disabled="@(!_sendReminderEmails)" />
|
|
</div>
|
|
|
|
<div class="sender-create-wizard__field">
|
|
<label class="sender-create-wizard__label sender-create-wizard__label-row">
|
|
<span>@L("ReminderIntervalDays", "Erinnerungsintervall (Tage)")</span>
|
|
<MudTooltip Text='@L("SenderWizard_Help_ReminderIntervalDays", "Abstand in Tagen zwischen den weiteren Erinnerungen.")'>
|
|
<MudIconButton Icon="@Icons.Material.Filled.Info" Color="Color.Tertiary" Size="Size.Small" Class="sender-create-wizard__help-icon" aria-label='@L("SenderWizard_HelpAria_ReminderIntervalDays", "Hilfe zum Feld Erinnerungsintervall")' />
|
|
</MudTooltip>
|
|
</label>
|
|
<InputNumber @bind-Value="_reminderIntervalDays" class="form-control form-control-sm" disabled="@(!_sendReminderEmails)" />
|
|
</div>
|
|
|
|
<div class="sender-create-wizard__field">
|
|
<label class="sender-create-wizard__label sender-create-wizard__label-row">
|
|
<span>@L("ExpiresWhenDays", "Laeuft ab nach (Tage)")</span>
|
|
<MudTooltip Text='@L("SenderWizard_Help_ExpiresWhenDays", "Legt fest, nach wie vielen Tagen der Umschlag automatisch ablaeuft.")'>
|
|
<MudIconButton Icon="@Icons.Material.Filled.Info" Color="Color.Tertiary" Size="Size.Small" Class="sender-create-wizard__help-icon" aria-label='@L("SenderWizard_HelpAria_ExpiresWhenDays", "Hilfe zum Feld Laeuft ab nach")' />
|
|
</MudTooltip>
|
|
</label>
|
|
<InputNumber @bind-Value="_expiresWhenDays" class="form-control form-control-sm" />
|
|
</div>
|
|
|
|
<div class="sender-create-wizard__field">
|
|
<label class="sender-create-wizard__label sender-create-wizard__label-row">
|
|
<span>@L("ExpiresWarningWhenDays", "Ablaufwarnung (Tage)")</span>
|
|
<MudTooltip Text='@L("SenderWizard_Help_ExpiresWarningWhenDays", "Tage vor Ablauf, an denen eine Warnung versendet wird.")'>
|
|
<MudIconButton Icon="@Icons.Material.Filled.Info" Color="Color.Tertiary" Size="Size.Small" Class="sender-create-wizard__help-icon" aria-label='@L("SenderWizard_HelpAria_ExpiresWarningWhenDays", "Hilfe zum Feld Ablaufwarnung")' />
|
|
</MudTooltip>
|
|
</label>
|
|
<InputNumber @bind-Value="_expiresWarningWhenDays" class="form-control form-control-sm" />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
}
|
|
else if (_currentStep == 1)
|
|
{
|
|
<div class="sender-create-wizard__suggestions">
|
|
<DxTextBox Text="@_receiverSuggestionFilterText"
|
|
TextChanged="OnReceiverSuggestionFilterChanged"
|
|
BindValueMode="BindValueMode.OnInput"
|
|
NullText='@L("SenderWizard_FilterRecentReceivers_Placeholder", "Empfänger in Vorschlägen filtern...")'
|
|
CssClass="w-100" />
|
|
|
|
@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" role="listbox" aria-label="Recent receivers">
|
|
@foreach (var suggestion in FilteredRecentSuggestions)
|
|
{
|
|
<button type="button"
|
|
class="sender-create-wizard__suggestion-item"
|
|
@onclick="() => ApplyRecentSuggestionAndAddAsync(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__receiver-tagbox-wrap">
|
|
<div class="sender-create-wizard__receiver-list" role="table" aria-label="Added receivers">
|
|
<div class="sender-create-wizard__receiver-existing-list">
|
|
@for (var i = 0; i < _receivers.Count; i++)
|
|
{
|
|
var rowIndex = i;
|
|
var receiver = _receivers[rowIndex];
|
|
|
|
<div class="sender-create-wizard__receiver-row" role="row">
|
|
<div class="sender-create-wizard__receiver-fields-stack sender-create-wizard__field--full">
|
|
<div class="sender-create-wizard__field">
|
|
<DxTextBox Text="@receiver.FullName"
|
|
TextChanged="@(value => OnReceiverListNameChanged(rowIndex, value))"
|
|
BindValueMode="BindValueMode.OnInput"
|
|
NullText='@L("FullName", "Vor- und Nachname")'
|
|
CssClass="w-100"
|
|
Enabled="@(!IsActionLocked)" />
|
|
</div>
|
|
<div class="sender-create-wizard__field">
|
|
<DxTextBox Text="@receiver.EmailAddress"
|
|
TextChanged="@(value => OnReceiverListEmailChanged(rowIndex, value))"
|
|
BindValueMode="BindValueMode.OnInput"
|
|
NullText='@L("EmailAddress", "E-Mail-Adresse")'
|
|
CssClass="w-100"
|
|
Enabled="@(!IsActionLocked)" />
|
|
</div>
|
|
</div>
|
|
<button type="button"
|
|
class="sender-create-wizard__receiver-remove-btn"
|
|
@onclick="() => RemoveReceiver(receiver)"
|
|
disabled="@IsActionLocked"
|
|
title='@L("Remove", "Entfernen")'
|
|
aria-label='@L("Remove", "Entfernen")'>
|
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16" aria-hidden="true">
|
|
<path d="M5.5 5.5A.5.5 0 0 1 6 6v6a.5.5 0 0 1-1 0V6a.5.5 0 0 1 .5-.5zm2.5 0a.5.5 0 0 1 .5.5v6a.5.5 0 0 1-1 0V6a.5.5 0 0 1 .5-.5zm3 .5a.5.5 0 0 0-1 0v6a.5.5 0 0 0 1 0V6z" />
|
|
<path fill-rule="evenodd" d="M14.5 3a1 1 0 0 1-1 1H13v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V4h-.5a1 1 0 0 1-1-1V2a1 1 0 0 1 1-1H6a1 1 0 0 1 1-1h2a1 1 0 0 1 1 1h3.5a1 1 0 0 1 1 1v1zM4.118 4 4 4.059V13a1 1 0 0 0 1 1h6a1 1 0 0 0 1-1V4.059L11.882 4H4.118zM2.5 3V2h11v1h-11z" />
|
|
</svg>
|
|
</button>
|
|
</div>
|
|
}
|
|
<div class="sender-create-wizard__receiver-row sender-create-wizard__receiver-row--new" role="row">
|
|
<div class="sender-create-wizard__receiver-fields-stack sender-create-wizard__field--full">
|
|
<div class="sender-create-wizard__field">
|
|
<DxTextBox Text="@_receiverName"
|
|
TextChanged="OnReceiverNameChanged"
|
|
BindValueMode="BindValueMode.OnInput"
|
|
NullText="Max Mustermann"
|
|
CssClass="w-100"
|
|
Enabled="@(!IsActionLocked)" />
|
|
</div>
|
|
<div class="sender-create-wizard__field">
|
|
<DxTextBox Text="@_receiverEmail"
|
|
TextChanged="OnReceiverEmailChanged"
|
|
BindValueMode="BindValueMode.OnInput"
|
|
NullText="name@beispiel.de"
|
|
CssClass="w-100"
|
|
Enabled="@(!IsActionLocked)" />
|
|
</div>
|
|
</div>
|
|
<button type="button"
|
|
class="sender-create-wizard__receiver-add-inline-btn"
|
|
@onclick="AddReceiver"
|
|
disabled="@IsActionLocked"
|
|
title='@L("AddReceiver", "Empfänger hinzufügen")'
|
|
aria-label='@L("AddReceiver", "Empfänger hinzufügen")'>
|
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16" aria-hidden="true">
|
|
<path d="M8 1a.5.5 0 0 1 .5.5V7.5h6a.5.5 0 0 1 0 1h-6v6a.5.5 0 0 1-1 0v-6h-6a.5.5 0 0 1 0-1h6v-6A.5.5 0 0 1 8 1z" />
|
|
</svg>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
}
|
|
</MudStep>
|
|
}
|
|
</ChildContent>
|
|
</MudStepper>
|
|
</MudPaper>
|
|
|
|
<aside class="sender-create-wizard__wizard-side">
|
|
<PdfFileDropZone Disabled="@IsActionLocked"
|
|
HasDocument="@(_documentBytes is { Length: > 0 })"
|
|
DocumentName="@_documentFileName"
|
|
DocumentSizeText="@_documentSizeText"
|
|
UploadText='@L("SenderWizard_DocumentUploadSimpleHint", "Dokument hinzufuegen: klicken oder per Drag-and-Drop ablegen")'
|
|
ReplaceText='@L("SenderWizard_DocumentUploadSimpleHint", "Dokument hinzufuegen: klicken oder per Drag-and-Drop ablegen")'
|
|
UploadedHintText='@L("SenderWizard_DocumentReplaceHint", "Zum Ersetzen klicken oder eine Datei auf diese Fläche ziehen.")'
|
|
FileSelected="OnDocumentSelectedAsync" />
|
|
</aside>
|
|
</div>
|
|
|
|
@if (!string.IsNullOrWhiteSpace(_validationMessage))
|
|
{
|
|
<div class="sender-create-wizard__validation">@_validationMessage</div>
|
|
}
|
|
|
|
</div>
|
|
</BodyContentTemplate>
|
|
<FooterContentTemplate>
|
|
<div class="sender-create-wizard__footer">
|
|
<DxButton Text="@L("Cancel", "Abbrechen")"
|
|
RenderStyle="ButtonRenderStyle.Secondary"
|
|
Click="CloseAsync"
|
|
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 readonly HashSet<int> _completedSteps = [];
|
|
|
|
private string _title = string.Empty;
|
|
private int? _selectedEnvelopeTypeId;
|
|
private string _message = string.Empty;
|
|
private string _language = "de-DE";
|
|
private bool _useAccessCode;
|
|
private bool _tfaEnabled;
|
|
private CertificationType _certificationType = CertificationType.AdvancedElectronicSignature;
|
|
private int _finalEmailToCreator = (int)FinalEmailType.No;
|
|
private int _finalEmailToReceivers = (int)FinalEmailType.No;
|
|
private bool _sendReminderEmails;
|
|
private int _firstReminderDays;
|
|
private int _reminderIntervalDays;
|
|
private int _expiresWhenDays;
|
|
private int _expiresWarningWhenDays;
|
|
|
|
private string _receiverName = string.Empty;
|
|
private string _receiverEmail = string.Empty;
|
|
private string _receiverSuggestionFilterText = string.Empty;
|
|
private readonly List<CreateEnvelopeWizardReceiver> _receivers = [];
|
|
private readonly List<RecentReceiverSuggestionDto> _recentReceiverSuggestions = [];
|
|
private bool _isLoadingRecentSuggestions;
|
|
private bool _recentSuggestionsLoaded;
|
|
|
|
private const int SuggestionLimit = 20;
|
|
|
|
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 IsFesSelected => _certificationType == CertificationType.AdvancedElectronicSignature;
|
|
|
|
private bool IsFirstStep => _currentStep <= 0;
|
|
private bool IsLastStep => _currentStep >= TotalSteps - 1;
|
|
private IReadOnlyList<RecentReceiverSuggestionDto> FilteredRecentSuggestions =>
|
|
BuildFilteredRecentSuggestions();
|
|
|
|
private string GetStepTitle(int step) => step switch
|
|
{
|
|
0 => L("SenderWizard_Step_Start", "Start"),
|
|
1 => L("SenderWizard_Step_Receivers", "Empfänger"),
|
|
2 => L("SenderEditor_EnvelopeSettings", "Envelope-Einstellungen"),
|
|
3 => L("SenderWizard_Step_Message", "Nachricht und letzter Dokument-Upload"),
|
|
_ => L("SenderWizard_Step_Start", "Start")
|
|
};
|
|
|
|
private string GetStepDescription(int step) => step switch
|
|
{
|
|
0 => L("SenderWizard_Step_Basics_Desc", "Starten Sie mit den Pflichtangaben für den Umschlag."),
|
|
1 => L("SenderWizard_Step_Receivers_Desc", "Definieren Sie die Empfänger für den Signaturprozess."),
|
|
2 => L("SenderWizard_Step_Settings_Desc", "Konfigurieren Sie Sicherheits-, Erinnerungs- und Ablaufoptionen."),
|
|
3 => L("SenderWizard_Step_Message_Desc", "Fuegen Sie optionale Nachricht hinzu und nutzen Sie rechts die letzte Upload-Moeglichkeit im Wizard."),
|
|
_ => L("SenderWizard_Step_Basics_Desc", "Starten Sie mit den Pflichtangaben für den Umschlag.")
|
|
};
|
|
|
|
protected override void OnParametersSet()
|
|
{
|
|
_isVisible = Visible;
|
|
|
|
if (_selectedEnvelopeTypeId is null && EnvelopeTypes.Count > 0)
|
|
ApplyDefaultEnvelopeType();
|
|
|
|
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 OnReceiverSuggestionFilterChanged(string? value)
|
|
{
|
|
_receiverSuggestionFilterText = 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;
|
|
var selectedType = EnvelopeTypes.FirstOrDefault(x => x.Id == id);
|
|
if (selectedType is not null)
|
|
ApplyEnvelopeTypeDefaults(selectedType);
|
|
|
|
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 Task OnReceiverListNameChanged(int index, string? value)
|
|
{
|
|
if (IsActionLocked || index < 0 || index >= _receivers.Count)
|
|
return Task.CompletedTask;
|
|
|
|
var current = _receivers[index];
|
|
_receivers[index] = current with { FullName = value ?? string.Empty };
|
|
_validationMessage = null;
|
|
return Task.CompletedTask;
|
|
}
|
|
|
|
private Task OnReceiverListEmailChanged(int index, string? value)
|
|
{
|
|
if (IsActionLocked || index < 0 || index >= _receivers.Count)
|
|
return Task.CompletedTask;
|
|
|
|
var current = _receivers[index];
|
|
_receivers[index] = current with { EmailAddress = value ?? string.Empty };
|
|
_validationMessage = null;
|
|
return Task.CompletedTask;
|
|
}
|
|
|
|
private IReadOnlyList<RecentReceiverSuggestionDto> BuildFilteredRecentSuggestions()
|
|
{
|
|
if (_recentReceiverSuggestions.Count == 0)
|
|
return [];
|
|
|
|
var handler = new ReceiverSuggestionFilterHandler(_recentReceiverSuggestions);
|
|
var filterText = _receiverSuggestionFilterText.Trim();
|
|
var filtered = string.IsNullOrWhiteSpace(filterText)
|
|
? _recentReceiverSuggestions
|
|
: handler.Filter(filterText);
|
|
|
|
return filtered
|
|
.GroupBy(x => x.EmailAddress, StringComparer.OrdinalIgnoreCase)
|
|
.Select(g => g.OrderByDescending(x => x.LastUsedAt).First())
|
|
.OrderByDescending(x => x.LastUsedAt)
|
|
.ThenBy(x => x.EmailAddress, StringComparer.OrdinalIgnoreCase)
|
|
.Take(SuggestionLimit)
|
|
.ToList();
|
|
}
|
|
|
|
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)
|
|
{
|
|
_completedSteps.Add(_currentStep);
|
|
_currentStep++;
|
|
|
|
if (_currentStep == 1)
|
|
await EnsureRecentSuggestionsLoadedAsync();
|
|
|
|
}
|
|
}
|
|
finally
|
|
{
|
|
_isStepActionRunning = false;
|
|
}
|
|
|
|
await Task.CompletedTask;
|
|
}
|
|
|
|
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,
|
|
UseAccessCode: _useAccessCode,
|
|
TFAEnabled: _tfaEnabled,
|
|
CertificationType: _certificationType,
|
|
FinalEmailToCreator: _finalEmailToCreator,
|
|
FinalEmailToReceivers: _finalEmailToReceivers,
|
|
SendReminderEmails: _sendReminderEmails,
|
|
FirstReminderDays: _firstReminderDays,
|
|
ReminderIntervalDays: _reminderIntervalDays,
|
|
ExpiresWhenDays: _expiresWhenDays,
|
|
ExpiresWarningWhenDays: _expiresWarningWhenDays,
|
|
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 == 3)
|
|
return;
|
|
|
|
if (_currentStep == 1 && (!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(SuggestionLimit);
|
|
_recentReceiverSuggestions.Clear();
|
|
_recentReceiverSuggestions.AddRange(suggestions);
|
|
_recentSuggestionsLoaded = true;
|
|
}
|
|
catch
|
|
{
|
|
_recentReceiverSuggestions.Clear();
|
|
_recentSuggestionsLoaded = true;
|
|
}
|
|
finally
|
|
{
|
|
_isLoadingRecentSuggestions = false;
|
|
await InvokeAsync(StateHasChanged);
|
|
}
|
|
}
|
|
|
|
private async Task ApplyRecentSuggestionAndAddAsync(RecentReceiverSuggestionDto suggestion)
|
|
{
|
|
if (IsActionLocked)
|
|
return;
|
|
|
|
_receiverName = suggestion.FullName;
|
|
_receiverEmail = suggestion.EmailAddress;
|
|
await AddReceiver();
|
|
}
|
|
|
|
private bool ValidateCurrentStep()
|
|
{
|
|
if (_currentStep == 0)
|
|
{
|
|
if (_selectedEnvelopeTypeId is null && EnvelopeTypes.Count > 0)
|
|
_selectedEnvelopeTypeId = GetDefaultEnvelopeTypeId();
|
|
|
|
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 (!ValidateSettings(out var settingsError))
|
|
{
|
|
_validationMessage = settingsError;
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
if (_currentStep == 1)
|
|
{
|
|
if (_receivers.Count == 0)
|
|
{
|
|
_validationMessage = L("SenderEditor_Validation_ReceiverRequired", "Bitte fügen Sie mindestens einen Empfänger hinzu.");
|
|
return false;
|
|
}
|
|
|
|
for (var i = 0; i < _receivers.Count; i++)
|
|
{
|
|
var receiver = _receivers[i];
|
|
var fullName = receiver.FullName.Trim();
|
|
var email = receiver.EmailAddress.Trim();
|
|
|
|
if (string.IsNullOrWhiteSpace(fullName))
|
|
{
|
|
_validationMessage = L("SenderEditor_Validation_FullNameRequired", "Bitte geben Sie einen Vor- und Nachnamen ein.");
|
|
return false;
|
|
}
|
|
|
|
if (string.IsNullOrWhiteSpace(email))
|
|
{
|
|
_validationMessage = L("SenderEditor_Validation_EmailRequired", "Bitte geben Sie eine E-Mail-Adresse ein.");
|
|
return false;
|
|
}
|
|
|
|
if (!EmailValidator.IsValid(email))
|
|
{
|
|
_validationMessage = L("SenderEditor_Validation_EmailInvalid", "Bitte geben Sie eine gültige E-Mail-Adresse ein.");
|
|
return false;
|
|
}
|
|
}
|
|
|
|
var duplicateEmailExists = _receivers
|
|
.GroupBy(x => x.EmailAddress.Trim(), StringComparer.OrdinalIgnoreCase)
|
|
.Any(group => group.Count() > 1);
|
|
|
|
if (duplicateEmailExists)
|
|
{
|
|
_validationMessage = L("SenderEditor_Validation_EmailDuplicate", "Diese E-Mail-Adresse wurde bereits hinzugefügt.");
|
|
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 OnTfaChanged(ChangeEventArgs args)
|
|
{
|
|
_validationMessage = null;
|
|
|
|
if (IsFesSelected)
|
|
{
|
|
_tfaEnabled = true;
|
|
_useAccessCode = true;
|
|
return;
|
|
}
|
|
|
|
_tfaEnabled = ParseCheckboxValue(args);
|
|
if (_tfaEnabled)
|
|
_useAccessCode = true;
|
|
}
|
|
|
|
private Task OnCertificationTypeChanged()
|
|
{
|
|
_validationMessage = null;
|
|
NormalizeSettings();
|
|
return Task.CompletedTask;
|
|
}
|
|
|
|
private void OnUseAccessCodeChanged(ChangeEventArgs args)
|
|
{
|
|
_validationMessage = null;
|
|
|
|
if (_tfaEnabled)
|
|
{
|
|
_useAccessCode = true;
|
|
return;
|
|
}
|
|
|
|
_useAccessCode = ParseCheckboxValue(args);
|
|
}
|
|
|
|
private void OnSendReminderEmailsChanged(ChangeEventArgs args)
|
|
{
|
|
_validationMessage = null;
|
|
_sendReminderEmails = ParseCheckboxValue(args);
|
|
}
|
|
|
|
private static bool ParseCheckboxValue(ChangeEventArgs args)
|
|
{
|
|
if (args.Value is bool boolValue)
|
|
return boolValue;
|
|
|
|
return bool.TryParse(args.Value?.ToString(), out var parsed) && parsed;
|
|
}
|
|
|
|
private void ApplyEnvelopeTypeDefaults(EnvelopeTypeDto envelopeType)
|
|
{
|
|
if (!string.IsNullOrWhiteSpace(envelopeType.Language))
|
|
_language = envelopeType.Language;
|
|
|
|
if (envelopeType.UseAccessCode.HasValue)
|
|
_useAccessCode = envelopeType.UseAccessCode.Value;
|
|
|
|
if (_tfaEnabled)
|
|
_useAccessCode = true;
|
|
|
|
if (envelopeType.CertificationType.HasValue)
|
|
_certificationType = envelopeType.CertificationType.Value;
|
|
|
|
if (envelopeType.FinalEmailToCreator.HasValue)
|
|
_finalEmailToCreator = envelopeType.FinalEmailToCreator.Value;
|
|
|
|
if (envelopeType.FinalEmailToReceivers.HasValue)
|
|
_finalEmailToReceivers = envelopeType.FinalEmailToReceivers.Value;
|
|
|
|
if (envelopeType.SendReminderEmails.HasValue)
|
|
_sendReminderEmails = envelopeType.SendReminderEmails.Value;
|
|
|
|
if (envelopeType.FirstReminderDays.HasValue)
|
|
_firstReminderDays = envelopeType.FirstReminderDays.Value;
|
|
|
|
if (envelopeType.ReminderIntervalDays.HasValue)
|
|
_reminderIntervalDays = envelopeType.ReminderIntervalDays.Value;
|
|
|
|
if (envelopeType.ExpiresDays.HasValue)
|
|
_expiresWhenDays = envelopeType.ExpiresDays.Value;
|
|
|
|
if (envelopeType.ExpiresWarningDays.HasValue)
|
|
_expiresWarningWhenDays = envelopeType.ExpiresWarningDays.Value;
|
|
|
|
NormalizeSettings();
|
|
}
|
|
|
|
private void NormalizeSettings()
|
|
{
|
|
_language = string.IsNullOrWhiteSpace(_language) ? "de-DE" : _language.Trim();
|
|
|
|
if (IsFesSelected)
|
|
_tfaEnabled = true;
|
|
|
|
if (_tfaEnabled)
|
|
_useAccessCode = true;
|
|
|
|
_firstReminderDays = Math.Max(0, _firstReminderDays);
|
|
_reminderIntervalDays = Math.Max(0, _reminderIntervalDays);
|
|
_expiresWhenDays = Math.Max(0, _expiresWhenDays);
|
|
_expiresWarningWhenDays = Math.Max(0, _expiresWarningWhenDays);
|
|
|
|
if (_expiresWhenDays > 0 && _expiresWarningWhenDays > _expiresWhenDays)
|
|
_expiresWarningWhenDays = _expiresWhenDays;
|
|
}
|
|
|
|
private bool ValidateSettings(out string? message)
|
|
{
|
|
NormalizeSettings();
|
|
|
|
if (_sendReminderEmails && _reminderIntervalDays <= 0)
|
|
{
|
|
message = L("SenderEditor_Validation_ReminderInterval", "Bitte geben Sie ein Erinnerungsintervall groesser als 0 Tage ein.");
|
|
return false;
|
|
}
|
|
|
|
if (_sendReminderEmails && _firstReminderDays < 0)
|
|
{
|
|
message = L("SenderEditor_Validation_FirstReminder", "Bitte geben Sie gueltige Tage fuer die erste Erinnerung ein.");
|
|
return false;
|
|
}
|
|
|
|
if (_expiresWhenDays > 0 && _expiresWarningWhenDays > _expiresWhenDays)
|
|
{
|
|
message = L("SenderEditor_Validation_ExpiryWarning", "Die Ablaufwarnung darf nicht nach dem Ablaufdatum liegen.");
|
|
return false;
|
|
}
|
|
|
|
message = null;
|
|
return true;
|
|
}
|
|
|
|
private void ApplyDefaultEnvelopeType()
|
|
{
|
|
_selectedEnvelopeTypeId = GetDefaultEnvelopeTypeId();
|
|
if (!_selectedEnvelopeTypeId.HasValue)
|
|
return;
|
|
|
|
var selectedType = EnvelopeTypes.FirstOrDefault(x => x.Id == _selectedEnvelopeTypeId.Value);
|
|
if (selectedType is not null)
|
|
ApplyEnvelopeTypeDefaults(selectedType);
|
|
}
|
|
|
|
private void ResetWizardState()
|
|
{
|
|
_currentStep = 0;
|
|
_completedSteps.Clear();
|
|
_validationMessage = null;
|
|
|
|
_title = string.Empty;
|
|
_selectedEnvelopeTypeId = null;
|
|
_message = string.Empty;
|
|
_language = "de-DE";
|
|
_useAccessCode = false;
|
|
_tfaEnabled = false;
|
|
_certificationType = CertificationType.AdvancedElectronicSignature;
|
|
_finalEmailToCreator = (int)FinalEmailType.No;
|
|
_finalEmailToReceivers = (int)FinalEmailType.No;
|
|
_sendReminderEmails = false;
|
|
_firstReminderDays = 0;
|
|
_reminderIntervalDays = 0;
|
|
_expiresWhenDays = 0;
|
|
_expiresWarningWhenDays = 0;
|
|
|
|
_receiverName = string.Empty;
|
|
_receiverEmail = string.Empty;
|
|
_receiverSuggestionFilterText = string.Empty;
|
|
_receivers.Clear();
|
|
_recentReceiverSuggestions.Clear();
|
|
_isLoadingRecentSuggestions = false;
|
|
_recentSuggestionsLoaded = false;
|
|
|
|
_documentBytes = null;
|
|
_documentFileName = null;
|
|
_documentSizeText = string.Empty;
|
|
|
|
ApplyDefaultEnvelopeType();
|
|
NormalizeSettings();
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
}
|