Add receiver management to EnvelopeSenderEditorPage

Introduced a new "Receivers" panel in `EnvelopeSenderEditorPage` to manage receivers. Added a popup for adding receivers with validation, email suggestions, and caching for performance. Updated the layout to display receiver details and signature fields.

Injected `EnvelopeReceiverPageDataService` for receiver-related operations. Added a `ReceiverDraft` model and implemented methods for managing receivers. Enhanced CSS for the new UI elements and ensured responsiveness. Minor refactoring and cleanup included.
This commit is contained in:
2026-07-01 16:32:28 +02:00
parent 6120e6062e
commit ca24a96084
3 changed files with 572 additions and 16 deletions

View File

@@ -4,12 +4,14 @@ using EnvelopeGenerator.Application.Common.Dto;
using EnvelopeGenerator.Application.Common.Dto.EnvelopeReceiver;
using EnvelopeGenerator.Application.Documents.Queries;
using EnvelopeGenerator.Application.EnvelopeReceivers.Queries;
using EnvelopeGenerator.Application.Receivers.Queries;
using EnvelopeGenerator.Server.Client.Models;
using EnvelopeGenerator.Server.Client.Models.Constants;
using EnvelopeGenerator.Server.Extensions;
using EnvelopeGenerator.Server.Options;
using MediatR;
using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Options;
using ApplicationEnvelopeReceiverDto = EnvelopeGenerator.Application.Common.Dto.EnvelopeReceiver.EnvelopeReceiverDto;
@@ -21,7 +23,8 @@ namespace EnvelopeGenerator.Server.Services;
public class EnvelopeReceiverPageDataService(
IMediator mediator,
IDistributedCache cache,
IOptions<CacheOptions> cacheOptions)
IOptions<CacheOptions> cacheOptions,
IMemoryCache memoryCache)
{
private const string SignatureCacheKeyPrefix = "envelope-generator.receiver-ui.signature:";
@@ -101,4 +104,23 @@ public class EnvelopeReceiverPageDataService(
Page = element.Page,
SenderAppType = (EnvelopeGenerator.Server.Client.Models.Constants.SenderAppType)element.SenderAppType
};
private static readonly string ReceiverEmailSearchCacheKey = Guid.NewGuid().ToString();
public async Task<IEnumerable<string>> SearchReceiverEMailsAsync(string emailSearchTerm, CancellationToken cancellationToken = default)
{
return await memoryCache.GetOrCreateAsync(ReceiverEmailSearchCacheKey + emailSearchTerm, async entry =>
{
var query = new ReadReceiverQuery { EmailAddressSearch = emailSearchTerm };
var receivers = await mediator.Send(query, cancellationToken);
if(receivers.Any())
entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(30);
else
entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(10);
return receivers.Select(r => r.EmailAddress);
}) ?? [];
}
}