From 87250ba007465babb276121dbaddd4a452e68ad6 Mon Sep 17 00:00:00 2001 From: Gulum Date: Sat, 6 Jun 2026 00:27:29 +0200 Subject: [PATCH] FEAT-3: litter type+CRUD, Zucht strings, /wuerfe nested routes (retire LittersPage) Co-Authored-By: Claude Opus 4.8 (1M context) --- gerbil-manager-web/src/App.tsx | 11 +++- gerbil-manager-web/src/api/litters.ts | 19 +++++- gerbil-manager-web/src/api/types.ts | 22 +++++++ gerbil-manager-web/src/pages/LittersPage.tsx | 10 --- .../src/pages/WuerfeListPage.tsx | 10 +++ .../src/pages/WurfDetailPage.tsx | 10 +++ gerbil-manager-web/src/pages/WurfFormPage.tsx | 10 +++ gerbil-manager-web/src/strings/de.ts | 63 ++++++++++++++++++- 8 files changed, 141 insertions(+), 14 deletions(-) delete mode 100644 gerbil-manager-web/src/pages/LittersPage.tsx create mode 100644 gerbil-manager-web/src/pages/WuerfeListPage.tsx create mode 100644 gerbil-manager-web/src/pages/WurfDetailPage.tsx create mode 100644 gerbil-manager-web/src/pages/WurfFormPage.tsx diff --git a/gerbil-manager-web/src/App.tsx b/gerbil-manager-web/src/App.tsx index 3d03575..6af97cb 100644 --- a/gerbil-manager-web/src/App.tsx +++ b/gerbil-manager-web/src/App.tsx @@ -11,7 +11,9 @@ import HomePage from './pages/HomePage' import KontaktePage from './pages/KontaktePage' import KontaktDetailPage from './pages/KontaktDetailPage' import KontaktFormPage from './pages/KontaktFormPage' -import LittersPage from './pages/LittersPage' +import WuerfeListPage from './pages/WuerfeListPage' +import WurfDetailPage from './pages/WurfDetailPage' +import WurfFormPage from './pages/WurfFormPage' import NotFoundPage from './pages/NotFoundPage' import StammbaumPage from './pages/StammbaumPage' @@ -28,7 +30,12 @@ export default function App() { } /> } /> - } /> + + } /> + } /> + } /> + } /> + {/* FEAT-2: Kontakte ersetzt das Züchter-Platzhalter-Routing (Breeder -> Contact) */} } /> diff --git a/gerbil-manager-web/src/api/litters.ts b/gerbil-manager-web/src/api/litters.ts index 26760ad..abd0696 100644 --- a/gerbil-manager-web/src/api/litters.ts +++ b/gerbil-manager-web/src/api/litters.ts @@ -1,7 +1,24 @@ /** Typed API functions for the Würfe (litters) resource. */ import { api, resources } from './client' -import type { Litter } from './types' +import { toQueryString, type GridifyQuery } from './gridify' +import type { CreateLitter, Litter, Paged, UpdateLitter } from './types' export function getLitter(id: string): Promise { return api.get(`${resources.litters}/${id}`) } + +export function listLitters(query: GridifyQuery): Promise> { + return api.get>(`${resources.litters}${toQueryString(query)}`) +} + +export function createLitter(body: CreateLitter): Promise { + return api.post(resources.litters, body) +} + +export function updateLitter(id: string, body: UpdateLitter): Promise { + return api.put(`${resources.litters}/${id}`, body) +} + +export function deleteLitter(id: string): Promise { + return api.delete(`${resources.litters}/${id}`) +} diff --git a/gerbil-manager-web/src/api/types.ts b/gerbil-manager-web/src/api/types.ts index 158db4b..91312be 100644 --- a/gerbil-manager-web/src/api/types.ts +++ b/gerbil-manager-web/src/api/types.ts @@ -80,12 +80,34 @@ export interface Contact { export interface Litter { id: string name: string + /** Wurfdatum (birth date). */ date: DateOnlyString + /** Wurfstärke — total born count. */ totalBorn: number | null + /** + * Abgabedatum (auto-suggested ~35 days after birth, editable). + * Optional in the type so existing Litter constructors (e.g. pedigree test + * factories) keep compiling; the API DTO always includes it (nullable). + */ + expectedGoHomeDate?: DateOnlyString | null + notes?: string | null fatherId: string | null motherId: string | null } +/** Payload for POST /litters. */ +export interface CreateLitter { + name: string + date: DateOnlyString + totalBorn?: number | null + expectedGoHomeDate?: DateOnlyString | null + notes?: string | null + fatherId?: string | null + motherId?: string | null +} + +export type UpdateLitter = Partial + /** Paged list envelope returned by Gridify list endpoints. */ export interface Paged { items: T[] diff --git a/gerbil-manager-web/src/pages/LittersPage.tsx b/gerbil-manager-web/src/pages/LittersPage.tsx deleted file mode 100644 index 42e5fa5..0000000 --- a/gerbil-manager-web/src/pages/LittersPage.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import { de } from '../strings/de' - -export default function LittersPage() { - return ( -
-

{de.pages.litters.title}

-

{de.pages.litters.comingSoon}

-
- ) -} diff --git a/gerbil-manager-web/src/pages/WuerfeListPage.tsx b/gerbil-manager-web/src/pages/WuerfeListPage.tsx new file mode 100644 index 0000000..833457a --- /dev/null +++ b/gerbil-manager-web/src/pages/WuerfeListPage.tsx @@ -0,0 +1,10 @@ +import { de } from '../strings/de' + +export default function WuerfeListPage() { + // Fleshed out in the next FEAT-3 increment (Gridify list, year filter, sort). + return ( +
+

{de.pages.litters.title}

+
+ ) +} diff --git a/gerbil-manager-web/src/pages/WurfDetailPage.tsx b/gerbil-manager-web/src/pages/WurfDetailPage.tsx new file mode 100644 index 0000000..0da05ca --- /dev/null +++ b/gerbil-manager-web/src/pages/WurfDetailPage.tsx @@ -0,0 +1,10 @@ +import { de } from '../strings/de' + +export default function WurfDetailPage() { + // Fleshed out in a later FEAT-3 increment (litter workspace + Jungtier erfassen). + return ( +
+

{de.pages.litters.title}

+
+ ) +} diff --git a/gerbil-manager-web/src/pages/WurfFormPage.tsx b/gerbil-manager-web/src/pages/WurfFormPage.tsx new file mode 100644 index 0000000..71317c1 --- /dev/null +++ b/gerbil-manager-web/src/pages/WurfFormPage.tsx @@ -0,0 +1,10 @@ +import { de } from '../strings/de' + +export default function WurfFormPage() { + // Fleshed out in a later FEAT-3 increment (parents picker, auto go-home date). + return ( +
+

{de.pages.litters.form.createTitle}

+
+ ) +} diff --git a/gerbil-manager-web/src/strings/de.ts b/gerbil-manager-web/src/strings/de.ts index 56fa06e..5f4936c 100644 --- a/gerbil-manager-web/src/strings/de.ts +++ b/gerbil-manager-web/src/strings/de.ts @@ -117,9 +117,70 @@ export const de = { GivenAway: 'Abgegeben', }, }, + // ── FEAT-3 (Kevin): Zucht — Würfe + Zuchtpaare ── litters: { title: 'Würfe', - comingSoon: 'Die Wurf-Verwaltung entsteht gerade. Bald kannst du hier Würfe dokumentieren.', + tabs: { + litters: 'Würfe', + pairs: 'Zuchtpaare', + }, + // Liste + newButton: 'Neuer Wurf', + empty: 'Keine Würfe gefunden.', + countLabel: 'Würfe', + filterYear: 'Jahr', + allYears: 'Alle Jahre', + sort: { + dateDesc: 'Wurfdatum (neueste)', + dateAsc: 'Wurfdatum (älteste)', + }, + // Felder + fields: { + name: 'Bezeichnung', + date: 'Wurfdatum', + father: 'Vater', + mother: 'Mutter', + totalBorn: 'Wurfstärke', + expectedGoHomeDate: 'Voraussichtliches Abgabedatum', + notes: 'Notizen', + }, + // Detail / Arbeitsbereich + detail: { + parents: 'Elterntiere', + registered: 'Erfasste Jungtiere', + juveniles: 'Jungtiere', + registerJuvenile: 'Jungtier erfassen', + expectedColors: 'Erwartete Farbschläge dieser Verpaarung', + needParentsGenotype: + 'Für die Farbvorhersage müssen bei Vater und Mutter Genotypen hinterlegt sein.', + noJuveniles: 'Noch keine Jungtiere erfasst.', + unknownParent: 'Unbekannt', + edit: 'Bearbeiten', + back: 'Zurück zur Liste', + notFound: 'Dieser Wurf wurde nicht gefunden.', + }, + // Formular + form: { + createTitle: 'Neuen Wurf anlegen', + editTitle: 'Wurf bearbeiten', + none: '— keine Angabe —', + goHomeHint: 'Vorschlag: 35 Tage nach dem Wurfdatum. Anpassbar.', + save: 'Speichern', + cancel: 'Abbrechen', + saving: 'Speichern …', + }, + validation: { + nameRequired: 'Bitte eine Bezeichnung eingeben.', + dateRequired: 'Bitte ein Wurfdatum angeben.', + }, + // Zuchtpaar-Übersicht + pairs: { + title: 'Zuchtpaare', + empty: 'Noch keine Zuchtpaare — diese ergeben sich aus den erfassten Würfen.', + litterCount: 'Würfe', + lastLitter: 'Letzter Wurf', + testMating: 'Probeverpaarung', + }, }, breeders: { title: 'Züchter',