From e960c02cd4a8bd406641523c9e20a9b619bc0b7d Mon Sep 17 00:00:00 2001 From: TekH Date: Mon, 28 Sep 2026 12:47:37 +0200 Subject: [PATCH] Add AccessCode feature to EnvelopeSenderPage UI Introduced a new `AccessCode` property in `EnvelopeReceiverDto` to support displaying and copying access codes in the envelope sender page. - Updated `EnvelopeReceiverDto` to include the nullable `AccessCode` property. - Enhanced `EnvelopeSenderPage.razor` to display the `AccessCode` for each receiver, with a copy-to-clipboard button. - Implemented `CopyAccessCodeAsync` for clipboard functionality using JavaScript interop. - Styled the `AccessCode` section in `sender-page.css` for a responsive and user-friendly design. - Improved error handling for clipboard operations with console warnings. These changes improve the user experience by allowing senders to view and copy access codes for receivers. --- .../EnvelopeReceiver/EnvelopeReceiverDto.cs | 7 +- .../Components/Pages/EnvelopeSenderPage.razor | 35 ++++++++++ .../wwwroot/css/sender-page.css | 69 +++++++++++++++++++ 3 files changed, 110 insertions(+), 1 deletion(-) diff --git a/EnvelopeGenerator.Application/Common/Dto/EnvelopeReceiver/EnvelopeReceiverDto.cs b/EnvelopeGenerator.Application/Common/Dto/EnvelopeReceiver/EnvelopeReceiverDto.cs index b75722d9..86153648 100644 --- a/EnvelopeGenerator.Application/Common/Dto/EnvelopeReceiver/EnvelopeReceiverDto.cs +++ b/EnvelopeGenerator.Application/Common/Dto/EnvelopeReceiver/EnvelopeReceiverDto.cs @@ -60,6 +60,11 @@ public record EnvelopeReceiverDto /// public string? PrivateMessage { get; init; } + /// + /// + /// + public string? AccessCode { get; init; } + /// /// /// @@ -83,4 +88,4 @@ public record EnvelopeReceiverDto h.Receiver?.Id == ReceiverId && h.Status == EnvelopeStatus.DocumentSigned ) ?? false; -} \ No newline at end of file +} diff --git a/EnvelopeGenerator.Server/EnvelopeGenerator.Server/Components/Pages/EnvelopeSenderPage.razor b/EnvelopeGenerator.Server/EnvelopeGenerator.Server/Components/Pages/EnvelopeSenderPage.razor index 77bdbeaf..20c248ee 100644 --- a/EnvelopeGenerator.Server/EnvelopeGenerator.Server/Components/Pages/EnvelopeSenderPage.razor +++ b/EnvelopeGenerator.Server/EnvelopeGenerator.Server/Components/Pages/EnvelopeSenderPage.razor @@ -315,6 +315,8 @@
@{ var isSigned = IsReceiverSigned(envelope, receiver); + var accessCode = receiver.AccessCode; + var hasAccessCode = !string.IsNullOrWhiteSpace(accessCode); } @if (isSigned) @@ -337,6 +339,24 @@ @receiver.Name @receiver.Receiver?.EmailAddress
+
+ @L("AccessCode", "Access code") +
+ + +
+
} @@ -840,6 +860,21 @@ return value.ResourceNotFound ? fallback : value.Value; } + async Task CopyAccessCodeAsync(string? accessCode) + { + if (string.IsNullOrWhiteSpace(accessCode)) + return; + + try + { + await JSRuntime.InvokeVoidAsync("navigator.clipboard.writeText", accessCode); + } + catch + { + await JSRuntime.InvokeVoidAsync("console.warn", "[Sender] Failed to copy access code to clipboard."); + } + } + void OnCustomizeElement(GridCustomizeElementEventArgs e) { // Future: Add custom row coloring based on status if needed diff --git a/EnvelopeGenerator.Server/EnvelopeGenerator.Server/wwwroot/css/sender-page.css b/EnvelopeGenerator.Server/EnvelopeGenerator.Server/wwwroot/css/sender-page.css index e121770a..dce4848c 100644 --- a/EnvelopeGenerator.Server/EnvelopeGenerator.Server/wwwroot/css/sender-page.css +++ b/EnvelopeGenerator.Server/EnvelopeGenerator.Server/wwwroot/css/sender-page.css @@ -382,6 +382,71 @@ color: #c62828; } +.sender-access-code { + min-width: 120px; + display: flex; + flex-direction: column; + gap: 0.25rem; +} + +.sender-access-code__label { + font-size: 0.7rem; + font-weight: 700; + letter-spacing: 0.02em; + text-transform: uppercase; + color: #64748b; +} + +.sender-access-code__row { + display: flex; + align-items: center; + gap: 0; +} + +.sender-access-code__value { + width: 72px; + height: 28px; + border: 1px solid rgba(126, 34, 206, 0.22); + border-right: none; + border-radius: 6px 0 0 6px; + padding: 0 0.55rem; + font-size: 0.8rem; + font-weight: 600; + color: #1e293b; + background: #f8fafc; +} + +.sender-access-code__value:focus { + outline: 2px solid rgba(126, 34, 206, 0.18); + border-color: rgba(126, 34, 206, 0.45); +} + +.sender-access-code__copy { + height: 28px; + border: 1px solid rgba(126, 34, 206, 0.3); + border-radius: 0 6px 6px 0; + width: 30px; + min-width: 30px; + padding: 0; + display: inline-flex; + align-items: center; + justify-content: center; + color: #4c1d95; + background: rgba(126, 34, 206, 0.08); + cursor: pointer; + transition: all 0.2s ease; +} + +.sender-access-code__copy:hover:not(:disabled) { + border-color: rgba(126, 34, 206, 0.45); + background: rgba(126, 34, 206, 0.16); +} + +.sender-access-code__copy:disabled { + opacity: 0.45; + cursor: not-allowed; +} + .sender-history-list { display: flex; flex-direction: column; @@ -521,6 +586,10 @@ padding: 0.875rem 1rem; font-size: 0.813rem; } + + .sender-access-code { + min-width: 100%; + } } @media (max-width: 560px) {