mirror of
https://github.com/Tria-plc/emaui.git
synced 2026-08-26 13:02:50 +00:00
feat: add document requirements and form schema management for license types
- Implement DocumentRequirementsTab for managing document upload requirements. - Create FieldEditorDrawer and SectionEditorDrawer for editing fields and sections in the form schema. - Develop FormSchemaTab to handle sections and fields for a license type's form schema. - Introduce CertificateRequirementsPage to serve as the main interface for configuring license type requirements. - Add hooks for requirement actions to streamline mutation handling and notifications. - Implement condition handling for fields and sections to manage visibility based on user input. - Create schema-paths configuration to facilitate condition target collection.
This commit is contained in:
@@ -6,6 +6,9 @@ import type {
|
||||
ApplicationPayment,
|
||||
ApplicationStaff,
|
||||
Attachment,
|
||||
DocumentRequirement,
|
||||
FormSchemaPalette,
|
||||
FormSectionConfig,
|
||||
InitiatePaymentResult,
|
||||
IssuedLicense,
|
||||
Inspection,
|
||||
@@ -25,6 +28,7 @@ import type {
|
||||
QueueFilter,
|
||||
RemarkTargetType,
|
||||
SavedQueueView,
|
||||
SchemaIssue,
|
||||
TemplateFieldPlacement,
|
||||
TemplateLogoPlacement,
|
||||
TemplatePageOptions,
|
||||
@@ -66,6 +70,7 @@ const TAGS = [
|
||||
'License',
|
||||
'SavedView',
|
||||
'LicenseTemplate',
|
||||
'DocumentRequirement',
|
||||
] as const;
|
||||
|
||||
const listTag = (type: (typeof TAGS)[number]) => ({ type, id: 'LIST' }) as const;
|
||||
@@ -178,6 +183,76 @@ export const licensingApi = baseApi
|
||||
providesTags: (_r, _e, arg) => [itemTag('LicenseType', arg.idOrKey)],
|
||||
}),
|
||||
|
||||
// ------------------------------------------------ form-schema builder
|
||||
/** Replaces a licence type's form schema. Server re-validates on save. */
|
||||
updateFormSchema: builder.mutation<
|
||||
LicenseType,
|
||||
{ id: string; formSchema: { sections: FormSectionConfig[] } }
|
||||
>({
|
||||
query: ({ id, formSchema }) => ({
|
||||
url: `/license-types/${id}/form-schema`,
|
||||
method: 'PUT',
|
||||
body: { formSchema },
|
||||
}),
|
||||
invalidatesTags: (_r, error, { id }) =>
|
||||
error ? [] : [itemTag('LicenseType', id), listTag('LicenseType')],
|
||||
}),
|
||||
|
||||
/** Dry-run lint, for inline feedback while the schema is being edited. */
|
||||
validateFormSchema: builder.mutation<
|
||||
{ valid: boolean; issues: SchemaIssue[] },
|
||||
{ formSchema: { sections: FormSectionConfig[] }; licenseTypeId?: string }
|
||||
>({
|
||||
query: (body) => ({
|
||||
url: '/license-types/form-schema/validate',
|
||||
method: 'POST',
|
||||
body,
|
||||
}),
|
||||
}),
|
||||
|
||||
/** Field types, condition operators and prefill sources the builder may offer. */
|
||||
getFormSchemaPalette: builder.query<FormSchemaPalette, void>({
|
||||
query: () => ({ url: '/license-types/form-schema/palette' }),
|
||||
}),
|
||||
|
||||
// ------------------------------------------------- document requirements
|
||||
/**
|
||||
* Every document requirement, for the admin editor to filter by licence
|
||||
* type client-side. The collection-query `q` filter syntax (`w=column:op:
|
||||
* value`) has no typed builder on this side, and the table is small
|
||||
* configuration data with no pagination need — see `licenseTypeId` usage
|
||||
* at the call site.
|
||||
*/
|
||||
getDocumentRequirements: builder.query<Paginated<DocumentRequirement>, void>({
|
||||
query: () => ({ url: '/document-requirements' }),
|
||||
providesTags: () => [listTag('DocumentRequirement')],
|
||||
}),
|
||||
|
||||
createDocumentRequirement: builder.mutation<
|
||||
DocumentRequirement,
|
||||
Partial<DocumentRequirement> & { licenseTypeId: string; key: string; name: DocumentRequirement['name'] }
|
||||
>({
|
||||
query: (body) => ({ url: '/document-requirements', method: 'POST', body }),
|
||||
invalidatesTags: (_r, error) => (error ? [] : [listTag('DocumentRequirement')]),
|
||||
}),
|
||||
|
||||
updateDocumentRequirement: builder.mutation<
|
||||
DocumentRequirement,
|
||||
{ id: string } & Partial<DocumentRequirement>
|
||||
>({
|
||||
query: ({ id, ...body }) => ({
|
||||
url: `/document-requirements/${id}`,
|
||||
method: 'PUT',
|
||||
body,
|
||||
}),
|
||||
invalidatesTags: (_r, error) => (error ? [] : [listTag('DocumentRequirement')]),
|
||||
}),
|
||||
|
||||
deleteDocumentRequirement: builder.mutation<unknown, string>({
|
||||
query: (id) => ({ url: `/document-requirements/${id}`, method: 'DELETE' }),
|
||||
invalidatesTags: (_r, error) => (error ? [] : [listTag('DocumentRequirement')]),
|
||||
}),
|
||||
|
||||
// -------------------------------------------------------- application
|
||||
createApplication: builder.mutation<
|
||||
LicenseApplication,
|
||||
@@ -827,6 +902,13 @@ export const {
|
||||
useGetLicenseTypesQuery,
|
||||
useGetLicenseCategoriesQuery,
|
||||
useUpdateLicenseFeesMutation,
|
||||
useUpdateFormSchemaMutation,
|
||||
useValidateFormSchemaMutation,
|
||||
useGetFormSchemaPaletteQuery,
|
||||
useGetDocumentRequirementsQuery,
|
||||
useCreateDocumentRequirementMutation,
|
||||
useUpdateDocumentRequirementMutation,
|
||||
useDeleteDocumentRequirementMutation,
|
||||
useUpdateLicenseValidityMutation,
|
||||
useGetLicenseTypeRequirementsQuery,
|
||||
useCreateApplicationMutation,
|
||||
|
||||
@@ -79,10 +79,12 @@ export interface FormFieldConfig {
|
||||
label: Bilingual;
|
||||
type: FormFieldType;
|
||||
required?: boolean;
|
||||
placeholder?: Bilingual;
|
||||
helpText?: Bilingual;
|
||||
options?: { value: string; label: Bilingual }[];
|
||||
min?: number;
|
||||
max?: number;
|
||||
maxLength?: number;
|
||||
showWhen?: FieldCondition;
|
||||
readOnly?: boolean;
|
||||
source?: string;
|
||||
@@ -235,6 +237,7 @@ export interface StcwCapacityRow {
|
||||
|
||||
export interface DocumentRequirement {
|
||||
id: string;
|
||||
licenseTypeId: string;
|
||||
key: string;
|
||||
name: Bilingual;
|
||||
description?: Bilingual;
|
||||
@@ -244,7 +247,32 @@ export interface DocumentRequirement {
|
||||
allowedMimeTypes: string[];
|
||||
maxSizeMb: number;
|
||||
requiresValidityDates: boolean;
|
||||
allowMultiple: boolean;
|
||||
sortOrder: number;
|
||||
isActive: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* What the form-schema builder may put on a form — the field types the engine
|
||||
* understands, which constraints each one honours, the condition operators it
|
||||
* supports, and the prefill sources a read-only field may draw from. Drives
|
||||
* the builder's pickers so they never hardcode a list the server already owns.
|
||||
*/
|
||||
export interface FormSchemaPalette {
|
||||
fieldTypes: {
|
||||
type: FormFieldType;
|
||||
supportsOptions: boolean;
|
||||
supportsRange: boolean;
|
||||
supportsMaxLength: boolean;
|
||||
}[];
|
||||
conditionOperators: ("equals" | "notEquals" | "in" | "isSet")[];
|
||||
prefillSources: string[];
|
||||
}
|
||||
|
||||
/** One problem the server's form-schema lint found. */
|
||||
export interface SchemaIssue {
|
||||
path: string;
|
||||
message: string;
|
||||
}
|
||||
|
||||
export interface StaffEvidenceRequirement {
|
||||
|
||||
Reference in New Issue
Block a user