diff --git a/EnvelopeGenerator.ReceiverUI/Models/AnnotationDto.cs b/EnvelopeGenerator.ReceiverUI/Models/AnnotationDto.cs new file mode 100644 index 00000000..642cc6a9 --- /dev/null +++ b/EnvelopeGenerator.ReceiverUI/Models/AnnotationDto.cs @@ -0,0 +1,29 @@ +namespace EnvelopeGenerator.ReceiverUI.Models; + +/// +/// Represents a pre-assigned signature annotation position on a specific page. +///

+/// Coordinate unit (X, Y): Hundredths of an inch (1/100 inch ? 2.83 PDF points), +/// origin at the top-left corner of the page, both axes increase downward/rightward. +/// This matches the DevExpress XtraReports coordinate system (). +///

+/// Difference from PSPDFKit: Same origin (top-left) and direction, but PSPDFKit uses PDF points (1/72 inch). +/// Convert: xDX = xPsPdf * (100.0 / 72.0) +///
+/// Difference from GDPicture: GDPicture uses PDF points with bottom-left origin (PDF standard); Y is flipped. +/// Convert: yDX = (pageHeightPt - yGD - elemHeightPt) * (100.0 / 72.0) +///
+public record AnnotationDto +{ + /// Unique identifier of the annotation. + public long Id { get; init; } + + /// 1-based page number within the document. + public int? Page { get; init; } + + /// Horizontal position in hundredths of an inch from the left edge of the page. + public double? X { get; init; } + + /// Vertical position in hundredths of an inch from the top edge of the page. + public double? Y { get; init; } +} diff --git a/EnvelopeGenerator.ReceiverUI/Program.cs b/EnvelopeGenerator.ReceiverUI/Program.cs index 00b87dd5..2e54da86 100644 --- a/EnvelopeGenerator.ReceiverUI/Program.cs +++ b/EnvelopeGenerator.ReceiverUI/Program.cs @@ -16,6 +16,7 @@ builder.Services.Configure(opts => builder.Configuration.GetSection(ApiOptions.SectionName).Bind(opts)); builder.Services.AddScoped(); builder.Services.AddScoped(); +builder.Services.AddScoped(); builder.Services.AddDevExpressWebAssemblyBlazorReportViewer(); builder.Services.AddDevExpressWebAssemblyBlazorPdfViewer(); diff --git a/EnvelopeGenerator.ReceiverUI/Services/AnnotationService.cs b/EnvelopeGenerator.ReceiverUI/Services/AnnotationService.cs new file mode 100644 index 00000000..5fde8210 --- /dev/null +++ b/EnvelopeGenerator.ReceiverUI/Services/AnnotationService.cs @@ -0,0 +1,32 @@ +using System.Net.Http.Json; +using System.Text.Json; +using EnvelopeGenerator.ReceiverUI.Models; +using EnvelopeGenerator.ReceiverUI.Options; +using Microsoft.Extensions.Options; + +namespace EnvelopeGenerator.ReceiverUI.Services; + +/// +/// Retrieves annotation positions from the API. +/// The URL is composed as {BaseUrl}/api/Annotation/{envelopeKey}. +/// During development, BaseUrl is empty so the request resolves to the +/// YARP-proxied route on the same origin, which currently serves +/// fake-data/annotations.json. To switch to real data, update the +/// YARP route in yarp.json — no code change required. +/// +public class AnnotationService(HttpClient http, IOptions apiOptions) +{ + private static readonly JsonSerializerOptions _jsonOptions = new(JsonSerializerDefaults.Web); + + public async Task> GetAnnotationsAsync(string envelopeKey, CancellationToken cancel = default) + { + var url = $"{apiOptions.Value.BaseUrl}/api/Annotation/{Uri.EscapeDataString(envelopeKey)}"; + var response = await http.GetAsync(url, cancel); + + if (!response.IsSuccessStatusCode) + return []; + + var result = await response.Content.ReadFromJsonAsync>(_jsonOptions, cancel); + return result ?? []; + } +}