FEAT-3: litter type+CRUD, Zucht strings, /wuerfe nested routes (retire LittersPage)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -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() {
|
||||
<Route path=":id/bearbeiten" element={<GerbilFormPage />} />
|
||||
<Route path=":id/stammbaum" element={<StammbaumPage />} />
|
||||
</Route>
|
||||
<Route path="wuerfe" element={<LittersPage />} />
|
||||
<Route path="wuerfe">
|
||||
<Route index element={<WuerfeListPage />} />
|
||||
<Route path="neu" element={<WurfFormPage />} />
|
||||
<Route path=":id" element={<WurfDetailPage />} />
|
||||
<Route path=":id/bearbeiten" element={<WurfFormPage />} />
|
||||
</Route>
|
||||
{/* FEAT-2: Kontakte ersetzt das Züchter-Platzhalter-Routing (Breeder -> Contact) */}
|
||||
<Route path="becken">
|
||||
<Route index element={<BeckenPage />} />
|
||||
|
||||
@@ -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<Litter> {
|
||||
return api.get<Litter>(`${resources.litters}/${id}`)
|
||||
}
|
||||
|
||||
export function listLitters(query: GridifyQuery): Promise<Paged<Litter>> {
|
||||
return api.get<Paged<Litter>>(`${resources.litters}${toQueryString(query)}`)
|
||||
}
|
||||
|
||||
export function createLitter(body: CreateLitter): Promise<Litter> {
|
||||
return api.post<Litter>(resources.litters, body)
|
||||
}
|
||||
|
||||
export function updateLitter(id: string, body: UpdateLitter): Promise<Litter> {
|
||||
return api.put<Litter>(`${resources.litters}/${id}`, body)
|
||||
}
|
||||
|
||||
export function deleteLitter(id: string): Promise<void> {
|
||||
return api.delete(`${resources.litters}/${id}`)
|
||||
}
|
||||
|
||||
@@ -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<CreateLitter>
|
||||
|
||||
/** Paged list envelope returned by Gridify list endpoints. */
|
||||
export interface Paged<T> {
|
||||
items: T[]
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
import { de } from '../strings/de'
|
||||
|
||||
export default function LittersPage() {
|
||||
return (
|
||||
<section>
|
||||
<h2>{de.pages.litters.title}</h2>
|
||||
<p>{de.pages.litters.comingSoon}</p>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
10
gerbil-manager-web/src/pages/WuerfeListPage.tsx
Normal file
10
gerbil-manager-web/src/pages/WuerfeListPage.tsx
Normal file
@@ -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 (
|
||||
<section className="page">
|
||||
<h2>{de.pages.litters.title}</h2>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
10
gerbil-manager-web/src/pages/WurfDetailPage.tsx
Normal file
10
gerbil-manager-web/src/pages/WurfDetailPage.tsx
Normal file
@@ -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 (
|
||||
<section className="page">
|
||||
<h2>{de.pages.litters.title}</h2>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
10
gerbil-manager-web/src/pages/WurfFormPage.tsx
Normal file
10
gerbil-manager-web/src/pages/WurfFormPage.tsx
Normal file
@@ -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 (
|
||||
<section className="page">
|
||||
<h2>{de.pages.litters.form.createTitle}</h2>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
@@ -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',
|
||||
|
||||
Reference in New Issue
Block a user