mirror of
https://github.com/Tria-plc/emaui.git
synced 2026-09-07 17:45:43 +00:00
refactor: move license validity management to behavior tab and add capital threshold requirement
This commit is contained in:
@@ -36,6 +36,8 @@ interface Draft {
|
||||
requiresSeafarerRegistration: boolean;
|
||||
requiresValidMedical: boolean;
|
||||
minSeaTimeDays: number | null;
|
||||
capitalThreshold: number | null;
|
||||
validityMonths: number;
|
||||
renewalWindowDays: number;
|
||||
expiryReminderDays: number[];
|
||||
requiresOperatorMode: boolean;
|
||||
@@ -59,6 +61,11 @@ function toDraft(licenseType: LicenseType): Draft {
|
||||
licenseType.requiresSeafarerRegistration ?? false,
|
||||
requiresValidMedical: licenseType.requiresValidMedical ?? false,
|
||||
minSeaTimeDays: licenseType.minSeaTimeDays ?? null,
|
||||
capitalThreshold:
|
||||
licenseType.capitalThreshold == null
|
||||
? null
|
||||
: Number(licenseType.capitalThreshold),
|
||||
validityMonths: licenseType.validityMonths ?? 12,
|
||||
renewalWindowDays: licenseType.renewalWindowDays ?? 60,
|
||||
expiryReminderDays: licenseType.expiryReminderDays ?? [60, 30, 7],
|
||||
requiresOperatorMode: licenseType.requiresOperatorMode ?? true,
|
||||
@@ -194,10 +201,25 @@ export function BehaviorTab({ licenseType }: { licenseType: LicenseType }) {
|
||||
<Text size="xs" c="dimmed">
|
||||
{t(
|
||||
'certReq.behavior.eligibilityHint',
|
||||
'Checked when an applicant submits. Tightening a gate can stop someone mid-way from submitting a draft they have already started.',
|
||||
'Checked when an applicant submits, and the capital requirement again when an officer approves. Tightening a gate can stop someone mid-way from submitting a draft they have already started.',
|
||||
)}
|
||||
</Text>
|
||||
|
||||
<NullableNumber
|
||||
label={t('certReq.behavior.capitalThreshold', 'Minimum paid-up capital')}
|
||||
switchLabel={t('certReq.behavior.capitalOn', 'Require a minimum paid-up capital')}
|
||||
description={t(
|
||||
'certReq.behavior.capitalHint',
|
||||
'An officer cannot approve until they have verified capital at or above this. Applies to applications already in the queue, not just new ones.',
|
||||
)}
|
||||
value={draft.capitalThreshold}
|
||||
onChange={(v) => set('capitalThreshold', v)}
|
||||
disabled={!canEdit}
|
||||
min={0}
|
||||
defaultValue={1_000_000}
|
||||
thousandSeparator
|
||||
/>
|
||||
|
||||
<Switch
|
||||
checked={draft.requiresSeafarerRegistration}
|
||||
onChange={(e) => set('requiresSeafarerRegistration', e.currentTarget.checked)}
|
||||
@@ -243,7 +265,27 @@ export function BehaviorTab({ licenseType }: { licenseType: LicenseType }) {
|
||||
/>
|
||||
</Section>
|
||||
|
||||
<Section title={t('certReq.behavior.renewal', 'Renewal')}>
|
||||
<Section title={t('certReq.behavior.renewal', 'Validity and renewal')}>
|
||||
{/* Stored in months, edited in years: a licence term is a number of
|
||||
years to everyone who works with one. Half-years stay expressible. */}
|
||||
<NumberInput
|
||||
label={t('certReq.behavior.validityYears', 'Valid for (years)')}
|
||||
description={t(
|
||||
'certReq.behavior.validityHint',
|
||||
'Applied when a licence is issued. Licences already issued keep the expiry date they were given.',
|
||||
)}
|
||||
value={Number((draft.validityMonths / 12).toFixed(2))}
|
||||
onChange={(v) =>
|
||||
set('validityMonths', Math.round(Number(v || 0) * 12) || draft.validityMonths)
|
||||
}
|
||||
min={0.5}
|
||||
max={20}
|
||||
step={0.5}
|
||||
decimalScale={1}
|
||||
allowNegative={false}
|
||||
disabled={!canEdit}
|
||||
/>
|
||||
|
||||
<NumberInput
|
||||
label={t('certReq.behavior.renewalWindow', 'Renewal opens (days before expiry)')}
|
||||
value={draft.renewalWindowDays}
|
||||
@@ -389,6 +431,8 @@ function NullableNumber({
|
||||
onChange,
|
||||
disabled,
|
||||
min,
|
||||
defaultValue,
|
||||
thousandSeparator,
|
||||
}: {
|
||||
label: string;
|
||||
switchLabel: string;
|
||||
@@ -397,12 +441,17 @@ function NullableNumber({
|
||||
onChange: (value: number | null) => void;
|
||||
disabled: boolean;
|
||||
min: number;
|
||||
/** Seeded when the switch is turned on. Defaults to the minimum. */
|
||||
defaultValue?: number;
|
||||
thousandSeparator?: boolean;
|
||||
}) {
|
||||
return (
|
||||
<Stack gap="xs">
|
||||
<Switch
|
||||
checked={value !== null}
|
||||
onChange={(e) => onChange(e.currentTarget.checked ? min || 1 : null)}
|
||||
onChange={(e) =>
|
||||
onChange(e.currentTarget.checked ? (defaultValue ?? min ?? 1) : null)
|
||||
}
|
||||
label={switchLabel}
|
||||
description={description}
|
||||
disabled={disabled}
|
||||
@@ -414,6 +463,8 @@ function NullableNumber({
|
||||
onChange={(v) => onChange(typeof v === 'number' ? v : value)}
|
||||
min={min}
|
||||
allowNegative={false}
|
||||
thousandSeparator={thousandSeparator ? ',' : undefined}
|
||||
decimalScale={thousandSeparator ? 2 : undefined}
|
||||
disabled={disabled}
|
||||
/>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user