feat: add REISSUE application kind and dynamic file size limits, and remove unused serviceKind logic

This commit is contained in:
estifanos
2026-09-02 10:31:18 +00:00
parent 51aa446eee
commit 92f2f16b80
7 changed files with 45 additions and 31 deletions

View File

@@ -21,7 +21,6 @@ import {
type CertificateCategory,
type CompletionEffect,
type LicenseType,
type ServiceKind,
type WorkflowProfile,
} from '@ema-platform/api';
import { useRequirementActions } from '../hooks/useRequirementActions';
@@ -29,7 +28,6 @@ import { useRequirementActions } from '../hooks/useRequirementActions';
/** The shape the form edits — every field the behaviour endpoint accepts. */
interface Draft {
workflowProfile: WorkflowProfile;
serviceKind: ServiceKind;
completionEffect: CompletionEffect | null;
certificateCategory: CertificateCategory | null;
requiresExamination: boolean;
@@ -57,7 +55,6 @@ const REMINDER_OFFSETS = ['90', '60', '30', '14', '7'];
function toDraft(licenseType: LicenseType): Draft {
return {
workflowProfile: licenseType.workflowProfile ?? 'STANDARD',
serviceKind: licenseType.serviceKind ?? 'LICENSE',
completionEffect: licenseType.completionEffect ?? null,
certificateCategory: licenseType.certificateCategory ?? null,
requiresExamination: licenseType.requiresExamination ?? false,
@@ -154,12 +151,22 @@ export function BehaviorTab({ licenseType }: { licenseType: LicenseType }) {
...rest
} = draft;
// A type switched from "does not expire" straight to a term in days still
// carries `validityMonths: 0`, which the server's 6-month floor refuses.
// Days win over months at issuance, so the zero is simply left alone.
const term = expires
? {
validityDays,
...(validityMonths > 0 ? { validityMonths } : {}),
}
: {};
const ok = await run(
() =>
save({
id: licenseType.id,
...rest,
...(expires ? { validityMonths, validityDays } : {}),
...term,
...(expires && draft.renewalEnabled
? { renewalWindowDays, expiryReminderDays }
: {}),
@@ -241,21 +248,10 @@ export function BehaviorTab({ licenseType }: { licenseType: LicenseType }) {
disabled={!canEdit}
/>
<Select
label={t('certReq.behavior.serviceKind', 'Service kind')}
description={t(
'certReq.behavior.serviceKindHint',
'Catalogue classification only — no workflow depends on it.',
)}
data={[
{ value: 'LICENSE', label: t('certReq.behavior.license', 'Licence') },
{ value: 'REGISTRATION', label: t('certReq.behavior.registrationKind', 'Registration') },
]}
value={draft.serviceKind}
onChange={(v) => v && set('serviceKind', v as ServiceKind)}
allowDeselect={false}
disabled={!canEdit}
/>
{/* `serviceKind` is deliberately not offered here: nothing in the
backend or either portal reads it, so a control for it would be
a setting that changes nothing. Bring it back once something
branches on it. */}
</Section>
<Section title={t('certReq.behavior.eligibility', 'Eligibility gates')}>

View File

@@ -322,6 +322,7 @@ export function DocumentRequirementEditorDrawer({
data={[
{ value: 'NEW', label: t('certReq.doc.kindNew', 'New application') },
{ value: 'RENEWAL', label: t('certReq.doc.kindRenewal', 'Renewal') },
{ value: 'REISSUE', label: t('certReq.doc.kindReissue', 'Damaged / reissue') },
]}
value={draft.applicationKind}
onChange={(v) => v && setDraft((d) => ({ ...d, applicationKind: v as ApplicationKind }))}

View File

@@ -20,7 +20,14 @@ import { useRequirementActions } from '../hooks/useRequirementActions';
import { describeCondition } from './ConditionBuilder';
import { DocumentRequirementEditorDrawer } from './DocumentRequirementEditorDrawer';
const KINDS: ApplicationKind[] = ['NEW', 'RENEWAL'];
/** Every kind the server validates a document set for, so each can be configured. */
const KINDS: ApplicationKind[] = ['NEW', 'RENEWAL', 'REISSUE'];
const KIND_LABEL: Record<ApplicationKind, [string, string]> = {
NEW: ['certReq.doc.kindNew', 'New application'],
RENEWAL: ['certReq.doc.kindRenewal', 'Renewal'],
REISSUE: ['certReq.doc.kindReissue', 'Damaged / reissue'],
};
const MODE_COLOR: Record<DocumentRequirement['mode'], string> = {
ALWAYS: 'blue',
@@ -112,9 +119,7 @@ export function DocumentRequirementsTab({ licenseType }: { licenseType: LicenseT
return (
<Card key={kind} withBorder radius="md" p="md">
<Group justify="space-between" mb="sm">
<Title order={5}>
{kind === 'NEW' ? t('certReq.doc.kindNew', 'New application') : t('certReq.doc.kindRenewal', 'Renewal')}
</Title>
<Title order={5}>{t(...KIND_LABEL[kind])}</Title>
<Button
size="xs"
variant="light"

View File

@@ -1496,6 +1496,7 @@ export const am: Translations = {
applicationKind: "የማመልከቻ ዓይነት",
kindNew: "አዲስ ማመልከቻ",
kindRenewal: "ዕድሳት",
kindReissue: "የተበላሸ / ምትክ",
kindLocked: "ከተፈጠረ በኋላ የማመልከቻ ዓይነት መቀየር አይቻልም",
mode: "ዘዴ",
modeAlways: "ሁልጊዜ ያስፈልጋል",

View File

@@ -1502,6 +1502,7 @@ export const en = {
applicationKind: 'Application kind',
kindNew: 'New application',
kindRenewal: 'Renewal',
kindReissue: 'Damaged / reissue',
kindLocked: 'Application kind cannot change once created',
mode: 'Mode',
modeAlways: 'Always required',