Merge branch 'dev' of github.com:Tria-plc/emaui into fix/coc-exam-workflow-defects

This commit is contained in:
mihretue
2026-08-31 14:20:32 +03:00
15 changed files with 786 additions and 51 deletions

View File

@@ -40,6 +40,7 @@ import type {
SavedQueueView,
SchemaIssue,
ServiceKind,
StaffRoleRequirement,
TemplateFieldPlacement,
TemplateLogoPlacement,
TemplatePageOptions,
@@ -99,6 +100,7 @@ const TAGS = [
'PickupAppointment',
'Department',
'Rank',
'StaffRoleRequirement',
// Owned by the personal-document slice; named here so declaring a mode of
// operation can invalidate the vault, whose slots depend on it.
'PersonalDocument',
@@ -366,6 +368,42 @@ export const licensingApi = baseApi
invalidatesTags: (_r, error) => (error ? [] : [listTag('DocumentRequirement')]),
}),
// ----------------------------------------------- staff role requirements
/**
* Every staff role requirement, filtered by licence type at the call
* site — same reasoning as `getDocumentRequirements`: small
* configuration data with no pagination need.
*/
getStaffRoleRequirements: builder.query<Paginated<StaffRoleRequirement>, void>({
query: () => ({ url: '/staff-role-requirements' }),
providesTags: () => [listTag('StaffRoleRequirement')],
}),
createStaffRoleRequirement: builder.mutation<
StaffRoleRequirement,
Partial<StaffRoleRequirement> & { licenseTypeId: string; roleKey: string; name: StaffRoleRequirement['name'] }
>({
query: (body) => ({ url: '/staff-role-requirements', method: 'POST', body }),
invalidatesTags: (_r, error) => (error ? [] : [listTag('StaffRoleRequirement')]),
}),
updateStaffRoleRequirement: builder.mutation<
StaffRoleRequirement,
{ id: string } & Partial<StaffRoleRequirement>
>({
query: ({ id, ...body }) => ({
url: `/staff-role-requirements/${id}`,
method: 'PUT',
body,
}),
invalidatesTags: (_r, error) => (error ? [] : [listTag('StaffRoleRequirement')]),
}),
deleteStaffRoleRequirement: builder.mutation<unknown, string>({
query: (id) => ({ url: `/staff-role-requirements/${id}`, method: 'DELETE' }),
invalidatesTags: (_r, error) => (error ? [] : [listTag('StaffRoleRequirement')]),
}),
// --------------------------------------------------- departments & ranks
/** Every department, for the admin editor. */
getDepartments: builder.query<Paginated<Department>, void>({
@@ -524,6 +562,36 @@ export const licensingApi = baseApi
providesTags: (_r, _e, arg) => [itemTag('Attachment', arg.ownerId)],
}),
/**
* Copies the applicant's personal documents onto an application, for
* every requirement their vault answers and this application has not
* already got. Idempotent — a filled slot is never touched.
*/
fillApplicationDocumentsFromVault: builder.mutation<
{ filled: string[] },
string
>({
query: (applicationId) => ({
url: `/license-applications/${applicationId}/documents/fill-from-vault`,
method: 'POST',
}),
invalidatesTags: (_r, error, applicationId) =>
error ? [] : [itemTag('Attachment', applicationId)],
}),
/** The same, for a seafarer registration. */
fillRegistrationDocumentsFromVault: builder.mutation<
{ filled: string[] },
string
>({
query: (registrationId) => ({
url: `/seafarer-registrations/${registrationId}/documents/fill-from-vault`,
method: 'POST',
}),
invalidatesTags: (_r, error, registrationId) =>
error ? [] : [itemTag('Attachment', registrationId)],
}),
deleteAttachment: builder.mutation<unknown, { attachmentId: string; ownerId: string }>({
query: ({ attachmentId }) => ({
url: `/attachments/${attachmentId}`,
@@ -1289,6 +1357,10 @@ export const {
useCreateDocumentRequirementMutation,
useUpdateDocumentRequirementMutation,
useDeleteDocumentRequirementMutation,
useGetStaffRoleRequirementsQuery,
useCreateStaffRoleRequirementMutation,
useUpdateStaffRoleRequirementMutation,
useDeleteStaffRoleRequirementMutation,
useGetDepartmentsQuery,
useGetActiveDepartmentsQuery,
useCreateDepartmentMutation,
@@ -1321,6 +1393,8 @@ export const {
useResolveRemarkMutation,
useResubmitApplicationMutation,
useGetAttachmentsQuery,
useFillApplicationDocumentsFromVaultMutation,
useFillRegistrationDocumentsFromVaultMutation,
useDeleteAttachmentMutation,
useGetQueueQuery,
useGetAssignedToMeQuery,

View File

@@ -109,6 +109,14 @@ export interface FormFieldConfig {
showWhen?: FieldCondition;
readOnly?: boolean;
source?: string;
/**
* Marks `min` as bound to live configuration rather than stored with the
* field — `"licenseType.capitalThreshold"` for a capital amount. The server
* resolves it on every read, so `min` already carries the real floor by the
* time the wizard sees it; this is only here so the builder round-trips the
* binding instead of dropping it on save.
*/
minSource?: string;
sortOrder?: number;
}
@@ -356,6 +364,7 @@ export interface StaffEvidenceRequirement {
export interface StaffRoleRequirement {
id: string;
licenseTypeId: string;
roleKey: string;
name: Bilingual;
minCount: number;
@@ -364,6 +373,7 @@ export interface StaffRoleRequirement {
minYearsExperience: number | null;
requiredEvidence: StaffEvidenceRequirement[];
sortOrder: number;
isActive: boolean;
}
export interface LicenseTypeRequirements {
@@ -433,6 +443,12 @@ export interface Attachment {
ownerType: string;
ownerId: string;
documentKey: string;
/**
* Set when this was filled from the applicant's personal document vault
* rather than uploaded here — what both apps badge as "From My Documents".
* Null for an ordinary upload, and cleared the moment the file is replaced.
*/
copiedFromAttachmentId?: string | null;
title: string | null;
validFrom: string | null;
validTo: string | null;