diff --git a/gerbil-manager-web/e2e/charakter.spec.ts b/gerbil-manager-web/e2e/charakter.spec.ts new file mode 100644 index 0000000..1cfdc50 --- /dev/null +++ b/gerbil-manager-web/e2e/charakter.spec.ts @@ -0,0 +1,21 @@ +/** FEAT-14b: Charakterbogen — Eigenschaft umschalten, persistieren, im Abgabe-Komposer wiederfinden. */ +import { de, expect, skipUnlessMock, test } from './fixtures' + +test('Charakterbogen: Eigenschaft umschalten, speichern und im Abgabe-Komposer wiederfinden', async ({ + page, +}) => { + skipUnlessMock() + await page.goto('/rennmaeuse/kruemel') + await expect(page.getByRole('heading', { name: 'Krümel' })).toBeVisible() + await expect(page.getByText(de.character.sectionTitle)).toBeVisible() + + // Eigenschaft 'neugierig' aktivieren und speichern. + await page.getByRole('checkbox', { name: 'neugierig' }).check() + await page.getByRole('button', { name: de.character.save }).click() + await expect(page.getByRole('checkbox', { name: 'neugierig' })).toBeChecked() + + // Tier zur Abgabe stellen -> erscheint im /abgabe-Komposer mit gesetzter Eigenschaft. + await page.getByRole('button', { name: de.pages.abgabe.markAction }).click() + await page.goto('/abgabe') + await expect(page.getByRole('checkbox', { name: 'neugierig' })).toBeChecked() +}) diff --git a/gerbil-manager-web/src/components/GroupComposer.tsx b/gerbil-manager-web/src/components/GroupComposer.tsx index 1e143c3..a8a5654 100644 --- a/gerbil-manager-web/src/components/GroupComposer.tsx +++ b/gerbil-manager-web/src/components/GroupComposer.tsx @@ -7,7 +7,9 @@ import { listGerbilPhotos, photoSrc, type GerbilPhoto } from '../api/photos' import { generateSaleAd } from '../api/saleAd' import { useApi, useMutation } from '../hooks/useApi' import { formatDate, genderLabel } from '../format/labels' +import { traitLabels } from '../format/traits' import FarbschlagImage from './FarbschlagImage' +import Charakterbogen from './Charakterbogen' type SaleStatus = 'free' | 'loose' | 'reserved' @@ -34,9 +36,13 @@ export default function GroupComposer({ groupNumber, animals, farbschlagOf }: Gr const [status, setStatus] = useState('free') const [reservedName, setReservedName] = useState('') const [tagline, setTagline] = useState('') - // Per-animal personality text, seeded from notes on first render. + // Per-animal character note, seeded from the persisted characterNote (or notes). const [personality, setPersonality] = useState>(() => - Object.fromEntries(animals.map((a) => [a.id, a.notes ?? ''])), + Object.fromEntries(animals.map((a) => [a.id, a.characterNote ?? a.notes ?? ''])), + ) + // Per-animal selected trait keys, seeded from the persisted Charakterbogen. + const [traitsByAnimal, setTraitsByAnimal] = useState>(() => + Object.fromEntries(animals.map((a) => [a.id, a.characterTraits ?? []])), ) const [selectedPhotos, setSelectedPhotos] = useState>({}) const [hints, setHints] = useState('') @@ -147,7 +153,9 @@ export default function GroupComposer({ groupNumber, animals, farbschlagOf }: Gr name: a.name, farbschlag: farbschlagOf(a), dateOfBirth: a.dateOfBirth, - notes: personality[a.id] ?? a.notes ?? null, + notes: a.notes ?? null, + traits: traitLabels(traitsByAnimal[a.id] ?? []), + characterNote: personality[a.id] ?? null, })), statusLine, hints, @@ -201,14 +209,12 @@ export default function GroupComposer({ groupNumber, animals, farbschlagOf }: Gr {a.dateOfBirth ? ` · ${t.listing.bornOn} ${formatDate(a.dateOfBirth)}` : ''} -