Mijn aanvragen (C): FE contracts + applications adapter + parse boundary
- Regenerate the NSwag client against the new backend endpoints (application + content methods, Aanvraag DTOs) — clears the API-client drift. - registratie/domain/aanvraag.ts: FE domain view — AanvraagType + AanvraagStatus discriminated union (illegal states unrepresentable) + Aanvraag/AanvraagDetail. Lives in registratie: the dashboard consumes it, downstream wizards produce it. - ApplicationsAdapter (infrastructure, the only new network surface): list resource + create/syncDraft/cancel/submit commands, with a hand-written parse* boundary (parseAanvraagStatus/parseApplicationSummary/parseApplications/parseApplicationDetail) mapping untrusted DTO -> domain, per ADR-0001. Spec covers each status tag + rejects. - UploadAdapter.contentUrl(id): direct href for preview/download (browser opens it). Gates green: dotnet test 56, vitest 122, lint, build. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -312,6 +312,31 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/api/v1/uploads/{documentId}/content": {
|
||||||
|
"get": {
|
||||||
|
"tags": [
|
||||||
|
"BigRegister.Api, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"
|
||||||
|
],
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"name": "documentId",
|
||||||
|
"in": "path",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK"
|
||||||
|
},
|
||||||
|
"404": {
|
||||||
|
"description": "Not Found"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"/api/v1/uploads/status": {
|
"/api/v1/uploads/status": {
|
||||||
"get": {
|
"get": {
|
||||||
"tags": [
|
"tags": [
|
||||||
@@ -402,6 +427,205 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"/api/v1/applications": {
|
||||||
|
"get": {
|
||||||
|
"tags": [
|
||||||
|
"BigRegister.Api, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/components/schemas/ApplicationSummaryDto"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"post": {
|
||||||
|
"tags": [
|
||||||
|
"BigRegister.Api, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"
|
||||||
|
],
|
||||||
|
"requestBody": {
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/CreateApplicationRequest"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
"responses": {
|
||||||
|
"201": {
|
||||||
|
"description": "Created",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/ApplicationDetailDto"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/api/v1/applications/{id}": {
|
||||||
|
"get": {
|
||||||
|
"tags": [
|
||||||
|
"BigRegister.Api, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"
|
||||||
|
],
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"name": "id",
|
||||||
|
"in": "path",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/ApplicationDetailDto"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"404": {
|
||||||
|
"description": "Not Found"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"put": {
|
||||||
|
"tags": [
|
||||||
|
"BigRegister.Api, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"
|
||||||
|
],
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"name": "id",
|
||||||
|
"in": "path",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"requestBody": {
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/DraftSyncRequest"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
"responses": {
|
||||||
|
"204": {
|
||||||
|
"description": "No Content"
|
||||||
|
},
|
||||||
|
"404": {
|
||||||
|
"description": "Not Found"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"delete": {
|
||||||
|
"tags": [
|
||||||
|
"BigRegister.Api, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"
|
||||||
|
],
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"name": "id",
|
||||||
|
"in": "path",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"204": {
|
||||||
|
"description": "No Content"
|
||||||
|
},
|
||||||
|
"409": {
|
||||||
|
"description": "Conflict",
|
||||||
|
"content": {
|
||||||
|
"application/problem+json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/ProblemDetails"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"404": {
|
||||||
|
"description": "Not Found"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/api/v1/applications/{id}/submit": {
|
||||||
|
"post": {
|
||||||
|
"tags": [
|
||||||
|
"BigRegister.Api, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"
|
||||||
|
],
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"name": "id",
|
||||||
|
"in": "path",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"requestBody": {
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/SubmitApplicationRequest"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/SubmitApplicationResponse"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"409": {
|
||||||
|
"description": "Conflict",
|
||||||
|
"content": {
|
||||||
|
"application/problem+json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/ProblemDetails"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"404": {
|
||||||
|
"description": "Not Found"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"components": {
|
"components": {
|
||||||
@@ -424,6 +648,38 @@
|
|||||||
},
|
},
|
||||||
"additionalProperties": false
|
"additionalProperties": false
|
||||||
},
|
},
|
||||||
|
"AanvraagStatusDto": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"tag": {
|
||||||
|
"type": "string",
|
||||||
|
"nullable": true
|
||||||
|
},
|
||||||
|
"stepIndex": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int32",
|
||||||
|
"nullable": true
|
||||||
|
},
|
||||||
|
"stepCount": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int32",
|
||||||
|
"nullable": true
|
||||||
|
},
|
||||||
|
"referentie": {
|
||||||
|
"type": "string",
|
||||||
|
"nullable": true
|
||||||
|
},
|
||||||
|
"manual": {
|
||||||
|
"type": "boolean",
|
||||||
|
"nullable": true
|
||||||
|
},
|
||||||
|
"reden": {
|
||||||
|
"type": "string",
|
||||||
|
"nullable": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
"AdresDto": {
|
"AdresDto": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
@@ -442,6 +698,81 @@
|
|||||||
},
|
},
|
||||||
"additionalProperties": false
|
"additionalProperties": false
|
||||||
},
|
},
|
||||||
|
"ApplicationDetailDto": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"type": "string",
|
||||||
|
"nullable": true
|
||||||
|
},
|
||||||
|
"type": {
|
||||||
|
"type": "string",
|
||||||
|
"nullable": true
|
||||||
|
},
|
||||||
|
"status": {
|
||||||
|
"$ref": "#/components/schemas/AanvraagStatusDto"
|
||||||
|
},
|
||||||
|
"draft": {
|
||||||
|
"nullable": true
|
||||||
|
},
|
||||||
|
"documentIds": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"nullable": true
|
||||||
|
},
|
||||||
|
"createdAt": {
|
||||||
|
"type": "string",
|
||||||
|
"nullable": true
|
||||||
|
},
|
||||||
|
"updatedAt": {
|
||||||
|
"type": "string",
|
||||||
|
"nullable": true
|
||||||
|
},
|
||||||
|
"submittedAt": {
|
||||||
|
"type": "string",
|
||||||
|
"nullable": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
|
"ApplicationSummaryDto": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"type": "string",
|
||||||
|
"nullable": true
|
||||||
|
},
|
||||||
|
"type": {
|
||||||
|
"type": "string",
|
||||||
|
"nullable": true
|
||||||
|
},
|
||||||
|
"status": {
|
||||||
|
"$ref": "#/components/schemas/AanvraagStatusDto"
|
||||||
|
},
|
||||||
|
"documentIds": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"nullable": true
|
||||||
|
},
|
||||||
|
"createdAt": {
|
||||||
|
"type": "string",
|
||||||
|
"nullable": true
|
||||||
|
},
|
||||||
|
"updatedAt": {
|
||||||
|
"type": "string",
|
||||||
|
"nullable": true
|
||||||
|
},
|
||||||
|
"submittedAt": {
|
||||||
|
"type": "string",
|
||||||
|
"nullable": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
"BrpAddressDto": {
|
"BrpAddressDto": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
@@ -472,6 +803,16 @@
|
|||||||
},
|
},
|
||||||
"additionalProperties": false
|
"additionalProperties": false
|
||||||
},
|
},
|
||||||
|
"CreateApplicationRequest": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"type": {
|
||||||
|
"type": "string",
|
||||||
|
"nullable": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
"DashboardViewDto": {
|
"DashboardViewDto": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
@@ -543,6 +884,28 @@
|
|||||||
},
|
},
|
||||||
"additionalProperties": false
|
"additionalProperties": false
|
||||||
},
|
},
|
||||||
|
"DraftSyncRequest": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"draft": { },
|
||||||
|
"stepIndex": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int32"
|
||||||
|
},
|
||||||
|
"stepCount": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int32"
|
||||||
|
},
|
||||||
|
"documentIds": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"nullable": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
"DuoDiplomaDto": {
|
"DuoDiplomaDto": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
@@ -806,6 +1169,41 @@
|
|||||||
},
|
},
|
||||||
"additionalProperties": false
|
"additionalProperties": false
|
||||||
},
|
},
|
||||||
|
"SubmitApplicationRequest": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"diplomaHerkomst": {
|
||||||
|
"type": "string",
|
||||||
|
"nullable": true
|
||||||
|
},
|
||||||
|
"uren": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int32",
|
||||||
|
"nullable": true
|
||||||
|
},
|
||||||
|
"documents": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/components/schemas/DocumentRefDto"
|
||||||
|
},
|
||||||
|
"nullable": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
|
"SubmitApplicationResponse": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"referentie": {
|
||||||
|
"type": "string",
|
||||||
|
"nullable": true
|
||||||
|
},
|
||||||
|
"status": {
|
||||||
|
"$ref": "#/components/schemas/AanvraagStatusDto"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
"UploadCategoriesDto": {
|
"UploadCategoriesDto": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|||||||
32
src/app/registratie/domain/aanvraag.ts
Normal file
32
src/app/registratie/domain/aanvraag.ts
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
/**
|
||||||
|
* An application (aanvraag) as the frontend sees it — the parsed, domain-side view
|
||||||
|
* of the backend-owned aggregate (see backend ApplicationStore + PRD 0001). Pure
|
||||||
|
* types, no Angular. Lives in `registratie` because the dashboard (here) is the
|
||||||
|
* consumer and the downstream wizards (`herregistratie → registratie`) produce them.
|
||||||
|
*
|
||||||
|
* The status is a discriminated union so illegal states are unrepresentable — same
|
||||||
|
* reflex as RemoteData. The server computes which tag applies (auto-approval on
|
||||||
|
* read); the FE renders it, it does not recompute the lifecycle.
|
||||||
|
*/
|
||||||
|
export type AanvraagType = 'registratie' | 'herregistratie' | 'intake';
|
||||||
|
|
||||||
|
export type AanvraagStatus =
|
||||||
|
| { tag: 'Concept'; stepIndex: number; stepCount: number }
|
||||||
|
| { tag: 'InBehandeling'; referentie: string; manual: boolean } // manual=true → "wordt handmatig beoordeeld"
|
||||||
|
| { tag: 'Goedgekeurd'; referentie: string }
|
||||||
|
| { tag: 'Afgewezen'; referentie: string; reden: string };
|
||||||
|
|
||||||
|
export interface Aanvraag {
|
||||||
|
id: string;
|
||||||
|
type: AanvraagType;
|
||||||
|
status: AanvraagStatus;
|
||||||
|
documentIds: string[];
|
||||||
|
createdAt: string;
|
||||||
|
updatedAt: string;
|
||||||
|
submittedAt?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Detail adds the opaque wizard snapshot used to resume a Concept. */
|
||||||
|
export interface AanvraagDetail extends Aanvraag {
|
||||||
|
draft: unknown;
|
||||||
|
}
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
import { describe, it, expect } from 'vitest';
|
||||||
|
import { parseAanvraagStatus, parseApplicationSummary, parseApplications, parseApplicationDetail } from './applications.adapter';
|
||||||
|
|
||||||
|
const concept = { id: 'a1', type: 'registratie', status: { tag: 'Concept', stepIndex: 1, stepCount: 4 }, documentIds: [], createdAt: '2026-07-01T10:00:00Z', updatedAt: '2026-07-01T10:05:00Z' };
|
||||||
|
|
||||||
|
describe('parseAanvraagStatus', () => {
|
||||||
|
it('parses each tag with its required fields', () => {
|
||||||
|
expect(parseAanvraagStatus({ tag: 'Concept', stepIndex: 2, stepCount: 4 })).toEqual({ ok: true, value: { tag: 'Concept', stepIndex: 2, stepCount: 4 } });
|
||||||
|
expect(parseAanvraagStatus({ tag: 'InBehandeling', referentie: 'BIG-1', manual: true }).ok).toBe(true);
|
||||||
|
expect(parseAanvraagStatus({ tag: 'Goedgekeurd', referentie: 'BIG-1' }).ok).toBe(true);
|
||||||
|
expect(parseAanvraagStatus({ tag: 'Afgewezen', referentie: 'BIG-1', reden: 'geen uren' }).ok).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('rejects a missing status, unknown tag, and wrong-typed fields', () => {
|
||||||
|
expect(parseAanvraagStatus(undefined).ok).toBe(false);
|
||||||
|
expect(parseAanvraagStatus({ tag: 'Onzin' }).ok).toBe(false);
|
||||||
|
expect(parseAanvraagStatus({ tag: 'InBehandeling', referentie: 'BIG-1' }).ok).toBe(false); // manual missing
|
||||||
|
expect(parseAanvraagStatus({ tag: 'Concept', stepIndex: 1 }).ok).toBe(false); // stepCount missing
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('parseApplicationSummary', () => {
|
||||||
|
it('maps a valid DTO to domain', () => {
|
||||||
|
const r = parseApplicationSummary(concept);
|
||||||
|
expect(r.ok && r.value.type).toBe('registratie');
|
||||||
|
expect(r.ok && r.value.status.tag).toBe('Concept');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('rejects a bad type and non-objects', () => {
|
||||||
|
expect(parseApplicationSummary({ ...concept, type: 'onbekend' }).ok).toBe(false);
|
||||||
|
expect(parseApplicationSummary(null).ok).toBe(false);
|
||||||
|
expect(parseApplicationSummary({ ...concept, id: 42 }).ok).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('parseApplications / parseApplicationDetail', () => {
|
||||||
|
it('parses a list and fails fast on a bad element', () => {
|
||||||
|
expect(parseApplications([concept, concept]).ok).toBe(true);
|
||||||
|
expect(parseApplications([concept, { ...concept, status: { tag: 'x' } }]).ok).toBe(false);
|
||||||
|
expect(parseApplications({}).ok).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('carries the opaque draft through detail', () => {
|
||||||
|
const r = parseApplicationDetail({ ...concept, draft: { beroep: 'arts' } });
|
||||||
|
expect(r.ok && (r.value.draft as { beroep: string }).beroep).toBe('arts');
|
||||||
|
});
|
||||||
|
});
|
||||||
115
src/app/registratie/infrastructure/applications.adapter.ts
Normal file
115
src/app/registratie/infrastructure/applications.adapter.ts
Normal file
@@ -0,0 +1,115 @@
|
|||||||
|
import { Injectable, inject, resource } from '@angular/core';
|
||||||
|
import { Result, ok, err } from '@shared/kernel/fp';
|
||||||
|
import {
|
||||||
|
ApiClient,
|
||||||
|
AanvraagStatusDto,
|
||||||
|
ApplicationSummaryDto,
|
||||||
|
ApplicationDetailDto,
|
||||||
|
DraftSyncRequest,
|
||||||
|
SubmitApplicationRequest,
|
||||||
|
SubmitApplicationResponse,
|
||||||
|
} from '@shared/infrastructure/api-client';
|
||||||
|
import { Aanvraag, AanvraagDetail, AanvraagStatus, AanvraagType } from '@registratie/domain/aanvraag';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Infrastructure adapter for the backend-owned Aanvraag aggregate — the only place
|
||||||
|
* its HTTP lives (ADR-0001 anti-corruption boundary). The list is a resource; the
|
||||||
|
* mutations (create/sync/cancel/submit) are thin commands the ApplicationsStore
|
||||||
|
* orchestrates optimistically. The untrusted response is validated + mapped to
|
||||||
|
* domain by the hand-written parse* boundary below.
|
||||||
|
*/
|
||||||
|
@Injectable({ providedIn: 'root' })
|
||||||
|
export class ApplicationsAdapter {
|
||||||
|
private client = inject(ApiClient);
|
||||||
|
|
||||||
|
/** The dashboard's application list (raw DTOs; the store parses at the boundary). */
|
||||||
|
applicationsResource() {
|
||||||
|
return resource({ loader: () => this.client.applicationsAll() });
|
||||||
|
}
|
||||||
|
|
||||||
|
detail(id: string): Promise<ApplicationDetailDto> {
|
||||||
|
return this.client.applicationsGET(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Create a Concept for a wizard type; resolves to the new aanvraag id. */
|
||||||
|
create(type: AanvraagType): Promise<string> {
|
||||||
|
return this.client.applicationsPOST({ type }).then((d) => d.id ?? '');
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Draft sync per step (idempotent). Keep it debounced at the call site — it is chatty. */
|
||||||
|
syncDraft(id: string, body: DraftSyncRequest): Promise<void> {
|
||||||
|
return this.client.applicationsPUT(id, body);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Cancel a Concept (cascades to its unlinked documents server-side). */
|
||||||
|
cancel(id: string): Promise<void> {
|
||||||
|
return this.client.applicationsDELETE(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
submit(id: string, body: SubmitApplicationRequest): Promise<SubmitApplicationResponse> {
|
||||||
|
return this.client.submit(id, body);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const AANVRAAG_TYPES: readonly string[] = ['registratie', 'herregistratie', 'intake'];
|
||||||
|
|
||||||
|
/** Trust-boundary parse of the status union — the tag drives which fields must exist. */
|
||||||
|
export function parseAanvraagStatus(s: AanvraagStatusDto | undefined): Result<string, AanvraagStatus> {
|
||||||
|
if (!s || typeof s.tag !== 'string') return err('aanvraag: missing status');
|
||||||
|
switch (s.tag) {
|
||||||
|
case 'Concept':
|
||||||
|
if (typeof s.stepIndex !== 'number' || typeof s.stepCount !== 'number') return err('aanvraag: bad Concept status');
|
||||||
|
return ok({ tag: 'Concept', stepIndex: s.stepIndex, stepCount: s.stepCount });
|
||||||
|
case 'InBehandeling':
|
||||||
|
if (typeof s.referentie !== 'string' || typeof s.manual !== 'boolean') return err('aanvraag: bad InBehandeling status');
|
||||||
|
return ok({ tag: 'InBehandeling', referentie: s.referentie, manual: s.manual });
|
||||||
|
case 'Goedgekeurd':
|
||||||
|
if (typeof s.referentie !== 'string') return err('aanvraag: bad Goedgekeurd status');
|
||||||
|
return ok({ tag: 'Goedgekeurd', referentie: s.referentie });
|
||||||
|
case 'Afgewezen':
|
||||||
|
if (typeof s.referentie !== 'string' || typeof s.reden !== 'string') return err('aanvraag: bad Afgewezen status');
|
||||||
|
return ok({ tag: 'Afgewezen', referentie: s.referentie, reden: s.reden });
|
||||||
|
default:
|
||||||
|
return err(`aanvraag: unknown status tag ${s.tag}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseCommon(dto: ApplicationSummaryDto): Result<string, Aanvraag> {
|
||||||
|
if (typeof dto.id !== 'string') return err('aanvraag: missing id');
|
||||||
|
if (typeof dto.type !== 'string' || !AANVRAAG_TYPES.includes(dto.type)) return err(`aanvraag: bad type ${dto.type}`);
|
||||||
|
if (typeof dto.createdAt !== 'string' || typeof dto.updatedAt !== 'string') return err('aanvraag: missing timestamps');
|
||||||
|
const status = parseAanvraagStatus(dto.status);
|
||||||
|
if (!status.ok) return status;
|
||||||
|
return ok({
|
||||||
|
id: dto.id,
|
||||||
|
type: dto.type as AanvraagType,
|
||||||
|
status: status.value,
|
||||||
|
documentIds: dto.documentIds ?? [],
|
||||||
|
createdAt: dto.createdAt,
|
||||||
|
updatedAt: dto.updatedAt,
|
||||||
|
submittedAt: dto.submittedAt,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function parseApplicationSummary(json: unknown): Result<string, Aanvraag> {
|
||||||
|
if (typeof json !== 'object' || json === null) return err('aanvraag: not an object');
|
||||||
|
return parseCommon(json as ApplicationSummaryDto);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function parseApplications(json: unknown): Result<string, Aanvraag[]> {
|
||||||
|
if (!Array.isArray(json)) return err('aanvragen: not an array');
|
||||||
|
const out: Aanvraag[] = [];
|
||||||
|
for (const item of json) {
|
||||||
|
const parsed = parseApplicationSummary(item);
|
||||||
|
if (!parsed.ok) return parsed;
|
||||||
|
out.push(parsed.value);
|
||||||
|
}
|
||||||
|
return ok(out);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function parseApplicationDetail(json: unknown): Result<string, AanvraagDetail> {
|
||||||
|
if (typeof json !== 'object' || json === null) return err('aanvraag: not an object');
|
||||||
|
const base = parseCommon(json as ApplicationDetailDto);
|
||||||
|
if (!base.ok) return base;
|
||||||
|
return ok({ ...base.value, draft: (json as ApplicationDetailDto).draft ?? null });
|
||||||
|
}
|
||||||
@@ -487,6 +487,46 @@ export class ApiClient {
|
|||||||
return Promise.resolve<UploadCategoriesDto>(null as any);
|
return Promise.resolve<UploadCategoriesDto>(null as any);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return OK
|
||||||
|
*/
|
||||||
|
content(documentId: string): Promise<void> {
|
||||||
|
let url_ = this.baseUrl + "/api/v1/uploads/{documentId}/content";
|
||||||
|
if (documentId === undefined || documentId === null)
|
||||||
|
throw new globalThis.Error("The parameter 'documentId' must be defined.");
|
||||||
|
url_ = url_.replace("{documentId}", encodeURIComponent("" + documentId));
|
||||||
|
url_ = url_.replace(/[?&]$/, "");
|
||||||
|
|
||||||
|
let options_: RequestInit = {
|
||||||
|
method: "GET",
|
||||||
|
headers: {
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return this.http.fetch(url_, options_).then((_response: Response) => {
|
||||||
|
return this.processContent(_response);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected processContent(response: Response): Promise<void> {
|
||||||
|
const status = response.status;
|
||||||
|
let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); };
|
||||||
|
if (status === 200) {
|
||||||
|
return response.text().then((_responseText) => {
|
||||||
|
return;
|
||||||
|
});
|
||||||
|
} else if (status === 404) {
|
||||||
|
return response.text().then((_responseText) => {
|
||||||
|
return throwException("Not Found", status, _responseText, _headers);
|
||||||
|
});
|
||||||
|
} else if (status !== 200 && status !== 204) {
|
||||||
|
return response.text().then((_responseText) => {
|
||||||
|
return throwException("An unexpected server error occurred.", status, _responseText, _headers);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return Promise.resolve<void>(null as any);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param localIds (optional)
|
* @param localIds (optional)
|
||||||
* @return OK
|
* @return OK
|
||||||
@@ -617,6 +657,268 @@ export class ApiClient {
|
|||||||
}
|
}
|
||||||
return Promise.resolve<void>(null as any);
|
return Promise.resolve<void>(null as any);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return OK
|
||||||
|
*/
|
||||||
|
applicationsAll(): Promise<ApplicationSummaryDto[]> {
|
||||||
|
let url_ = this.baseUrl + "/api/v1/applications";
|
||||||
|
url_ = url_.replace(/[?&]$/, "");
|
||||||
|
|
||||||
|
let options_: RequestInit = {
|
||||||
|
method: "GET",
|
||||||
|
headers: {
|
||||||
|
"Accept": "application/json"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return this.http.fetch(url_, options_).then((_response: Response) => {
|
||||||
|
return this.processApplicationsAll(_response);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected processApplicationsAll(response: Response): Promise<ApplicationSummaryDto[]> {
|
||||||
|
const status = response.status;
|
||||||
|
let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); };
|
||||||
|
if (status === 200) {
|
||||||
|
return response.text().then((_responseText) => {
|
||||||
|
let result200: any = null;
|
||||||
|
result200 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver) as ApplicationSummaryDto[];
|
||||||
|
return result200;
|
||||||
|
});
|
||||||
|
} else if (status !== 200 && status !== 204) {
|
||||||
|
return response.text().then((_responseText) => {
|
||||||
|
return throwException("An unexpected server error occurred.", status, _responseText, _headers);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return Promise.resolve<ApplicationSummaryDto[]>(null as any);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Created
|
||||||
|
*/
|
||||||
|
applicationsPOST(body: CreateApplicationRequest): Promise<ApplicationDetailDto> {
|
||||||
|
let url_ = this.baseUrl + "/api/v1/applications";
|
||||||
|
url_ = url_.replace(/[?&]$/, "");
|
||||||
|
|
||||||
|
const content_ = JSON.stringify(body);
|
||||||
|
|
||||||
|
let options_: RequestInit = {
|
||||||
|
body: content_,
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
"Accept": "application/json"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return this.http.fetch(url_, options_).then((_response: Response) => {
|
||||||
|
return this.processApplicationsPOST(_response);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected processApplicationsPOST(response: Response): Promise<ApplicationDetailDto> {
|
||||||
|
const status = response.status;
|
||||||
|
let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); };
|
||||||
|
if (status === 201) {
|
||||||
|
return response.text().then((_responseText) => {
|
||||||
|
let result201: any = null;
|
||||||
|
result201 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver) as ApplicationDetailDto;
|
||||||
|
return result201;
|
||||||
|
});
|
||||||
|
} else if (status !== 200 && status !== 204) {
|
||||||
|
return response.text().then((_responseText) => {
|
||||||
|
return throwException("An unexpected server error occurred.", status, _responseText, _headers);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return Promise.resolve<ApplicationDetailDto>(null as any);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return OK
|
||||||
|
*/
|
||||||
|
applicationsGET(id: string): Promise<ApplicationDetailDto> {
|
||||||
|
let url_ = this.baseUrl + "/api/v1/applications/{id}";
|
||||||
|
if (id === undefined || id === null)
|
||||||
|
throw new globalThis.Error("The parameter 'id' must be defined.");
|
||||||
|
url_ = url_.replace("{id}", encodeURIComponent("" + id));
|
||||||
|
url_ = url_.replace(/[?&]$/, "");
|
||||||
|
|
||||||
|
let options_: RequestInit = {
|
||||||
|
method: "GET",
|
||||||
|
headers: {
|
||||||
|
"Accept": "application/json"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return this.http.fetch(url_, options_).then((_response: Response) => {
|
||||||
|
return this.processApplicationsGET(_response);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected processApplicationsGET(response: Response): Promise<ApplicationDetailDto> {
|
||||||
|
const status = response.status;
|
||||||
|
let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); };
|
||||||
|
if (status === 200) {
|
||||||
|
return response.text().then((_responseText) => {
|
||||||
|
let result200: any = null;
|
||||||
|
result200 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver) as ApplicationDetailDto;
|
||||||
|
return result200;
|
||||||
|
});
|
||||||
|
} else if (status === 404) {
|
||||||
|
return response.text().then((_responseText) => {
|
||||||
|
return throwException("Not Found", status, _responseText, _headers);
|
||||||
|
});
|
||||||
|
} else if (status !== 200 && status !== 204) {
|
||||||
|
return response.text().then((_responseText) => {
|
||||||
|
return throwException("An unexpected server error occurred.", status, _responseText, _headers);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return Promise.resolve<ApplicationDetailDto>(null as any);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return No Content
|
||||||
|
*/
|
||||||
|
applicationsPUT(id: string, body: DraftSyncRequest): Promise<void> {
|
||||||
|
let url_ = this.baseUrl + "/api/v1/applications/{id}";
|
||||||
|
if (id === undefined || id === null)
|
||||||
|
throw new globalThis.Error("The parameter 'id' must be defined.");
|
||||||
|
url_ = url_.replace("{id}", encodeURIComponent("" + id));
|
||||||
|
url_ = url_.replace(/[?&]$/, "");
|
||||||
|
|
||||||
|
const content_ = JSON.stringify(body);
|
||||||
|
|
||||||
|
let options_: RequestInit = {
|
||||||
|
body: content_,
|
||||||
|
method: "PUT",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return this.http.fetch(url_, options_).then((_response: Response) => {
|
||||||
|
return this.processApplicationsPUT(_response);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected processApplicationsPUT(response: Response): Promise<void> {
|
||||||
|
const status = response.status;
|
||||||
|
let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); };
|
||||||
|
if (status === 204) {
|
||||||
|
return response.text().then((_responseText) => {
|
||||||
|
return;
|
||||||
|
});
|
||||||
|
} else if (status === 404) {
|
||||||
|
return response.text().then((_responseText) => {
|
||||||
|
return throwException("Not Found", status, _responseText, _headers);
|
||||||
|
});
|
||||||
|
} else if (status !== 200 && status !== 204) {
|
||||||
|
return response.text().then((_responseText) => {
|
||||||
|
return throwException("An unexpected server error occurred.", status, _responseText, _headers);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return Promise.resolve<void>(null as any);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return No Content
|
||||||
|
*/
|
||||||
|
applicationsDELETE(id: string): Promise<void> {
|
||||||
|
let url_ = this.baseUrl + "/api/v1/applications/{id}";
|
||||||
|
if (id === undefined || id === null)
|
||||||
|
throw new globalThis.Error("The parameter 'id' must be defined.");
|
||||||
|
url_ = url_.replace("{id}", encodeURIComponent("" + id));
|
||||||
|
url_ = url_.replace(/[?&]$/, "");
|
||||||
|
|
||||||
|
let options_: RequestInit = {
|
||||||
|
method: "DELETE",
|
||||||
|
headers: {
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return this.http.fetch(url_, options_).then((_response: Response) => {
|
||||||
|
return this.processApplicationsDELETE(_response);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected processApplicationsDELETE(response: Response): Promise<void> {
|
||||||
|
const status = response.status;
|
||||||
|
let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); };
|
||||||
|
if (status === 204) {
|
||||||
|
return response.text().then((_responseText) => {
|
||||||
|
return;
|
||||||
|
});
|
||||||
|
} else if (status === 404) {
|
||||||
|
return response.text().then((_responseText) => {
|
||||||
|
return throwException("Not Found", status, _responseText, _headers);
|
||||||
|
});
|
||||||
|
} else if (status === 409) {
|
||||||
|
return response.text().then((_responseText) => {
|
||||||
|
let result409: any = null;
|
||||||
|
result409 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver) as ProblemDetails;
|
||||||
|
return throwException("Conflict", status, _responseText, _headers, result409);
|
||||||
|
});
|
||||||
|
} else if (status !== 200 && status !== 204) {
|
||||||
|
return response.text().then((_responseText) => {
|
||||||
|
return throwException("An unexpected server error occurred.", status, _responseText, _headers);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return Promise.resolve<void>(null as any);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return OK
|
||||||
|
*/
|
||||||
|
submit(id: string, body: SubmitApplicationRequest): Promise<SubmitApplicationResponse> {
|
||||||
|
let url_ = this.baseUrl + "/api/v1/applications/{id}/submit";
|
||||||
|
if (id === undefined || id === null)
|
||||||
|
throw new globalThis.Error("The parameter 'id' must be defined.");
|
||||||
|
url_ = url_.replace("{id}", encodeURIComponent("" + id));
|
||||||
|
url_ = url_.replace(/[?&]$/, "");
|
||||||
|
|
||||||
|
const content_ = JSON.stringify(body);
|
||||||
|
|
||||||
|
let options_: RequestInit = {
|
||||||
|
body: content_,
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
"Accept": "application/json"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return this.http.fetch(url_, options_).then((_response: Response) => {
|
||||||
|
return this.processSubmit(_response);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected processSubmit(response: Response): Promise<SubmitApplicationResponse> {
|
||||||
|
const status = response.status;
|
||||||
|
let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); };
|
||||||
|
if (status === 200) {
|
||||||
|
return response.text().then((_responseText) => {
|
||||||
|
let result200: any = null;
|
||||||
|
result200 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver) as SubmitApplicationResponse;
|
||||||
|
return result200;
|
||||||
|
});
|
||||||
|
} else if (status === 404) {
|
||||||
|
return response.text().then((_responseText) => {
|
||||||
|
return throwException("Not Found", status, _responseText, _headers);
|
||||||
|
});
|
||||||
|
} else if (status === 409) {
|
||||||
|
return response.text().then((_responseText) => {
|
||||||
|
let result409: any = null;
|
||||||
|
result409 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver) as ProblemDetails;
|
||||||
|
return throwException("Conflict", status, _responseText, _headers, result409);
|
||||||
|
});
|
||||||
|
} else if (status !== 200 && status !== 204) {
|
||||||
|
return response.text().then((_responseText) => {
|
||||||
|
return throwException("An unexpected server error occurred.", status, _responseText, _headers);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return Promise.resolve<SubmitApplicationResponse>(null as any);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AantekeningDto {
|
export interface AantekeningDto {
|
||||||
@@ -625,12 +927,42 @@ export interface AantekeningDto {
|
|||||||
datum?: string | undefined;
|
datum?: string | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface AanvraagStatusDto {
|
||||||
|
tag?: string | undefined;
|
||||||
|
stepIndex?: number | undefined;
|
||||||
|
stepCount?: number | undefined;
|
||||||
|
referentie?: string | undefined;
|
||||||
|
manual?: boolean | undefined;
|
||||||
|
reden?: string | undefined;
|
||||||
|
}
|
||||||
|
|
||||||
export interface AdresDto {
|
export interface AdresDto {
|
||||||
straat?: string | undefined;
|
straat?: string | undefined;
|
||||||
postcode?: string | undefined;
|
postcode?: string | undefined;
|
||||||
woonplaats?: string | undefined;
|
woonplaats?: string | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface ApplicationDetailDto {
|
||||||
|
id?: string | undefined;
|
||||||
|
type?: string | undefined;
|
||||||
|
status?: AanvraagStatusDto;
|
||||||
|
draft?: any | undefined;
|
||||||
|
documentIds?: string[] | undefined;
|
||||||
|
createdAt?: string | undefined;
|
||||||
|
updatedAt?: string | undefined;
|
||||||
|
submittedAt?: string | undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ApplicationSummaryDto {
|
||||||
|
id?: string | undefined;
|
||||||
|
type?: string | undefined;
|
||||||
|
status?: AanvraagStatusDto;
|
||||||
|
documentIds?: string[] | undefined;
|
||||||
|
createdAt?: string | undefined;
|
||||||
|
updatedAt?: string | undefined;
|
||||||
|
submittedAt?: string | undefined;
|
||||||
|
}
|
||||||
|
|
||||||
export interface BrpAddressDto {
|
export interface BrpAddressDto {
|
||||||
gevonden?: boolean;
|
gevonden?: boolean;
|
||||||
adres?: AdresDto;
|
adres?: AdresDto;
|
||||||
@@ -642,6 +974,10 @@ export interface ChangeRequestRequest {
|
|||||||
woonplaats?: string | undefined;
|
woonplaats?: string | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface CreateApplicationRequest {
|
||||||
|
type?: string | undefined;
|
||||||
|
}
|
||||||
|
|
||||||
export interface DashboardViewDto {
|
export interface DashboardViewDto {
|
||||||
registration?: RegistrationDto;
|
registration?: RegistrationDto;
|
||||||
person?: PersonDto;
|
person?: PersonDto;
|
||||||
@@ -665,6 +1001,13 @@ export interface DocumentRefDto {
|
|||||||
documentId?: string | undefined;
|
documentId?: string | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface DraftSyncRequest {
|
||||||
|
draft?: any;
|
||||||
|
stepIndex?: number;
|
||||||
|
stepCount?: number;
|
||||||
|
documentIds?: string[] | undefined;
|
||||||
|
}
|
||||||
|
|
||||||
export interface DuoDiplomaDto {
|
export interface DuoDiplomaDto {
|
||||||
id?: string | undefined;
|
id?: string | undefined;
|
||||||
naam?: string | undefined;
|
naam?: string | undefined;
|
||||||
@@ -750,6 +1093,17 @@ export interface RegistrationStatusDto {
|
|||||||
doorgehaaldOp?: string | undefined;
|
doorgehaaldOp?: string | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface SubmitApplicationRequest {
|
||||||
|
diplomaHerkomst?: string | undefined;
|
||||||
|
uren?: number | undefined;
|
||||||
|
documents?: DocumentRefDto[] | undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SubmitApplicationResponse {
|
||||||
|
referentie?: string | undefined;
|
||||||
|
status?: AanvraagStatusDto;
|
||||||
|
}
|
||||||
|
|
||||||
export interface UploadCategoriesDto {
|
export interface UploadCategoriesDto {
|
||||||
categories?: DocumentCategoryDto[] | undefined;
|
categories?: DocumentCategoryDto[] | undefined;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -57,6 +57,15 @@ export class UploadAdapter {
|
|||||||
return this.client.uploads(documentId);
|
return this.client.uploads(documentId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Direct URL to the stored bytes, for a preview/download link (`<a href>`) — the
|
||||||
|
* server serves it inline for pdf/image, attachment otherwise. Not a fetch: the
|
||||||
|
* browser opens it. demo-* ids (dev simulation) have no bytes and 404 here.
|
||||||
|
*/
|
||||||
|
contentUrl(documentId: string): string {
|
||||||
|
return `${environment.apiBaseUrl}/api/v1/uploads/${documentId}/content`;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Multipart upload with progress + cancel. ponytail: XHR (not fetch keepalive) —
|
* Multipart upload with progress + cancel. ponytail: XHR (not fetch keepalive) —
|
||||||
* progress events need XHR; the keepalive/background gap is covered by
|
* progress events need XHR; the keepalive/background gap is covered by
|
||||||
|
|||||||
Reference in New Issue
Block a user