Enhance PDF upload UX with progress and state handling
Refactor the PDF upload button to dynamically adjust its appearance and behavior based on `_isPageReady` and `_isPdfUploadInProgress` states. Add a spinner to indicate upload progress and disable the `<InputFile>` component during uploads or when the page is not ready. Introduce `_isPdfUploadInProgress` state to prevent multiple uploads and ensure consistent UI updates. Update the `OnPdfFileSelectedAsync` method to handle this state, including a `finally` block to reset it and trigger UI updates. Consolidate redundant code for disabled states and improve conditional rendering for better maintainability. Enhance visual feedback for loading states and make minor style adjustments for consistency.
This commit is contained in:
@@ -159,29 +159,43 @@
|
||||
</button>
|
||||
|
||||
@* PDF Upload *@
|
||||
@if (_isPageReady)
|
||||
{
|
||||
<label class="pdf-toolbar__btn"
|
||||
title='@L("UploadPdf", "PDF hochladen")'
|
||||
style="cursor: pointer; display: inline-flex; align-items: center; gap: 0.3rem; padding: 0.3rem 0.75rem; font-size: 0.75rem; font-weight: 500;">
|
||||
<label class="pdf-toolbar__btn"
|
||||
title='@L("UploadPdf", "PDF hochladen")'
|
||||
style="cursor: @((_isPageReady && !_isPdfUploadInProgress) ? "pointer" : "not-allowed");
|
||||
opacity:@((_isPageReady && !_isPdfUploadInProgress) ? "1" : "0.6");
|
||||
display: inline-flex; align-items: center; gap: 0.3rem; padding: 0.3rem 0.75rem; font-size: 0.75rem; font-weight: 500;">
|
||||
@if (_isPdfUploadInProgress)
|
||||
{
|
||||
<span class="spinner-border spinner-border-sm" role="status" style="width:0.8rem;height:0.8rem;border-width:2px;"></span>
|
||||
}
|
||||
else
|
||||
{
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" fill="currentColor" viewBox="0 0 16 16">
|
||||
<path d="M.5 9.9a.5.5 0 0 1 .5.5v2.5a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1v-2.5a.5.5 0 0 1 1 0v2.5a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2v-2.5a.5.5 0 0 1 .5-.5z" />
|
||||
<path d="M7.646 1.146a.5.5 0 0 1 .708 0l3 3a.5.5 0 0 1-.708.708L8.5 2.707V11.5a.5.5 0 0 1-1 0V2.707L5.354 4.854a.5.5 0 1 1-.708-.708l3-3z" />
|
||||
</svg>
|
||||
}
|
||||
@if (_isPdfUploadInProgress)
|
||||
{
|
||||
@L("UploadPdf", "PDF hochladen")
|
||||
<InputFile OnChange="OnPdfFileSelectedAsync"
|
||||
accept=".pdf"
|
||||
style="display: none;" />
|
||||
</label>
|
||||
}
|
||||
else
|
||||
{
|
||||
<span class="pdf-toolbar__btn"
|
||||
style="opacity:0.6; cursor:not-allowed; display: inline-flex; align-items: center; gap: 0.3rem; padding: 0.3rem 0.75rem; font-size: 0.75rem; font-weight: 500;">
|
||||
<span class="spinner-border spinner-border-sm" role="status" style="width:0.8rem;height:0.8rem;border-width:2px;"></span>
|
||||
@L("Loading", "Wird geladen")…
|
||||
</span>
|
||||
}
|
||||
@:
|
||||
@:...
|
||||
}
|
||||
else if (_isPageReady)
|
||||
{
|
||||
@L("UploadPdf", "PDF hochladen")
|
||||
}
|
||||
else
|
||||
{
|
||||
@L("Loading", "Wird geladen")
|
||||
@:
|
||||
@:...
|
||||
}
|
||||
<InputFile OnChange="OnPdfFileSelectedAsync"
|
||||
accept=".pdf"
|
||||
disabled="@(!_isPageReady || _isPdfUploadInProgress)"
|
||||
style="display: none;" />
|
||||
</label>
|
||||
|
||||
@if (_pdfLoaded && _signatureFields.Count > 0)
|
||||
{
|
||||
@@ -267,24 +281,42 @@
|
||||
<p class="text-white mb-4" style="opacity: 0.75; font-size: 0.85rem;">
|
||||
@L("SenderEditor_UploadPdfToPlaceFields", "Laden Sie eine PDF-Datei hoch, um Signaturfelder zu platzieren.")
|
||||
</p>
|
||||
@if (_isPageReady)
|
||||
{
|
||||
<label class="btn btn-light btn-sm" style="cursor: pointer; font-weight: 500;">
|
||||
<label class="btn btn-light btn-sm"
|
||||
style="cursor: @((_isPageReady && !_isPdfUploadInProgress) ? "pointer" : "not-allowed");
|
||||
opacity:@((_isPageReady && !_isPdfUploadInProgress) ? "1" : "0.8");
|
||||
font-weight: 500;">
|
||||
@if (_isPdfUploadInProgress)
|
||||
{
|
||||
<span class="spinner-border spinner-border-sm me-1" role="status" style="width:0.8rem;height:0.8rem;border-width:2px;"></span>
|
||||
}
|
||||
else
|
||||
{
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" fill="currentColor" class="me-1" viewBox="0 0 16 16">
|
||||
<path d="M.5 9.9a.5.5 0 0 1 .5.5v2.5a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1v-2.5a.5.5 0 0 1 1 0v2.5a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2v-2.5a.5.5 0 0 1 .5-.5z" />
|
||||
<path d="M7.646 1.146a.5.5 0 0 1 .708 0l3 3a.5.5 0 0 1-.708.708L8.5 2.707V11.5a.5.5 0 0 1-1 0V2.707L5.354 4.854a.5.5 0 1 1-.708-.708l3-3z" />
|
||||
</svg>
|
||||
}
|
||||
@if (_isPdfUploadInProgress)
|
||||
{
|
||||
@L("UploadPdf", "PDF hochladen")
|
||||
<InputFile OnChange="OnPdfFileSelectedAsync" accept=".pdf" style="display: none;" />
|
||||
</label>
|
||||
}
|
||||
else
|
||||
{
|
||||
<button class="btn btn-light btn-sm" type="button" disabled>
|
||||
<span class="spinner-border spinner-border-sm me-1" role="status" style="width:0.8rem;height:0.8rem;border-width:2px;"></span>
|
||||
@L("Loading", "Wird geladen")…
|
||||
</button>
|
||||
}
|
||||
@:
|
||||
@:...
|
||||
}
|
||||
else if (_isPageReady)
|
||||
{
|
||||
@L("UploadPdf", "PDF hochladen")
|
||||
}
|
||||
else
|
||||
{
|
||||
@L("Loading", "Wird geladen")
|
||||
@:
|
||||
@:...
|
||||
}
|
||||
<InputFile OnChange="OnPdfFileSelectedAsync"
|
||||
accept=".pdf"
|
||||
disabled="@(!_isPageReady || _isPdfUploadInProgress)"
|
||||
style="display: none;" />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
@@ -490,6 +522,7 @@
|
||||
// ── State ──
|
||||
bool _pdfLoaded = false;
|
||||
bool _isPageReady;
|
||||
bool _isPdfUploadInProgress;
|
||||
string _fileName = string.Empty;
|
||||
string? _errorMessage;
|
||||
byte[]? _originalPdfBytes; // Pristine upload — never modified, used as base for redraw
|
||||
@@ -658,6 +691,9 @@
|
||||
if (!_isPageReady)
|
||||
return;
|
||||
|
||||
if (_isPdfUploadInProgress)
|
||||
return;
|
||||
|
||||
_errorMessage = null;
|
||||
var file = e.File;
|
||||
if (file is null) return;
|
||||
@@ -670,6 +706,9 @@
|
||||
|
||||
try
|
||||
{
|
||||
_isPdfUploadInProgress = true;
|
||||
await InvokeAsync(StateHasChanged);
|
||||
|
||||
const long maxBytes = 50 * 1024 * 1024;
|
||||
using var ms = new System.IO.MemoryStream();
|
||||
await file.OpenReadStream(maxBytes).CopyToAsync(ms);
|
||||
@@ -695,6 +734,11 @@
|
||||
ex.Message);
|
||||
Logger.LogError(ex, "Failed to load PDF file");
|
||||
}
|
||||
finally
|
||||
{
|
||||
_isPdfUploadInProgress = false;
|
||||
await InvokeAsync(StateHasChanged);
|
||||
}
|
||||
}
|
||||
|
||||
// ── Placement mode ──
|
||||
|
||||
Reference in New Issue
Block a user