feat(portal-frontend): add worklist and case-detail typed interfaces and API services
Types mirror New.Api.Contracts verbatim; all write calls use the href given in a case's actions block rather than a client-built URL.
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
import { ApplicationConfig, provideBrowserGlobalErrorListeners } from '@angular/core';
|
import { ApplicationConfig, provideBrowserGlobalErrorListeners } from '@angular/core';
|
||||||
|
import { provideHttpClient } from '@angular/common/http';
|
||||||
import { provideRouter } from '@angular/router';
|
import { provideRouter } from '@angular/router';
|
||||||
|
|
||||||
import { routes } from './app.routes';
|
import { routes } from './app.routes';
|
||||||
@@ -6,6 +7,7 @@ import { routes } from './app.routes';
|
|||||||
export const appConfig: ApplicationConfig = {
|
export const appConfig: ApplicationConfig = {
|
||||||
providers: [
|
providers: [
|
||||||
provideBrowserGlobalErrorListeners(),
|
provideBrowserGlobalErrorListeners(),
|
||||||
provideRouter(routes)
|
provideRouter(routes),
|
||||||
|
provideHttpClient()
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,43 @@
|
|||||||
|
import { HttpClient } from '@angular/common/http';
|
||||||
|
import { Injectable, inject } from '@angular/core';
|
||||||
|
import { Observable } from 'rxjs';
|
||||||
|
|
||||||
|
import {
|
||||||
|
ApplicantDetailsRequest,
|
||||||
|
CaseDetail,
|
||||||
|
RecordAssessmentRequest,
|
||||||
|
RecordAssessmentResult,
|
||||||
|
TakeOwnershipResult,
|
||||||
|
} from './case-detail.types';
|
||||||
|
|
||||||
|
@Injectable({ providedIn: 'root' })
|
||||||
|
export class CaseDetailService {
|
||||||
|
private readonly http = inject(HttpClient);
|
||||||
|
|
||||||
|
getLegacyDetail(aanvraagId: string): Observable<CaseDetail> {
|
||||||
|
return this.http.get<CaseDetail>(`/api/worklist/legacy/${aanvraagId}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
getOwnedDetail(registrationApplicationId: string): Observable<CaseDetail> {
|
||||||
|
return this.http.get<CaseDetail>(`/api/worklist/owned/${registrationApplicationId}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Every write below is issued against an `href` taken directly from the
|
||||||
|
// detail response's `actions` block, never a URL built from the id -
|
||||||
|
// that's the point of the HATEOAS-style contract (see ADR-002/003).
|
||||||
|
updateDetails(href: string, body: ApplicantDetailsRequest): Observable<void> {
|
||||||
|
return this.http.put<void>(href, body);
|
||||||
|
}
|
||||||
|
|
||||||
|
takeOwnership(href: string): Observable<TakeOwnershipResult> {
|
||||||
|
return this.http.post<TakeOwnershipResult>(href, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
releaseOwnership(href: string): Observable<void> {
|
||||||
|
return this.http.delete<void>(href);
|
||||||
|
}
|
||||||
|
|
||||||
|
recordAssessment(href: string, body: RecordAssessmentRequest): Observable<RecordAssessmentResult> {
|
||||||
|
return this.http.post<RecordAssessmentResult>(href, body);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
// Mirrors New.Api.Contracts.CaseDetailResponse and its request contracts
|
||||||
|
// (ApplicantDetailsRequest, RecordAssessmentRequest) verbatim. `actions`
|
||||||
|
// links (href) are always used as-is, never rebuilt client-side.
|
||||||
|
|
||||||
|
export interface ActionLink {
|
||||||
|
mode: string;
|
||||||
|
href: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CaseDetailActions {
|
||||||
|
editApplicantDetails: ActionLink;
|
||||||
|
recordAssessment: ActionLink;
|
||||||
|
takeOwnership?: ActionLink;
|
||||||
|
releaseOwnership?: ActionLink;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Address {
|
||||||
|
street: string;
|
||||||
|
number: string;
|
||||||
|
postalCode: string;
|
||||||
|
city: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Assessment {
|
||||||
|
outcome: string;
|
||||||
|
motivation: string;
|
||||||
|
verifiedItems: string[];
|
||||||
|
exceptionReason: string | null;
|
||||||
|
rejectionCategory: string | null;
|
||||||
|
decidedOn: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CaseDetail {
|
||||||
|
origin: 'Legacy' | 'Owned';
|
||||||
|
legacyAanvraagId: number | null;
|
||||||
|
registrationApplicationId: string | null;
|
||||||
|
surname: string;
|
||||||
|
initials: string;
|
||||||
|
bsn: string;
|
||||||
|
address: Address | null;
|
||||||
|
email: string | null;
|
||||||
|
phone: string | null;
|
||||||
|
preferredChannel: string;
|
||||||
|
diplomaCode: string;
|
||||||
|
diplomaCountryOfIssue: string;
|
||||||
|
diplomaIssuedOn: string;
|
||||||
|
receivedOn: string;
|
||||||
|
assessment: Assessment | null;
|
||||||
|
processStatus: string | null;
|
||||||
|
lastModifiedAt: string | null;
|
||||||
|
actions: CaseDetailActions;
|
||||||
|
seams: Record<string, string | null>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ApplicantDetailsRequest {
|
||||||
|
surname: string;
|
||||||
|
initials: string;
|
||||||
|
address: Address | null;
|
||||||
|
email: string | null;
|
||||||
|
phone: string | null;
|
||||||
|
preferredChannel: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface RecordAssessmentRequest {
|
||||||
|
verifiedItems: string[];
|
||||||
|
exceptionReason: string | null;
|
||||||
|
outcome: 'Approved' | 'Rejected';
|
||||||
|
rejectionCategory: string | null;
|
||||||
|
motivation: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface RecordAssessmentResult {
|
||||||
|
closurePending: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface TakeOwnershipResult {
|
||||||
|
registrationApplicationId: string;
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
// Mirrors New.Api.Contracts error shapes verbatim.
|
||||||
|
|
||||||
|
export interface FieldError {
|
||||||
|
field: string;
|
||||||
|
message: string;
|
||||||
|
detail?: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 400 - legacy write-through validation failures only (seam B). */
|
||||||
|
export interface ErrorsResponse {
|
||||||
|
errors: FieldError[];
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 422 - a single named domain-invariant failure. Render `invariant` and
|
||||||
|
* `message` as given; the set of invariants isn't fixed client-side
|
||||||
|
* knowledge (ADR-003), so no switch/enum maps over it. */
|
||||||
|
export interface InvariantViolationResponse {
|
||||||
|
invariant: string;
|
||||||
|
message: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 409 - a conflict, e.g. release-ownership blocked by prior domain writes. */
|
||||||
|
export interface MessageResponse {
|
||||||
|
message: string;
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
import { HttpClient, HttpParams } from '@angular/common/http';
|
||||||
|
import { Injectable, inject } from '@angular/core';
|
||||||
|
import { Observable } from 'rxjs';
|
||||||
|
|
||||||
|
import { WorklistPage, WorklistQuery } from './worklist.types';
|
||||||
|
|
||||||
|
@Injectable({ providedIn: 'root' })
|
||||||
|
export class WorklistService {
|
||||||
|
private readonly http = inject(HttpClient);
|
||||||
|
|
||||||
|
getWorklist(query: WorklistQuery = {}): Observable<WorklistPage> {
|
||||||
|
let params = new HttpParams();
|
||||||
|
if (query.bucket) params = params.set('bucket', query.bucket);
|
||||||
|
if (query.origin) params = params.set('origin', query.origin);
|
||||||
|
if (query.search) params = params.set('search', query.search);
|
||||||
|
return this.http.get<WorklistPage>('/api/worklist', { params });
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
// Mirrors New.Api.Contracts.WorklistItemResponse / WorklistPageResponse verbatim.
|
||||||
|
|
||||||
|
export interface WorklistItem {
|
||||||
|
origin: 'Legacy' | 'Owned';
|
||||||
|
legacyAanvraagId: number | null;
|
||||||
|
registrationApplicationId: string | null;
|
||||||
|
surname: string;
|
||||||
|
initials: string;
|
||||||
|
bsn: string;
|
||||||
|
receivedOn: string;
|
||||||
|
bucket: string;
|
||||||
|
assessmentOutcome: string | null;
|
||||||
|
processStatus: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface WorklistPage {
|
||||||
|
items: WorklistItem[];
|
||||||
|
page: number;
|
||||||
|
pageSize: number;
|
||||||
|
totalCount: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface WorklistQuery {
|
||||||
|
bucket?: string;
|
||||||
|
origin?: string;
|
||||||
|
search?: string;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user