feat(person): generation dropdown on Person edit/new forms (#689)
PersonEditForm.svelte gains a G 0…G 6 select inside the {#if isPerson}
block. min-h-[44px] meets WCAG 2.5.8 / dual-audience touch target.
generationStr is initialised via $state(untrack(...)) so prop reruns
never reset an in-progress edit (same pattern as selectedType).
Both /persons/[id]/edit and /persons/new form actions read the field
without the conditional-spread idiom — generation always lands in the
PUT/POST body. G 0 is a valid family-tree-root value the spread would
silently drop, and an empty option sends null so a human can clear the
field back to "unset".
i18n adds person_label_generation / person_option_generation_unset /
person_hint_generation in de/en/es. Drops the dead stammbaum_generations
key (zero callsites after the filter-chip removal in the spec).
Tests: dropdown render + hydration in the component, generation=0/3/null
arriving in the API body in the server actions.
Refs #689
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -113,4 +113,48 @@ describe('PersonEditForm', () => {
|
||||
expect(alias.value).toBe('');
|
||||
expect(birthYear.value).toBe('');
|
||||
});
|
||||
|
||||
// ─── generation dropdown (#689) ─────────────────────────────────────────────
|
||||
|
||||
it('renders the generation select with G 0…G 6 options when personType is PERSON', async () => {
|
||||
render(PersonEditForm, { props: { person: personPersonal } });
|
||||
|
||||
const select = (await page.getByLabelText(/^generation$/i).element()) as HTMLSelectElement;
|
||||
const labels = Array.from(select.options).map((o) => o.label.trim());
|
||||
expect(labels).toEqual(
|
||||
expect.arrayContaining(['G 0', 'G 1', 'G 2', 'G 3', 'G 4', 'G 5', 'G 6'])
|
||||
);
|
||||
});
|
||||
|
||||
it('hides the generation select for INSTITUTION', async () => {
|
||||
render(PersonEditForm, { props: { person: personInstitution } });
|
||||
|
||||
await expect.element(page.getByLabelText(/^generation$/i)).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('hydrates the generation select from person.generation', async () => {
|
||||
render(PersonEditForm, {
|
||||
props: {
|
||||
person: { ...personPersonal, generation: 3 } as typeof personPersonal & {
|
||||
generation: number;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const select = (await page.getByLabelText(/^generation$/i).element()) as HTMLSelectElement;
|
||||
expect(select.value).toBe('3');
|
||||
});
|
||||
|
||||
it('hydrates the generation select to "" when person.generation is null', async () => {
|
||||
render(PersonEditForm, {
|
||||
props: {
|
||||
person: { ...personPersonal, generation: null } as typeof personPersonal & {
|
||||
generation: number | null;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const select = (await page.getByLabelText(/^generation$/i).element()) as HTMLSelectElement;
|
||||
expect(select.value).toBe('');
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user