Refactor envelope receiver auth flow and state handling
- Introduce IReceiverAuthService and ReceiverAuthService for all envelope receiver authentication and status API calls - Add ReceiverAuthModel as a client-side DTO for API responses - Refactor EnvelopeState to store all relevant fields and update via ApplyApiResponse - Overhaul EnvelopePage.razor to use new service and state, with improved status handling and UI - Enhance ApiResponse and ApiServiceBase to support structured error deserialization - Register IReceiverAuthService in DI container
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
@page "/envelope/{EnvelopeKey}"
|
||||
@rendermode InteractiveAuto
|
||||
@inject IEnvelopeService EnvelopeService
|
||||
@inject IReceiverAuthService ReceiverAuthService
|
||||
@inject EnvelopeState State
|
||||
@implements IDisposable
|
||||
|
||||
@@ -13,24 +13,59 @@
|
||||
break;
|
||||
|
||||
case EnvelopePageStatus.NotFound:
|
||||
<ErrorDisplay Title="Nicht gefunden"
|
||||
Message="Dieses Dokument existiert nicht oder ist nicht mehr verfügbar." />
|
||||
<StatusPage Type="not_found" />
|
||||
break;
|
||||
|
||||
case EnvelopePageStatus.AlreadySigned:
|
||||
<ErrorDisplay Title="Bereits unterschrieben"
|
||||
Message="Dieses Dokument wurde bereits unterschrieben."
|
||||
Icon="check-circle" />
|
||||
<StatusPage Type="signed"
|
||||
Title="@State.Title"
|
||||
SenderEmail="@State.SenderEmail" />
|
||||
break;
|
||||
|
||||
case EnvelopePageStatus.Rejected:
|
||||
<StatusPage Type="rejected"
|
||||
Title="@State.Title"
|
||||
SenderEmail="@State.SenderEmail" />
|
||||
break;
|
||||
|
||||
case EnvelopePageStatus.Expired:
|
||||
<StatusPage Type="expired" />
|
||||
break;
|
||||
|
||||
case EnvelopePageStatus.RequiresAccessCode:
|
||||
<AccessCodeForm EnvelopeKey="@EnvelopeKey"
|
||||
ErrorMessage="@State.ErrorMessage"
|
||||
SenderEmail="@State.SenderEmail"
|
||||
Title="@State.Title"
|
||||
TfaEnabled="@State.TfaEnabled"
|
||||
HasPhoneNumber="@State.HasPhoneNumber"
|
||||
OnSubmit="HandleAccessCodeSubmit" />
|
||||
break;
|
||||
|
||||
case EnvelopePageStatus.RequiresTwoFactor:
|
||||
<TfaForm EnvelopeKey="@EnvelopeKey"
|
||||
TfaType="@(State.TfaType ?? "authenticator")"
|
||||
TfaExpiration="@State.TfaExpiration"
|
||||
HasPhoneNumber="@State.HasPhoneNumber"
|
||||
ErrorMessage="@State.ErrorMessage"
|
||||
OnSubmit="HandleTfaSubmit" />
|
||||
break;
|
||||
|
||||
case EnvelopePageStatus.ShowDocument:
|
||||
<PdfViewer DocumentBytes="@_documentBytes" />
|
||||
@* Phase 4 (PSPDFKit) kommt später — vorerst Platzhalter *@
|
||||
<div class="text-center mt-5">
|
||||
<div class="status-icon signed">
|
||||
<i class="bi bi-file-earmark-check"></i>
|
||||
</div>
|
||||
<h2>Dokument bereit</h2>
|
||||
<p class="text-muted">
|
||||
«@State.Title» — PDF-Viewer wird in Phase 4 integriert.
|
||||
</p>
|
||||
@if (State.ReadOnly)
|
||||
{
|
||||
<span class="badge bg-secondary">Nur Lesen</span>
|
||||
}
|
||||
</div>
|
||||
break;
|
||||
|
||||
case EnvelopePageStatus.Error:
|
||||
@@ -41,44 +76,83 @@
|
||||
@code {
|
||||
[Parameter] public string EnvelopeKey { get; set; } = default!;
|
||||
|
||||
private byte[]? _documentBytes;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
State.OnChange += StateHasChanged;
|
||||
await LoadEnvelopeAsync();
|
||||
}
|
||||
|
||||
private async Task LoadEnvelopeAsync()
|
||||
{
|
||||
State.SetLoading();
|
||||
|
||||
var result = await EnvelopeService.GetEnvelopeReceiversAsync();
|
||||
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
if (result.StatusCode == 401)
|
||||
State.SetAccessCodeRequired();
|
||||
else if (result.StatusCode == 404)
|
||||
State.SetNotFound();
|
||||
else
|
||||
State.SetError(result.ErrorMessage ?? "Unbekannter Fehler");
|
||||
return;
|
||||
}
|
||||
|
||||
State.SetDocument();
|
||||
await LoadStatusAsync();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Empfängt das Tuple (Code, PreferSms) von AccessCodeForm.OnSubmit.
|
||||
/// AccessCodeForm gibt immer ein Tuple zurück, weil es auch den
|
||||
/// SMS-Toggle-Zustand enthält (für TFA).
|
||||
/// Erster API-Call: Status prüfen.
|
||||
/// Entspricht dem GET /Envelope/{key} im Web-Projekt.
|
||||
/// Die API entscheidet, was passiert (AccessCode nötig? Bereits signiert? etc.)
|
||||
/// </summary>
|
||||
private async Task LoadStatusAsync()
|
||||
{
|
||||
State.SetLoading();
|
||||
|
||||
var result = await ReceiverAuthService.GetStatusAsync(EnvelopeKey);
|
||||
|
||||
if (result.IsSuccess && result.Data is not null)
|
||||
{
|
||||
State.ApplyApiResponse(result.Data);
|
||||
}
|
||||
else if (result.StatusCode == 404)
|
||||
{
|
||||
State.SetNotFound();
|
||||
}
|
||||
else
|
||||
{
|
||||
State.SetError(result.ErrorMessage ?? "Verbindung zum Server fehlgeschlagen.");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Zweiter API-Call: AccessCode senden.
|
||||
/// Wird von AccessCodeForm aufgerufen (OnSubmit-Callback).
|
||||
/// Die API prüft den Code und antwortet mit dem nächsten Status.
|
||||
/// </summary>
|
||||
private async Task HandleAccessCodeSubmit((string Code, bool PreferSms) submission)
|
||||
{
|
||||
// AccessCode an API senden
|
||||
// Bei Erfolg: State.SetDocument() oder State.SetTwoFactorRequired()
|
||||
// Bei Fehler: State.SetError(...)
|
||||
var result = await ReceiverAuthService.SubmitAccessCodeAsync(
|
||||
EnvelopeKey, submission.Code, submission.PreferSms);
|
||||
|
||||
if (result.IsSuccess && result.Data is not null)
|
||||
{
|
||||
State.ApplyApiResponse(result.Data);
|
||||
}
|
||||
else if (result.Data is not null)
|
||||
{
|
||||
// 401 mit Body → falscher Code, API gibt trotzdem ReceiverAuthModel zurück
|
||||
State.ApplyApiResponse(result.Data);
|
||||
}
|
||||
else
|
||||
{
|
||||
State.SetError(result.ErrorMessage ?? "Fehler bei der Code-Prüfung.");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Dritter API-Call: TFA-Code senden.
|
||||
/// Wird von TfaForm aufgerufen (OnSubmit-Callback).
|
||||
/// </summary>
|
||||
private async Task HandleTfaSubmit((string Code, string Type) submission)
|
||||
{
|
||||
var result = await ReceiverAuthService.SubmitTfaCodeAsync(
|
||||
EnvelopeKey, submission.Code, submission.Type);
|
||||
|
||||
if (result.IsSuccess && result.Data is not null)
|
||||
{
|
||||
State.ApplyApiResponse(result.Data);
|
||||
}
|
||||
else if (result.Data is not null)
|
||||
{
|
||||
State.ApplyApiResponse(result.Data);
|
||||
}
|
||||
else
|
||||
{
|
||||
State.SetError(result.ErrorMessage ?? "Fehler bei der TFA-Prüfung.");
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose() => State.OnChange -= StateHasChanged;
|
||||
|
||||
Reference in New Issue
Block a user