Enhance certificate designer and seafarer registration features with image support and dynamic department/rank options

This commit is contained in:
Nati
2026-08-24 14:15:55 +00:00
parent 4a3ad7c2e6
commit bd65fc0eab
16 changed files with 320 additions and 115 deletions

View File

@@ -572,12 +572,15 @@ export interface TemplateFieldPlacement {
/** Variable rendered here, or null when the block carries literal `text`. */
variable: string | null;
text?: string;
/** Renders as `<img>` when "image" — see TemplateVariable.kind. */
type?: "text" | "image";
xPct: number;
yPct: number;
widthPct: number;
fontSize?: number;
fontWeight?: "normal" | "bold";
align?: "left" | "center" | "right";
fontStyle?: "normal" | "italic";
align?: "left" | "center" | "right" | "justify";
color?: string;
}
@@ -639,6 +642,8 @@ export interface LicenseTemplate {
export interface TemplateVariable {
key: string;
label: string;
/** "image" means the value is a data URI to place as `<img>`, not text. */
kind?: "text" | "image";
}
export interface Paginated<T> {

View File

@@ -210,14 +210,22 @@ const OPTION_LABELS: Partial<Record<keyof SeafarerRegistrationAnswers, { value:
bloodType: BLOOD_TYPE_OPTIONS,
};
/** Display value for one answer: option label for enums, "—" when blank. */
/**
* Display value for one answer: option label for enums, "—" when blank.
*
* `departmentOptions` overrides the hardcoded `DEPARTMENT_OPTIONS` fallback
* for the `department` field — the live list from `GET /departments`, so a
* department added in the backoffice after this constants file was written
* still gets its name instead of falling back to the raw code.
*/
export function displaySeafarerAnswer(
field: keyof SeafarerRegistrationAnswers,
value: unknown,
departmentOptions?: { value: string; label: string }[],
): string {
if (value === null || value === undefined || value === '') return '—';
if (typeof value === 'boolean') return value ? 'Yes' : 'No';
const options = OPTION_LABELS[field];
const options = field === 'department' && departmentOptions ? departmentOptions : OPTION_LABELS[field];
if (options) return options.find((o) => o.value === value)?.label ?? String(value);
return String(value);
}