diff --git a/EnvelopeGenerator.Server/EnvelopeGenerator.Server.Client/Components/Sender/CreateEnvelopeWizardPopup.razor b/EnvelopeGenerator.Server/EnvelopeGenerator.Server.Client/Components/Sender/CreateEnvelopeWizardPopup.razor index 545ef8b0..f099c3f0 100644 --- a/EnvelopeGenerator.Server/EnvelopeGenerator.Server.Client/Components/Sender/CreateEnvelopeWizardPopup.razor +++ b/EnvelopeGenerator.Server/EnvelopeGenerator.Server.Client/Components/Sender/CreateEnvelopeWizardPopup.razor @@ -1,6 +1,7 @@ @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 @@ -106,6 +107,93 @@ } else if (_currentStep == 2) + { +
+
+
+ @L("SenderEditor_EnvelopeSettings", "Envelope-Einstellungen") +
+ +
+
+ + +
+ +
+ + +
+ +
+ + +
+ +
+
+ + +
+
+
+
+ +
+
+ @L("SendReminderEmails", "Erinnerungs-E-Mails senden") +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+
+
+
+ } + else if (_currentStep == 3) {
@L("SenderWizard_RecentReceivers", "Zuletzt verwendete Empfänger")
@@ -320,7 +408,7 @@ [Parameter] public IReadOnlyList EnvelopeTypes { get; set; } = []; - private const int TotalSteps = 4; + private const int TotalSteps = 5; private static readonly System.ComponentModel.DataAnnotations.EmailAddressAttribute EmailValidator = new(); private bool _isVisible; @@ -331,6 +419,16 @@ private int? _selectedEnvelopeTypeId; private string _message = string.Empty; private string _language = "de-DE"; + private bool _useAccessCode; + private bool _tfaEnabled; + private int _certificationType = (int)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; @@ -372,8 +470,9 @@ { 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"), + 2 => L("SenderEditor_EnvelopeSettings", "Envelope-Einstellungen"), + 3 => L("SenderWizard_Step_Receivers", "Empfänger"), + 4 => L("SenderWizard_Step_Document", "Dokument"), _ => L("SenderWizard_Step_Basics", "Grunddaten") }; @@ -381,8 +480,9 @@ { 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."), + 2 => L("SenderWizard_Step_Settings_Desc", "Konfigurieren Sie Sicherheits-, Erinnerungs- und Ablaufoptionen."), + 3 => L("SenderWizard_Step_Receivers_Desc", "Definieren Sie die Empfänger für den Signaturprozess."), + 4 => 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.") }; @@ -391,7 +491,7 @@ _isVisible = Visible; if (_selectedEnvelopeTypeId is null && EnvelopeTypes.Count > 0) - _selectedEnvelopeTypeId = GetDefaultEnvelopeTypeId(); + ApplyDefaultEnvelopeType(); if (Visible && !_previousVisible) ResetWizardState(); @@ -434,6 +534,10 @@ 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; } @@ -600,7 +704,7 @@ { _currentStep++; - if (_currentStep == 2) + if (_currentStep == 3) await EnsureRecentSuggestionsLoadedAsync(); } } @@ -655,6 +759,16 @@ 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); @@ -687,7 +801,7 @@ if (_currentStep == 1) return; - if (_currentStep == 2 && (!string.IsNullOrWhiteSpace(_receiverName) || !string.IsNullOrWhiteSpace(_receiverEmail))) + if (_currentStep == 3 && (!string.IsNullOrWhiteSpace(_receiverName) || !string.IsNullOrWhiteSpace(_receiverEmail))) { await AddReceiver(); return; @@ -771,6 +885,17 @@ } if (_currentStep == 2) + { + if (!ValidateSettings(out var settingsError)) + { + _validationMessage = settingsError; + return false; + } + + return true; + } + + if (_currentStep == 3) { if (_receivers.Count == 0) { @@ -781,7 +906,7 @@ return true; } - if (_currentStep == 3) + if (_currentStep == 4) { if (_documentBytes is null || _documentBytes.Length == 0) { @@ -854,15 +979,151 @@ return Task.CompletedTask; } + private void OnTfaChanged(ChangeEventArgs args) + { + _validationMessage = null; + _tfaEnabled = ParseCheckboxValue(args); + if (_tfaEnabled) + _useAccessCode = true; + } + + 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 (_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; _validationMessage = null; _title = string.Empty; - _selectedEnvelopeTypeId = GetDefaultEnvelopeTypeId(); + _selectedEnvelopeTypeId = null; _message = string.Empty; _language = "de-DE"; + _useAccessCode = false; + _tfaEnabled = false; + _certificationType = (int)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; @@ -877,6 +1138,8 @@ _documentSizeText = string.Empty; _documentPreviewPageCount = 0; _documentPreviewPages = []; + + ApplyDefaultEnvelopeType(); } private int? GetDefaultEnvelopeTypeId() diff --git a/EnvelopeGenerator.Server/EnvelopeGenerator.Server.Client/Components/Sender/CreateEnvelopeWizardResult.cs b/EnvelopeGenerator.Server/EnvelopeGenerator.Server.Client/Components/Sender/CreateEnvelopeWizardResult.cs index d81c6f9b..c4b63ebb 100644 --- a/EnvelopeGenerator.Server/EnvelopeGenerator.Server.Client/Components/Sender/CreateEnvelopeWizardResult.cs +++ b/EnvelopeGenerator.Server/EnvelopeGenerator.Server.Client/Components/Sender/CreateEnvelopeWizardResult.cs @@ -5,6 +5,16 @@ public sealed record CreateEnvelopeWizardResult( string Message, int? EnvelopeTypeId, string Language, + bool UseAccessCode, + bool TFAEnabled, + int CertificationType, + int FinalEmailToCreator, + int FinalEmailToReceivers, + bool SendReminderEmails, + int FirstReminderDays, + int ReminderIntervalDays, + int ExpiresWhenDays, + int ExpiresWarningWhenDays, IReadOnlyList Receivers, byte[]? DocumentBytes, string? DocumentFileName); diff --git a/EnvelopeGenerator.Server/EnvelopeGenerator.Server.Client/Pages/SenderEditorPage.razor b/EnvelopeGenerator.Server/EnvelopeGenerator.Server.Client/Pages/SenderEditorPage.razor index 68186fe2..8d4b992d 100644 --- a/EnvelopeGenerator.Server/EnvelopeGenerator.Server.Client/Pages/SenderEditorPage.razor +++ b/EnvelopeGenerator.Server/EnvelopeGenerator.Server.Client/Pages/SenderEditorPage.razor @@ -732,6 +732,17 @@ _envelopeMessage = payload.Message ?? string.Empty; _selectedEnvelopeTypeId = payload.EnvelopeTypeId; _language = string.IsNullOrWhiteSpace(payload.Language) ? "de-DE" : payload.Language; + _useAccessCode = payload.UseAccessCode; + _tfaEnabled = payload.TFAEnabled; + _certificationType = payload.CertificationType; + _finalEmailToCreator = payload.FinalEmailToCreator; + _finalEmailToReceivers = payload.FinalEmailToReceivers; + _sendReminderEmails = payload.SendReminderEmails; + _firstReminderDays = payload.FirstReminderDays; + _reminderIntervalDays = payload.ReminderIntervalDays; + _expiresWhenDays = payload.ExpiresWhenDays; + _expiresWarningWhenDays = payload.ExpiresWarningWhenDays; + NormalizeSettings(); _receivers = payload.Receivers .Select((receiver, index) => new ReceiverDraft( diff --git a/EnvelopeGenerator.Server/EnvelopeGenerator.Server.Client/Pages/SenderPage.razor b/EnvelopeGenerator.Server/EnvelopeGenerator.Server.Client/Pages/SenderPage.razor index 1c07de46..2b5a2184 100644 --- a/EnvelopeGenerator.Server/EnvelopeGenerator.Server.Client/Pages/SenderPage.razor +++ b/EnvelopeGenerator.Server/EnvelopeGenerator.Server.Client/Pages/SenderPage.razor @@ -730,6 +730,16 @@ Message: result.Message, EnvelopeTypeId: result.EnvelopeTypeId, Language: result.Language, + UseAccessCode: result.UseAccessCode, + TFAEnabled: result.TFAEnabled, + CertificationType: result.CertificationType, + FinalEmailToCreator: result.FinalEmailToCreator, + FinalEmailToReceivers: result.FinalEmailToReceivers, + SendReminderEmails: result.SendReminderEmails, + FirstReminderDays: result.FirstReminderDays, + ReminderIntervalDays: result.ReminderIntervalDays, + ExpiresWhenDays: result.ExpiresWhenDays, + ExpiresWarningWhenDays: result.ExpiresWarningWhenDays, Receivers: result.Receivers .Select(x => new CreateEnvelopeBootstrapReceiver(x.FullName, x.EmailAddress)) .ToList(), diff --git a/EnvelopeGenerator.Server/EnvelopeGenerator.Server.Client/Services/CreateEnvelopeBootstrapStorageService.cs b/EnvelopeGenerator.Server/EnvelopeGenerator.Server.Client/Services/CreateEnvelopeBootstrapStorageService.cs index e39fd8a4..2d13cc61 100644 --- a/EnvelopeGenerator.Server/EnvelopeGenerator.Server.Client/Services/CreateEnvelopeBootstrapStorageService.cs +++ b/EnvelopeGenerator.Server/EnvelopeGenerator.Server.Client/Services/CreateEnvelopeBootstrapStorageService.cs @@ -47,6 +47,16 @@ public sealed record CreateEnvelopeBootstrapPayload( string Message, int? EnvelopeTypeId, string Language, + bool UseAccessCode, + bool TFAEnabled, + int CertificationType, + int FinalEmailToCreator, + int FinalEmailToReceivers, + bool SendReminderEmails, + int FirstReminderDays, + int ReminderIntervalDays, + int ExpiresWhenDays, + int ExpiresWarningWhenDays, IReadOnlyList Receivers, byte[]? DocumentBytes, string? DocumentFileName); diff --git a/EnvelopeGenerator.Server/EnvelopeGenerator.Server/wwwroot/css/sender-page.css b/EnvelopeGenerator.Server/EnvelopeGenerator.Server/wwwroot/css/sender-page.css index 318bcadc..e4605752 100644 --- a/EnvelopeGenerator.Server/EnvelopeGenerator.Server/wwwroot/css/sender-page.css +++ b/EnvelopeGenerator.Server/EnvelopeGenerator.Server/wwwroot/css/sender-page.css @@ -1242,6 +1242,40 @@ grid-column: 1 / -1; } +.sender-create-wizard__settings-grid { + display: grid; + gap: 0.8rem; +} + +.sender-create-wizard__settings-group { + border: 1px solid rgba(148, 163, 184, 0.34); + border-radius: 10px; + background: rgba(248, 250, 252, 0.86); + padding: 0.8rem; +} + +.sender-create-wizard__settings-title { + font-size: 0.8rem; + font-weight: 800; + color: #334155; + margin-bottom: 0.6rem; +} + +.sender-create-wizard__settings-toggles { + display: flex; + flex-wrap: wrap; + gap: 0.55rem 1.1rem; +} + +.sender-create-wizard__settings-toggle { + display: inline-flex; + align-items: center; + gap: 0.4rem; + font-size: 0.82rem; + font-weight: 600; + color: #334155; +} + .sender-create-wizard__label { font-size: 0.82rem; font-weight: 700;