- 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
130 lines
4.4 KiB
C#
130 lines
4.4 KiB
C#
using EnvelopeGenerator.ReceiverUI.Client.Models;
|
|
|
|
namespace EnvelopeGenerator.ReceiverUI.Client.State;
|
|
|
|
/// <summary>
|
|
/// Hält den aktuellen Zustand des geladenen Umschlags.
|
|
///
|
|
/// WARUM ein eigenes State-Objekt?
|
|
/// - Mehrere Komponenten auf einer Seite brauchen die gleichen Daten
|
|
/// - Ohne State müsste jede Komponente die Daten selbst laden → doppelte API-Calls
|
|
/// - StateHasChanged() informiert automatisch alle Subscriber
|
|
///
|
|
/// PATTERN: "Observable State" — Services setzen den State, Komponenten reagieren darauf.
|
|
///
|
|
/// Die Set-Methoden nehmen jetzt ein ReceiverAuthModel entgegen,
|
|
/// damit alle Felder (Title, SenderEmail, TfaType etc.) zentral gespeichert werden.
|
|
/// </summary>
|
|
public class EnvelopeState
|
|
{
|
|
private EnvelopePageStatus _status = EnvelopePageStatus.Loading;
|
|
|
|
/// <summary>Aktueller Seitenstatus</summary>
|
|
public EnvelopePageStatus Status
|
|
{
|
|
get => _status;
|
|
private set
|
|
{
|
|
_status = value;
|
|
NotifyStateChanged();
|
|
}
|
|
}
|
|
|
|
// ── Felder aus ReceiverAuthModel ──
|
|
|
|
/// <summary>Titel des Umschlags (z.B. "Vertragsdokument")</summary>
|
|
public string? Title { get; private set; }
|
|
|
|
/// <summary>Nachricht des Absenders</summary>
|
|
public string? Message { get; private set; }
|
|
|
|
/// <summary>E-Mail des Absenders (für Rückfragen-Hinweis)</summary>
|
|
public string? SenderEmail { get; private set; }
|
|
|
|
/// <summary>Ob TFA für diesen Umschlag aktiviert ist</summary>
|
|
public bool TfaEnabled { get; private set; }
|
|
|
|
/// <summary>Ob der Empfänger eine Telefonnummer hat (für SMS-TFA)</summary>
|
|
public bool HasPhoneNumber { get; private set; }
|
|
|
|
/// <summary>Ob das Dokument nur gelesen werden soll (ReadAndConfirm)</summary>
|
|
public bool ReadOnly { get; private set; }
|
|
|
|
/// <summary>TFA-Typ: "sms" oder "authenticator"</summary>
|
|
public string? TfaType { get; private set; }
|
|
|
|
/// <summary>Ablaufzeit des SMS-Codes (für Countdown-Timer)</summary>
|
|
public DateTime? TfaExpiration { get; private set; }
|
|
|
|
/// <summary>Fehlermeldung (z.B. "Falscher Zugangscode")</summary>
|
|
public string? ErrorMessage { get; private set; }
|
|
|
|
// ── Zustandsübergänge ──
|
|
|
|
public void SetLoading()
|
|
{
|
|
ErrorMessage = null;
|
|
Status = EnvelopePageStatus.Loading;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Setzt den State aus einer API-Antwort.
|
|
/// Zentrale Methode — alle Endpunkte liefern ReceiverAuthModel,
|
|
/// und diese Methode mappt den Status-String auf das richtige Enum.
|
|
/// </summary>
|
|
public void ApplyApiResponse(ReceiverAuthModel model)
|
|
{
|
|
// Gemeinsame Felder immer übernehmen
|
|
Title = model.Title ?? Title;
|
|
Message = model.Message ?? Message;
|
|
SenderEmail = model.SenderEmail ?? SenderEmail;
|
|
TfaEnabled = model.TfaEnabled;
|
|
HasPhoneNumber = model.HasPhoneNumber;
|
|
ReadOnly = model.ReadOnly;
|
|
TfaType = model.TfaType ?? TfaType;
|
|
TfaExpiration = model.TfaExpiration ?? TfaExpiration;
|
|
ErrorMessage = model.ErrorMessage;
|
|
|
|
// Status-String → Enum
|
|
Status = model.Status switch
|
|
{
|
|
"requires_access_code" => EnvelopePageStatus.RequiresAccessCode,
|
|
"requires_tfa" => EnvelopePageStatus.RequiresTwoFactor,
|
|
"show_document" => EnvelopePageStatus.ShowDocument,
|
|
"already_signed" => EnvelopePageStatus.AlreadySigned,
|
|
"rejected" => EnvelopePageStatus.Rejected,
|
|
"not_found" => EnvelopePageStatus.NotFound,
|
|
"expired" => EnvelopePageStatus.Expired,
|
|
"error" => EnvelopePageStatus.Error,
|
|
_ => EnvelopePageStatus.Error
|
|
};
|
|
}
|
|
|
|
/// <summary>Setzt Fehler wenn der API-Call selbst fehlschlägt (Netzwerk etc.)</summary>
|
|
public void SetError(string message)
|
|
{
|
|
ErrorMessage = message;
|
|
Status = EnvelopePageStatus.Error;
|
|
}
|
|
|
|
/// <summary>Setzt NotFound (z.B. bei 404 ohne Body)</summary>
|
|
public void SetNotFound() => Status = EnvelopePageStatus.NotFound;
|
|
|
|
// ── Event ──
|
|
public event Action? OnChange;
|
|
private void NotifyStateChanged() => OnChange?.Invoke();
|
|
}
|
|
|
|
/// <summary>Alle möglichen Zustände der Umschlag-Seite</summary>
|
|
public enum EnvelopePageStatus
|
|
{
|
|
Loading,
|
|
RequiresAccessCode,
|
|
RequiresTwoFactor,
|
|
ShowDocument,
|
|
AlreadySigned,
|
|
Rejected,
|
|
NotFound,
|
|
Expired,
|
|
Error
|
|
} |