From db4915020615086abb8af54696ab14c532d027cd Mon Sep 17 00:00:00 2001 From: Gulum Date: Sat, 6 Jun 2026 17:46:13 +0200 Subject: [PATCH] FORM-FIELDS-1: originBreeder + isDeaf in GerbilFormPage MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - types.ts: isDeaf?: boolean|null in Gerbil + CreateGerbil (UpdateGerbil erbt via Partial) - de.ts: fields.originBreeder, fields.isDeaf; form.isDeafUnknown/Yes/No - GerbilFormPage: originBreeder Freitext-Input (neben originContactId-Dropdown); isDeaf Tristate-Select (Unbekannt/Ja/Nein); round-trip load→display→save e2e: 2 neue Tests (originBreeder Freitext + isDeaf Tristate round-trip) Gate: vitest 82/82, e2e 146/146, tsc clean Rebase auf Pams CR-2 folgt nach deren Merge. --- gerbil-manager-web/e2e/tiere.spec.ts | 23 ++++++++++++ gerbil-manager-web/src/api/types.ts | 3 ++ .../src/pages/GerbilFormPage.tsx | 35 +++++++++++++++++++ gerbil-manager-web/src/strings/de.ts | 5 +++ 4 files changed, 66 insertions(+) diff --git a/gerbil-manager-web/e2e/tiere.spec.ts b/gerbil-manager-web/e2e/tiere.spec.ts index 469edc9..30f7a02 100644 --- a/gerbil-manager-web/e2e/tiere.spec.ts +++ b/gerbil-manager-web/e2e/tiere.spec.ts @@ -149,3 +149,26 @@ test('Tier bearbeiten — Notizen ändern', async ({ page }) => { await expect(page.getByRole('heading', { name: 'Krümel' })).toBeVisible() await expect(page.getByText('Sehr zutraulich.')).toBeVisible() }) + +test('Tier bearbeiten — originBreeder Freitext round-trip (FORM-FIELDS-1)', async ({ page }) => { + skipUnlessMock() + // Fridolin hat originBreeder='Zoohandlung Meier', kein originContactId → Freitext-Feld vorbelegt + await page.goto('/rennmaeuse/fridolin/bearbeiten') + await expect(page.getByLabel(t.fields.originBreeder)).toHaveValue('Zoohandlung Meier') + await page.getByLabel(t.fields.originBreeder).fill('Neue Musterzucht') + await page.getByRole('button', { name: t.form.save, exact: true }).click() + // Detailseite: Herkunft zeigt den neuen Wert (kein Contact → originBreeder-Text) + await expect(page.getByText('Neue Musterzucht')).toBeVisible() +}) + +test('Tier bearbeiten — isDeaf Tristate round-trip (FORM-FIELDS-1)', async ({ page }) => { + skipUnlessMock() + await page.goto('/rennmaeuse/kruemel/bearbeiten') + // Standard: Unbekannt (null → value='') + await expect(page.getByLabel(t.fields.isDeaf)).toHaveValue('') + await page.getByLabel(t.fields.isDeaf).selectOption({ label: t.form.isDeafYes }) + await page.getByRole('button', { name: t.form.save, exact: true }).click() + // Zurück zur Bearbeiten-Seite: Wert muss erhalten sein + await page.goto('/rennmaeuse/kruemel/bearbeiten') + await expect(page.getByLabel(t.fields.isDeaf)).toHaveValue('true') +}) diff --git a/gerbil-manager-web/src/api/types.ts b/gerbil-manager-web/src/api/types.ts index 40024b2..e9b75f9 100644 --- a/gerbil-manager-web/src/api/types.ts +++ b/gerbil-manager-web/src/api/types.ts @@ -54,6 +54,8 @@ export interface Gerbil { * as resident (backend default true). */ isResident?: boolean + /** FORM-FIELDS-1: true=gehörlos, false=hörend, null=unbekannt. */ + isDeaf?: boolean | null } /** Payload for POST /gerbils. */ @@ -76,6 +78,7 @@ export interface CreateGerbil { characterTraits?: string[] | null characterNote?: string | null isResident?: boolean + isDeaf?: boolean | null } /** Payload for PUT /gerbils/{id} (all optional / partial update). */ diff --git a/gerbil-manager-web/src/pages/GerbilFormPage.tsx b/gerbil-manager-web/src/pages/GerbilFormPage.tsx index f3eea99..7d38582 100644 --- a/gerbil-manager-web/src/pages/GerbilFormPage.tsx +++ b/gerbil-manager-web/src/pages/GerbilFormPage.tsx @@ -21,10 +21,12 @@ interface FormState { enclosureId: string litterId: string originContactId: string + originBreeder: string receiverContactId: string genotype: string notes: string isResident: boolean + isDeaf: boolean | null } const EMPTY: FormState = { @@ -39,10 +41,12 @@ const EMPTY: FormState = { enclosureId: '', litterId: '', originContactId: '', + originBreeder: '', receiverContactId: '', genotype: '', notes: '', isResident: true, + isDeaf: null, } function formFromGerbil(g: { @@ -57,10 +61,12 @@ function formFromGerbil(g: { enclosureId: string | null litterId: string | null originContactId: string | null + originBreeder?: string | null receiverContactId: string | null genotype: string | null notes: string | null isResident?: boolean | null + isDeaf?: boolean | null }): FormState { return { name: g.name, @@ -74,10 +80,12 @@ function formFromGerbil(g: { enclosureId: g.enclosureId ?? '', litterId: g.litterId ?? '', originContactId: g.originContactId ?? '', + originBreeder: g.originBreeder ?? '', receiverContactId: g.receiverContactId ?? '', genotype: g.genotype ?? '', notes: g.notes ?? '', isResident: g.isResident ?? true, + isDeaf: g.isDeaf ?? null, } } @@ -167,10 +175,12 @@ export default function GerbilFormPage() { enclosureId: nn(form.enclosureId), litterId: nn(form.litterId), originContactId: nn(form.originContactId), + originBreeder: nn(form.originBreeder), receiverContactId: nn(form.receiverContactId), genotype: nn(form.genotype), notes: nn(form.notes), isResident: form.isResident, + isDeaf: form.isDeaf, } const result = await mutation.run(body) if (result.ok) navigate(`/rennmaeuse/${result.value.id}`) @@ -326,6 +336,16 @@ export default function GerbilFormPage() { + + +