PostIt: validate/refuse an estimate with a signature (pro or client)

Adds the client-side ability to open an estimate from the list, draw a
signature on a reusable SignaturePadView control, and accept or reject it
against /api/v1/front/query/accept|reject. The server resolves the actor
role (provider vs client) from the caller's identity, so the same page works
for either party.

- Yavsc.Api.Client: QueryAcceptanceDto + FrontOfficeApiClient (accept/reject)
- PostIt: extract SignaturePadView UserControl from SignaturePage; new
  EstimateValidationPage (VM + view) with Valider/Refuser/Effacer/Retour;
  wire OpenEstimate entry point from EstimateListPage; register client/page
  in DI + ViewLocator
- Tests: FrontOfficeApiClient + EstimateValidationPageViewModel unit tests;
  update EstimateListPageViewModelTests ctor

Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
Paul Schneider 2026-09-21 17:33:18 +01:00
commit 35c5a7f611
18 changed files with 1149 additions and 151 deletions

View file

@ -11,7 +11,8 @@ public class EstimateListPageViewModelTests
{
var api = new StubEstimateListApi();
var client = new EstimateApiClient(api, "https://business.example/api/v1/");
var vm = new EstimateListPageViewModel(client, EstimateListPerspective.Client);
var front = new FrontOfficeApiClient(api, "https://business.example/api/v1/");
var vm = new EstimateListPageViewModel(client, EstimateListPerspective.Client, front);
await vm.InitializeAsync();
@ -28,7 +29,8 @@ public class EstimateListPageViewModelTests
{
var api = new StubEstimateListApi();
var client = new EstimateApiClient(api, "https://business.example/api/v1/");
var vm = new EstimateListPageViewModel(client, EstimateListPerspective.Provider);
var front = new FrontOfficeApiClient(api, "https://business.example/api/v1/");
var vm = new EstimateListPageViewModel(client, EstimateListPerspective.Provider, front);
await vm.InitializeAsync();
@ -42,7 +44,8 @@ public class EstimateListPageViewModelTests
{
var api = new StubEstimateListApi();
var client = new EstimateApiClient(api, "https://business.example/api/v1/");
var vm = new EstimateListPageViewModel(client, EstimateListPerspective.Provider);
var front = new FrontOfficeApiClient(api, "https://business.example/api/v1/");
var vm = new EstimateListPageViewModel(client, EstimateListPerspective.Provider, front);
await vm.InitializeAsync();
@ -63,7 +66,8 @@ public class EstimateListPageViewModelTests
{
var api = new StubEstimateListApi { Empty = true };
var client = new EstimateApiClient(api, "https://business.example/api/v1/");
var vm = new EstimateListPageViewModel(client, EstimateListPerspective.Client);
var front = new FrontOfficeApiClient(api, "https://business.example/api/v1/");
var vm = new EstimateListPageViewModel(client, EstimateListPerspective.Client, front);
await vm.InitializeAsync();