Adding all the license feature and renewal

This commit is contained in:
Mulu Mehari
2026-08-03 12:49:48 +03:00
parent c62ec59655
commit 77bfb01664
21 changed files with 1256 additions and 59 deletions

View File

@@ -14,6 +14,7 @@ import type {
LicenseStatus,
LicenseType,
LicenseTypeRequirements,
OperatorType,
AssignableOfficer,
DocumentDecision,
DocumentReview,
@@ -54,6 +55,7 @@ function serialiseQueueFilter(
const TAGS = [
'LicenseType',
'OperatorType',
'LicenseApplication',
'ApplicationQueue',
'Attachment',
@@ -84,6 +86,33 @@ export const licensingApi = baseApi
providesTags: () => [listTag('LicenseType')],
}),
/**
* The signed-in applicant's declared modes of operation.
*
* Separate from the licence-type catalogue on purpose: the catalogue is
* the same for everyone and heavily cached, while this is per-user and
* changes the moment they edit their profile.
*/
getMyOperatorTypes: builder.query<{ items: OperatorType[] }, void>({
query: () => ({ url: '/profiles/me/operations' }),
providesTags: () => [listTag('OperatorType')],
}),
/** Replaces the set — see the Operations tab in the portal profile. */
updateMyOperatorTypes: builder.mutation<
{ items: OperatorType[] },
{ licenseTypeIds: string[] }
>({
query: (body) => ({
url: '/profiles/me/operations',
method: 'PUT',
body,
}),
// The catalogue is filtered by this, so it has to refetch too.
invalidatesTags: (_r, error) =>
error ? [] : [listTag('OperatorType'), listTag('LicenseType')],
}),
/**
* Category catalogue used to group the licence cards. Static on the
* server, so it is cached under the licence-type list tag.
@@ -758,4 +787,6 @@ export const {
useGetNotificationsQuery,
useGetUnseenNotificationsQuery,
useMarkNotificationReadMutation,
useGetMyOperatorTypesQuery,
useUpdateMyOperatorTypesMutation,
} = licensingApi;

View File

@@ -86,6 +86,19 @@ export interface LicenseCategoryDefinition {
sortOrder: number;
}
/**
* A mode of operation the applicant has declared — the licence types they may
* file new applications for. `key` and `name` are denormalised from the
* licence type so the profile screen can render the set without also loading
* the whole catalogue.
*/
export interface OperatorType {
licenseTypeId: string;
key: string | null;
name: Bilingual | null;
declaredAt: string | null;
}
export interface LicenseType {
id: string;
key: string;
@@ -442,6 +455,18 @@ export interface IssuedLicense {
issueDate: string;
expiryDate: string;
status: 'ACTIVE' | 'EXPIRED' | 'SUSPENDED' | 'CANCELLED' | 'SUPERSEDED';
/**
* Days until the expiry date; negative once it has passed. Computed by the
* API in the authority's timezone — the client must not re-derive it, since
* a browser in another zone would land on a different day.
*/
daysUntilExpiry?: number;
/**
* Whether a renewal can be filed now: inside the licence type's renewal
* window, or after expiry. The API decides, because the window is per-type
* configuration.
*/
renewable?: boolean;
verificationCode: string;
certificateFileKey: string | null;
}