From b65098fafb038d341bb41ed4cbeac8b37b2bb592 Mon Sep 17 00:00:00 2001 From: TekH Date: Tue, 10 Nov 2026 19:29:33 +0100 Subject: [PATCH] Improve document upload UX and refactor wizard layout Enhanced the `CreateEnvelopeWizardPopup` component: - Added a new grid layout (`sender-create-wizard__body-layout`) to separate main content and side panel. - Introduced a collapsible side panel for document upload and preview. - Replaced old upload logic with `PdfFileDropZone` and added support for displaying document metadata (name, size) and replacement hints. - Added asynchronous document preview rendering with `EnsureDocumentPreviewPreparedAsync`. Localization updates: - Added new localized strings for document upload hints in `de-DE`, `en-US`, and `fr-FR`. CSS updates: - Styled the new layout and side panel with transitions. - Updated `PdfFileDropZone` styles for different states (e.g., document uploaded). Refactored code for better maintainability and improved user feedback during document upload and preview preparation. --- .../Resources/Resource.de-DE.resx | 2 + .../Resources/Resource.en-US.resx | 2 + .../Resources/Resource.fr-FR.resx | 2 + .../Sender/CreateEnvelopeWizardPopup.razor | 729 +++++++++--------- .../Components/Sender/PdfFileDropZone.razor | 32 +- .../wwwroot/css/sender-page.css | 83 ++ 6 files changed, 502 insertions(+), 348 deletions(-) diff --git a/EnvelopeGenerator.Application/Resources/Resource.de-DE.resx b/EnvelopeGenerator.Application/Resources/Resource.de-DE.resx index 0e5c7f2a..4b1e1c82 100644 --- a/EnvelopeGenerator.Application/Resources/Resource.de-DE.resx +++ b/EnvelopeGenerator.Application/Resources/Resource.de-DE.resx @@ -778,6 +778,8 @@ Signiertes Dokument System Start + Dokument hinzufuegen: klicken oder per Drag-and-Drop ablegen + Zum Ersetzen klicken oder eine Datei auf diese Flaeche ziehen. Ein unerwarteter Fehler ist aufgetreten. Bitte versuchen Sie es später erneut. PDF hochladen Benutzername diff --git a/EnvelopeGenerator.Application/Resources/Resource.en-US.resx b/EnvelopeGenerator.Application/Resources/Resource.en-US.resx index 98f44634..159d65e9 100644 --- a/EnvelopeGenerator.Application/Resources/Resource.en-US.resx +++ b/EnvelopeGenerator.Application/Resources/Resource.en-US.resx @@ -778,6 +778,8 @@ Signed document System Start + Add document: click or drag and drop + Click to replace or drag a file onto this area. An unexpected error occurred. Please try again later. Upload PDF Username diff --git a/EnvelopeGenerator.Application/Resources/Resource.fr-FR.resx b/EnvelopeGenerator.Application/Resources/Resource.fr-FR.resx index c07dfac4..26c7f8c3 100644 --- a/EnvelopeGenerator.Application/Resources/Resource.fr-FR.resx +++ b/EnvelopeGenerator.Application/Resources/Resource.fr-FR.resx @@ -778,6 +778,8 @@ Document signé Système Démarrer + Ajouter un document : cliquer ou glisser-deposer + Cliquez pour remplacer ou glissez un fichier sur cette zone. Une erreur inattendue s'est produite. Veuillez réessayer plus tard. Téléverser un PDF Nom d'utilisateur diff --git a/EnvelopeGenerator.Server/EnvelopeGenerator.Server.Client/Components/Sender/CreateEnvelopeWizardPopup.razor b/EnvelopeGenerator.Server/EnvelopeGenerator.Server.Client/Components/Sender/CreateEnvelopeWizardPopup.razor index aa9057bb..7db6eda2 100644 --- a/EnvelopeGenerator.Server/EnvelopeGenerator.Server.Client/Components/Sender/CreateEnvelopeWizardPopup.razor +++ b/EnvelopeGenerator.Server/EnvelopeGenerator.Server.Client/Components/Sender/CreateEnvelopeWizardPopup.razor @@ -28,387 +28,404 @@
- - - - @for (var step = 0; step < TotalSteps; step++) - { - var stepIndex = step; +
+ + + + @for (var step = 0; step < TotalSteps; step++) + { + var stepIndex = step; - -
@GetStepDescription(stepIndex)
- - @if (stepIndex == _currentStep) - { -
- @if (_currentStep == 0) - { -
-
- - -
- -
- - -
-
- } - else if (_currentStep == 3) - { -
-
- - -
- -
- - -
-
- } - else if (_currentStep == 2) - { -
-
-
- @L("SenderEditor_EnvelopeSettings", "Envelope-Einstellungen") -
+ +
@GetStepDescription(stepIndex)
+ @if (stepIndex == _currentStep) + { +
+
+
+ @if (_currentStep == 0) + {
- +
- + @foreach (var type in EnvelopeTypes) + { + + }
- -
- - -
- -
-
- - -
-
-
- -
-
- @L("SendReminderEmails", "Erinnerungs-E-Mails senden") -
- + } + else if (_currentStep == 3) + {
-
- +
- -
- - -
- -
- - -
- -
- - -
-
-
-
- } - else if (_currentStep == 1) - { -
- - - @if (_isLoadingRecentSuggestions) - { -
@L("Loading", "Lädt...")
- } - else if (_recentReceiverSuggestions.Count > 0) - { -
- @foreach (var suggestion in FilteredRecentSuggestions) - { - - }
} -
+ else if (_currentStep == 2) + { +
+
+
+ @L("SenderEditor_EnvelopeSettings", "Envelope-Einstellungen") +
-
-
-
- @for (var i = 0; i < _receivers.Count; i++) - { - var rowIndex = i; - var receiver = _receivers[rowIndex]; +
+
+ + +
-
-
-
- -
-
- +
+ + +
+ +
+ + +
+ +
+
+ +
-
- } -
-
-
- +
+ +
+
+ @L("SendReminderEmails", "Erinnerungs-E-Mails senden") +
+ +
+
+
+
- + + +
+ +
+ + +
+ +
+ + +
+ +
+ +
-
-
-
- } - else - { -
- - - @if (_documentBytes is not null) + } + else if (_currentStep == 1) { -
-
-
@_documentFileName
-
@_documentSizeText
-
-
- +
+ + + @if (_isLoadingRecentSuggestions) + { +
@L("Loading", "Lädt...")
+ } + else if (_recentReceiverSuggestions.Count > 0) + { +
+ @foreach (var suggestion in FilteredRecentSuggestions) + { + + } +
+ } +
+ +
+
+
+ @for (var i = 0; i < _receivers.Count; i++) + { + var rowIndex = i; + var receiver = _receivers[rowIndex]; + +
+
+
+ +
+
+ +
+
+ +
+ } +
+
+
+ +
+
+ +
+
+ +
+
} else { - +
+ + + @if (_documentBytes is not null) + { +
+
+
@_documentFileName
+
@_documentSizeText
+
+
+ +
+
+ } + else + { + + } +
}
- } +
} - - } - - - + + } + + + + + +
@if (!string.IsNullOrWhiteSpace(_validationMessage)) { @@ -507,6 +524,7 @@ private int _documentPreviewPageCount; private List _documentPreviewPages = []; private bool _isDocumentUploading; + private bool _isDocumentPreviewPrepared; private bool _isStepActionRunning; private bool _isFinishing; @@ -736,22 +754,12 @@ _documentBytes = ms.ToArray(); _documentFileName = file.Name; _documentSizeText = FormatSize(_documentBytes.Length); - _documentPreviewPages = []; - try - { - _documentPreviewPages = (await PdfRenderService.RenderPagesAsync(_documentBytes)) - .OrderBy(x => x.PageNumber) - .ToList(); - } - catch - { - _documentPreviewPages = []; - } + _documentPreviewPageCount = 0; + _isDocumentPreviewPrepared = false; - _documentPreviewPageCount = _documentPreviewPages.Count > 0 - ? _documentPreviewPages.Count - : EstimatePdfPageCount(_documentBytes) ?? 1; + if (_currentStep == 4) + await EnsureDocumentPreviewPreparedAsync(); } finally { @@ -792,6 +800,9 @@ if (_currentStep == 1) await EnsureRecentSuggestionsLoadedAsync(); + + if (_currentStep == 4) + await EnsureDocumentPreviewPreparedAsync(); } } finally @@ -948,6 +959,33 @@ await AddReceiver(); } + private async Task EnsureDocumentPreviewPreparedAsync() + { + if (_documentBytes is null || _documentBytes.Length == 0 || _isDocumentPreviewPrepared) + return; + + try + { + _isDocumentUploading = true; + _documentPreviewPages = (await PdfRenderService.RenderPagesAsync(_documentBytes)) + .OrderBy(x => x.PageNumber) + .ToList(); + } + catch + { + _documentPreviewPages = []; + } + finally + { + _documentPreviewPageCount = _documentPreviewPages.Count > 0 + ? _documentPreviewPages.Count + : EstimatePdfPageCount(_documentBytes) ?? 1; + + _isDocumentPreviewPrepared = true; + _isDocumentUploading = false; + } + } + private bool ValidateCurrentStep() { if (_currentStep == 0) @@ -1260,6 +1298,7 @@ _documentSizeText = string.Empty; _documentPreviewPageCount = 0; _documentPreviewPages = []; + _isDocumentPreviewPrepared = false; ApplyDefaultEnvelopeType(); } diff --git a/EnvelopeGenerator.Server/EnvelopeGenerator.Server.Client/Components/Sender/PdfFileDropZone.razor b/EnvelopeGenerator.Server/EnvelopeGenerator.Server.Client/Components/Sender/PdfFileDropZone.razor index 1cf0049c..065cfb8a 100644 --- a/EnvelopeGenerator.Server/EnvelopeGenerator.Server.Client/Components/Sender/PdfFileDropZone.razor +++ b/EnvelopeGenerator.Server/EnvelopeGenerator.Server.Client/Components/Sender/PdfFileDropZone.razor @@ -2,10 +2,24 @@
-
@CurrentActionText
- @if (!string.IsNullOrWhiteSpace(DragDropHintText)) + @if (HasDocument) { -
@DragDropHintText
+ @if (!string.IsNullOrWhiteSpace(DocumentName)) + { +
@DocumentName
+ } + @if (!string.IsNullOrWhiteSpace(DocumentSizeText)) + { +
@DocumentSizeText
+ } + @if (!string.IsNullOrWhiteSpace(UploadedHintText)) + { +
@UploadedHintText
+ } + } + else if (!string.IsNullOrWhiteSpace(CurrentActionText)) + { +
@CurrentActionText
}
@@ -38,6 +52,15 @@ [Parameter] public string DragDropHintText { get; set; } = "Datei hierhin ziehen oder klicken"; + [Parameter] + public string? DocumentName { get; set; } + + [Parameter] + public string? DocumentSizeText { get; set; } + + [Parameter] + public string UploadedHintText { get; set; } = "Zum Ersetzen klicken oder eine Datei hierher ziehen."; + [Parameter] public EventCallback FileSelected { get; set; } @@ -53,6 +76,9 @@ if (Disabled) return "sender-pdf-dropzone--disabled"; + if (HasDocument) + return "sender-pdf-dropzone--has-document"; + return _isDragActive ? "sender-pdf-dropzone--drag-active" : string.Empty; } } diff --git a/EnvelopeGenerator.Server/EnvelopeGenerator.Server/wwwroot/css/sender-page.css b/EnvelopeGenerator.Server/EnvelopeGenerator.Server/wwwroot/css/sender-page.css index 6094203d..53066101 100644 --- a/EnvelopeGenerator.Server/EnvelopeGenerator.Server/wwwroot/css/sender-page.css +++ b/EnvelopeGenerator.Server/EnvelopeGenerator.Server/wwwroot/css/sender-page.css @@ -1103,6 +1103,20 @@ outline: none; } +.sender-create-wizard__body-layout { + display: grid; + grid-template-columns: minmax(0, 1fr) minmax(240px, 280px); + gap: 0.85rem; + align-items: stretch; + min-height: min(66vh, 620px); + transition: grid-template-columns 220ms ease 0.2s, gap 220ms ease 0.2s; +} + +.sender-create-wizard__body-layout--document { + grid-template-columns: minmax(0, 1fr) 0; + gap: 0; +} + .sender-create-wizard-popup .dxbl-popup-content { max-height: min(78vh, 760px); overflow: auto; @@ -1121,6 +1135,7 @@ border-radius: 10px; background: rgba(126, 34, 206, 0.04); padding: 0.75rem; + height: 100%; } .sender-create-wizard__stepper { @@ -1214,6 +1229,47 @@ margin-top: 0.7rem; } +.sender-create-wizard__step-layout { + display: block; +} + +.sender-create-wizard__step-main { + min-width: 0; +} + +.sender-create-wizard__wizard-side { + min-width: 0; + max-width: 280px; + border: 1px solid rgba(126, 34, 206, 0.12); + border-radius: 10px; + background: rgba(126, 34, 206, 0.04); + padding: 0.75rem; + display: flex; + flex-direction: column; + justify-content: stretch; + opacity: 1; + transition: opacity 220ms ease 0.2s, transform 220ms ease 0.2s; +} + +.sender-create-wizard__wizard-side--hidden { + opacity: 0; + transform: translateX(12px); + pointer-events: none; +} + +.sender-create-wizard__body-layout--document .sender-create-wizard__wizard-side { + max-width: 0; + padding-left: 0; + padding-right: 0; + border-width: 0; + overflow: hidden; +} + +.sender-create-wizard__wizard-side .sender-pdf-dropzone { + height: 100%; + min-height: 100%; +} + .sender-create-wizard__meta { display: flex; flex-direction: column; @@ -1658,6 +1714,11 @@ box-shadow: 0 0 0 3px rgba(16, 185, 129, 0.16); } +.sender-pdf-dropzone--has-document { + border-color: rgba(16, 185, 129, 0.55); + background: linear-gradient(180deg, rgba(16, 185, 129, 0.16), rgba(16, 185, 129, 0.07)); +} + .sender-pdf-dropzone--disabled { opacity: 0.55; cursor: not-allowed; @@ -1680,6 +1741,18 @@ color: #64748b; } +.sender-pdf-dropzone__doc-name { + font-size: 0.82rem; + font-weight: 700; + color: #065f46; + line-height: 1.25; +} + +.sender-pdf-dropzone__doc-size { + font-size: 0.76rem; + color: #047857; +} + .sender-pdf-dropzone__input { position: absolute; inset: 0; @@ -1786,6 +1859,16 @@ width: 100%; } + .sender-create-wizard__body-layout { + grid-template-columns: 1fr; + gap: 0.7rem; + min-height: 0; + } + + .sender-create-wizard__wizard-side { + max-width: none; + } + .sender-create-wizard__receiver-remove-btn { align-self: flex-end; }