Refactor and enhance envelope wizard with MudBlazor

Replaced custom wizard UI with MudBlazor's MudStepper for a modern and consistent design. Added dynamic step titles, descriptions, and forms for envelope creation, including advanced settings like certification, reminders, and email notifications. Integrated PDF upload with preview functionality.

Refactored `CreateEnvelopeWizardPopup.razor` for better maintainability and modularity. Removed redundant code and centralized step-related logic. Improved localization, accessibility, and user experience.

Updated `EnvelopeGenerator.Server.Client.csproj` and `EnvelopeGenerator.Server.csproj` to include MudBlazor. Registered MudBlazor services in `Program.cs` and added required CSS/JS in `App.razor`. Updated styles in `sender-page.css` to align with the new stepper design.
This commit is contained in:
2026-11-05 15:22:21 +01:00
parent 595bbf3f25
commit e3d2225a44
8 changed files with 390 additions and 358 deletions

View File

@@ -5,6 +5,7 @@
@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
@@ -27,333 +28,341 @@
<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>
<MudPaper Class="sender-create-wizard__stepper-shell" Elevation="0">
<MudStepper Vertical="true"
NonLinear="false"
ShowResetButton="false"
ActiveIndex="@_currentStep"
Class="sender-create-wizard__stepper">
<ChildContent>
@for (var step = 0; step < TotalSteps; step++)
{
var stepIndex = step;
<div class="sender-create-wizard__meta">
<div class="sender-create-wizard__title">@CurrentStepTitle</div>
<div class="sender-create-wizard__description">@CurrentStepDescription</div>
</div>
<MudStep Title="@GetStepTitle(stepIndex)">
<div class="sender-create-wizard__stepper-description">@GetStepDescription(stepIndex)</div>
@if (stepIndex == _currentStep)
{
<div class="sender-create-wizard__step-content">
@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__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">@L("CertificationType", "Zertifizierung")</label>
<select @bind="_certificationType" 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">@L("FinalEmailToCreator", "Finale E-Mail an Ersteller")</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">@L("FinalEmailToReceivers", "Finale E-Mail an Empfänger")</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" />
@L("TFAEnabled", "2FA aktiviert")
</label>
<label class="sender-create-wizard__settings-toggle">
<input type="checkbox" checked="@_useAccessCode" @onchange="OnUseAccessCodeChanged" disabled="@_tfaEnabled" />
@L("UseAccessCode", "Zugriffscode verwenden")
</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" />
@L("SendReminderEmails", "Erinnerungs-E-Mails senden")
</label>
</div>
<div class="sender-create-wizard__field">
<label class="sender-create-wizard__label">@L("FirstReminderDays", "Erste Erinnerung (Tage)")</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">@L("ReminderIntervalDays", "Erinnerungsintervall (Tage)")</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">@L("ExpiresWhenDays", "Läuft ab nach (Tage)")</label>
<InputNumber @bind-Value="_expiresWhenDays" class="form-control form-control-sm" />
</div>
<div class="sender-create-wizard__field">
<label class="sender-create-wizard__label">@L("ExpiresWarningWhenDays", "Ablaufwarnung (Tage)")</label>
<InputNumber @bind-Value="_expiresWarningWhenDays" class="form-control form-control-sm" />
</div>
</div>
</div>
</div>
}
else if (_currentStep == 3)
{
<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" role="listbox" aria-label="Recent receivers">
@foreach (var suggestion in FilteredRecentSuggestions)
{
<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">
<button type="button"
class="sender-create-wizard__add-receiver-btn"
@onclick="AddReceiver"
disabled="@IsActionLocked">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" fill="currentColor" viewBox="0 0 16 16" aria-hidden="true">
<path d="M8 4a.5.5 0 0 1 .5.5V7.5H11.5a.5.5 0 0 1 0 1H8.5v3a.5.5 0 0 1-1 0v-3H4.5a.5.5 0 0 1 0-1H7.5v-3A.5.5 0 0 1 8 4z" />
</svg>
<span>@L("AddReceiver", "Empfänger hinzufügen")</span>
</button>
</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-tagbox-wrap">
<label class="sender-create-wizard__label" for="wizardReceiversTagBox">
@L("Receiver", "Empfänger")
</label>
<DxTagBox Data="@_receivers"
TData="CreateEnvelopeWizardReceiver"
TValue="CreateEnvelopeWizardReceiver"
AllowCustomTags="true"
@bind-Tags="@_receiverTags"
@bind-Tags:after="OnReceiverTagsChanged"
HideSelectedItems="false"
TextFieldName="@nameof(CreateEnvelopeWizardReceiver.EmailAddress)"
ListRenderMode="ListRenderMode.Virtual"
SearchMode="ListSearchMode.AutoSearch"
SearchFilterCondition="ListSearchFilterCondition.Contains"
SearchTextParseMode="ListSearchTextParseMode.GroupWordsByAnd"
CssClass="sender-create-wizard__receiver-tagbox"
InputId="wizardReceiversTagBox"
Enabled="@(!IsActionLocked)">
<TagDisplayTemplate Context="tagContext">
<div class="sender-create-wizard__receiver-tag">
@if (tagContext.DataItem is CreateEnvelopeWizardReceiver receiver)
{
<span class="sender-create-wizard__receiver-tag-name">@receiver.FullName</span>
<span class="sender-create-wizard__receiver-tag-email">@receiver.EmailAddress</span>
}
else
{
<span class="sender-create-wizard__receiver-tag-email">@tagContext.DisplayText</span>
}
<button type="button"
class="sender-create-wizard__receiver-tag-remove"
@onclick="tagContext.RemoveTagAction"
aria-label="Remove receiver"
disabled="@IsActionLocked">x</button>
</div>
</TagDisplayTemplate>
<EmptyDataAreaTemplate Context="emptyContext">
<div class="sender-create-wizard__tagbox-empty"></div>
</EmptyDataAreaTemplate>
</DxTagBox>
</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-preview-card">
<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>
<div class="sender-create-wizard__document-preview-wrap">
<SenderPdfImageEditor IsPlacementMode="false"
PageCount="@_documentPreviewPageCount"
Pages="@_documentPreviewPages"
PdfDataUrl="@DocumentPreviewDataUrl"
PdfFileName="@_documentFileName"
Fields="@_documentPreviewFieldOverlays"
EditorClick="OnDocumentPreviewEditorClickAsync"
RemoveField="OnDocumentPreviewRemoveFieldAsync"
MoveField="OnDocumentPreviewMoveFieldAsync" />
</div>
</div>
}
else
{
<PdfFileDropZone Disabled="@IsActionLocked"
HasDocument="false"
UploadText='@L("SenderWizard_DocumentRequiredHint", "Bitte laden Sie ein PDF-Dokument hoch, um fortzufahren.")'
DragDropHintText='@L("SenderWizard_DragDropPdfHint", "Oder ziehen Sie die PDF-Datei hierher.")'
FileSelected="OnDocumentSelectedAsync" />
}
</div>
}
</div>
}
</MudStep>
}
</ChildContent>
</MudStepper>
</MudPaper>
@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__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">@L("CertificationType", "Zertifizierung")</label>
<select @bind="_certificationType" 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">@L("FinalEmailToCreator", "Finale E-Mail an Ersteller")</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">@L("FinalEmailToReceivers", "Finale E-Mail an Empfänger")</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" />
@L("TFAEnabled", "2FA aktiviert")
</label>
<label class="sender-create-wizard__settings-toggle">
<input type="checkbox" checked="@_useAccessCode" @onchange="OnUseAccessCodeChanged" disabled="@_tfaEnabled" />
@L("UseAccessCode", "Zugriffscode verwenden")
</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" />
@L("SendReminderEmails", "Erinnerungs-E-Mails senden")
</label>
</div>
<div class="sender-create-wizard__field">
<label class="sender-create-wizard__label">@L("FirstReminderDays", "Erste Erinnerung (Tage)")</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">@L("ReminderIntervalDays", "Erinnerungsintervall (Tage)")</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">@L("ExpiresWhenDays", "Läuft ab nach (Tage)")</label>
<InputNumber @bind-Value="_expiresWhenDays" class="form-control form-control-sm" />
</div>
<div class="sender-create-wizard__field">
<label class="sender-create-wizard__label">@L("ExpiresWarningWhenDays", "Ablaufwarnung (Tage)")</label>
<InputNumber @bind-Value="_expiresWarningWhenDays" class="form-control form-control-sm" />
</div>
</div>
</div>
</div>
}
else if (_currentStep == 3)
{
<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" role="listbox" aria-label="Recent receivers">
@foreach (var suggestion in FilteredRecentSuggestions)
{
<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">
<button type="button"
class="sender-create-wizard__add-receiver-btn"
@onclick="AddReceiver"
disabled="@IsActionLocked">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" fill="currentColor" viewBox="0 0 16 16" aria-hidden="true">
<path d="M8 4a.5.5 0 0 1 .5.5V7.5H11.5a.5.5 0 0 1 0 1H8.5v3a.5.5 0 0 1-1 0v-3H4.5a.5.5 0 0 1 0-1H7.5v-3A.5.5 0 0 1 8 4z" />
</svg>
<span>@L("AddReceiver", "Empfänger hinzufügen")</span>
</button>
</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-tagbox-wrap">
<label class="sender-create-wizard__label" for="wizardReceiversTagBox">
@L("Receiver", "Empfänger")
</label>
<DxTagBox Data="@_receivers"
TData="CreateEnvelopeWizardReceiver"
TValue="CreateEnvelopeWizardReceiver"
AllowCustomTags="true"
@bind-Tags="@_receiverTags"
@bind-Tags:after="OnReceiverTagsChanged"
HideSelectedItems="false"
TextFieldName="@nameof(CreateEnvelopeWizardReceiver.EmailAddress)"
ListRenderMode="ListRenderMode.Virtual"
SearchMode="ListSearchMode.AutoSearch"
SearchFilterCondition="ListSearchFilterCondition.Contains"
SearchTextParseMode="ListSearchTextParseMode.GroupWordsByAnd"
CssClass="sender-create-wizard__receiver-tagbox"
InputId="wizardReceiversTagBox"
Enabled="@(!IsActionLocked)">
<TagDisplayTemplate Context="tagContext">
<div class="sender-create-wizard__receiver-tag">
@if (tagContext.DataItem is CreateEnvelopeWizardReceiver receiver)
{
<span class="sender-create-wizard__receiver-tag-name">@receiver.FullName</span>
<span class="sender-create-wizard__receiver-tag-email">@receiver.EmailAddress</span>
}
else
{
<span class="sender-create-wizard__receiver-tag-email">@tagContext.DisplayText</span>
}
<button type="button"
class="sender-create-wizard__receiver-tag-remove"
@onclick="tagContext.RemoveTagAction"
aria-label="Remove receiver"
disabled="@IsActionLocked">x</button>
</div>
</TagDisplayTemplate>
<EmptyDataAreaTemplate Context="emptyContext">
<div class="sender-create-wizard__tagbox-empty"></div>
</EmptyDataAreaTemplate>
</DxTagBox>
</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-preview-card">
<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>
<div class="sender-create-wizard__document-preview-wrap">
<SenderPdfImageEditor IsPlacementMode="false"
PageCount="@_documentPreviewPageCount"
Pages="@_documentPreviewPages"
PdfDataUrl="@DocumentPreviewDataUrl"
PdfFileName="@_documentFileName"
Fields="@_documentPreviewFieldOverlays"
EditorClick="OnDocumentPreviewEditorClickAsync"
RemoveField="OnDocumentPreviewRemoveFieldAsync"
MoveField="OnDocumentPreviewMoveFieldAsync" />
</div>
</div>
}
else
{
<PdfFileDropZone Disabled="@IsActionLocked"
HasDocument="false"
UploadText='@L("SenderWizard_DocumentRequiredHint", "Bitte laden Sie ein PDF-Dokument hoch, um fortzufahren.")'
DragDropHintText='@L("SenderWizard_DragDropPdfHint", "Oder ziehen Sie die PDF-Datei hierher.")'
FileSelected="OnDocumentSelectedAsync" />
}
</div>
}
</div>
</BodyContentTemplate>
<FooterContentTemplate>
@@ -465,7 +474,11 @@
? $"data:application/pdf;base64,{Convert.ToBase64String(_documentBytes)}"
: null;
private string CurrentStepTitle => _currentStep switch
private string CurrentStepTitle => GetStepTitle(_currentStep);
private string CurrentStepDescription => GetStepDescription(_currentStep);
private string GetStepTitle(int step) => step switch
{
0 => L("SenderWizard_Step_Basics", "Grunddaten"),
1 => L("SenderWizard_Step_Message", "Nachricht und Optionen"),
@@ -475,7 +488,7 @@
_ => L("SenderWizard_Step_Basics", "Grunddaten")
};
private string CurrentStepDescription => _currentStep switch
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_Message_Desc", "Fügen Sie optionale Nachricht und Einstellungen hinzu."),