feat: add NATIONALITY and NATION field types with dedicated country-picker logic and storage conversion

This commit is contained in:
estifanos
2026-09-08 06:45:34 +00:00
parent d5d77cbc30
commit e1150cab63
7 changed files with 126 additions and 15 deletions

View File

@@ -1,4 +1,4 @@
import { useEffect, useState } from 'react';
import { useEffect, useMemo, useState } from 'react';
import {
Button,
Checkbox,
@@ -20,6 +20,18 @@ import type { ConditionTarget } from '../config/schema-paths';
const KEY_PATTERN = /^[A-Za-z][A-Za-z0-9_]*$/;
/**
* Field types the builder offers on top of whatever the server palette lists.
* Both render the shared country picker in the portal — the full nationality
* list ("Ethiopian") and the full country list ("Ethiopia") — so neither takes
* options, a range or a max length. Merged in rather than assumed present so a
* palette that predates them still offers them.
*/
const EXTRA_FIELD_TYPES: FormSchemaPalette['fieldTypes'] = [
{ type: 'NATIONALITY', supportsOptions: false, supportsRange: false, supportsMaxLength: false },
{ type: 'NATION', supportsOptions: false, supportsRange: false, supportsMaxLength: false },
];
function emptyField(): FormFieldConfig {
return { key: '', label: { en: '', am: '' }, type: 'TEXT' };
}
@@ -52,7 +64,15 @@ export function FieldEditorDrawer({
}
}, [opened, field]);
const typeInfo = palette?.fieldTypes.find((f) => f.type === draft.type);
const fieldTypes = useMemo(() => {
const fromPalette = palette?.fieldTypes ?? [];
return [
...fromPalette,
...EXTRA_FIELD_TYPES.filter((extra) => !fromPalette.some((f) => f.type === extra.type)),
];
}, [palette]);
const typeInfo = fieldTypes.find((f) => f.type === draft.type);
const isNew = !field;
function save() {
@@ -128,7 +148,14 @@ export function FieldEditorDrawer({
<Select
label={t('certReq.field.type', 'Field type')}
data={(palette?.fieldTypes ?? []).map((f) => ({ value: f.type, label: f.type }))}
data={fieldTypes.map((f) => ({ value: f.type, label: f.type }))}
description={
draft.type === 'NATIONALITY'
? t('certReq.field.typeNationality', 'Applicant picks from the full nationality list (Ethiopian, Kenyan, …)')
: draft.type === 'NATION'
? t('certReq.field.typeNation', 'Applicant picks from the full country list (Ethiopia, Kenya, …)')
: undefined
}
value={draft.type}
onChange={(v) => v && setDraft((d) => ({ ...d, type: v as FormFieldConfig['type'] }))}
allowDeselect={false}

View File

@@ -1944,6 +1944,8 @@ export const am: Translations = {
keyInvalid: "ቁልፍ በፊደል መጀመር እና ፊደላት፣ ቁጥሮች፣ underscore ብቻ መያዝ አለበት",
label: "መለያ",
type: "የመስክ ዓይነት",
typeNationality: "አመልካቹ ከሙሉ የዜግነት ዝርዝር ይመርጣል (ኢትዮጵያዊ፣ ኬንያዊ፣ …)",
typeNation: "አመልካቹ ከሙሉ የአገር ዝርዝር ይመርጣል (ኢትዮጵያ፣ ኬንያ፣ …)",
required: "የግድ ያስፈልጋል",
placeholder: "ምሳሌ ጽሑፍ",
helpText: "የእገዛ ጽሑፍ",

View File

@@ -1959,6 +1959,8 @@ export const en = {
keyInvalid: 'Key must start with a letter and contain only letters, numbers, underscores',
label: 'Label',
type: 'Field type',
typeNationality: 'Applicant picks from the full nationality list (Ethiopian, Kenyan, …)',
typeNation: 'Applicant picks from the full country list (Ethiopia, Kenya, …)',
required: 'Required',
placeholder: 'Placeholder',
helpText: 'Help text',