GEHEGE-RENAME: UI-Begriff Becken → Gehege + Route /gehege + Icon 🏜️
- de.ts: alle nutzer-sichtbaren 'Becken'-Strings → 'Gehege' (nav, fields, titles, buttons, validation, delete, hilfe sections) - AppShell.tsx: route /becken → /gehege, icon 🛁 → 🏜️ (Wüsten-Habitat) - App.tsx: <Route path="gehege"> + <Route path="becken/*"> redirect (bewahrt Bookmarks; BeckenRedirect leitet Unterseiten 1:1 weiter) - BeckenPage/DetailPage/FormPage: interne Links /becken → /gehege - HilfePage.tsx: hartcodierte 'Becken'-Prosa → 'Gehege' - e2e/becken-kontakte.spec.ts: goto('/becken') → goto('/gehege') Gate: build ✓ eslint ✓ vitest 82/82 ✓ e2e 120/120 ✓
This commit is contained in:
@@ -7,7 +7,7 @@ const tk = de.pages.kontakte
|
||||
test.describe('Becken', () => {
|
||||
test('Belegung: Detail zeigt Bewohner mit Link zur Tierakte', async ({ page }) => {
|
||||
skipUnlessMock()
|
||||
await page.goto('/becken')
|
||||
await page.goto('/gehege')
|
||||
await page.getByRole('link', { name: /Großbecken/ }).click()
|
||||
await expect(page.getByRole('heading', { name: 'Großbecken' })).toBeVisible()
|
||||
await expect(page.getByText(`2 ${tb.occupancy.countMany}`)).toBeVisible()
|
||||
@@ -18,7 +18,7 @@ test.describe('Becken', () => {
|
||||
|
||||
test('Löschen eines belegten Beckens meldet den 409-Konflikt auf Deutsch', async ({ page }) => {
|
||||
skipUnlessMock()
|
||||
await page.goto('/becken')
|
||||
await page.goto('/gehege')
|
||||
await page.getByRole('link', { name: /Großbecken/ }).click()
|
||||
acceptNextDialog(page)
|
||||
await page.getByRole('button', { name: tb.delete.action }).click()
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { BrowserRouter, Route, Routes } from 'react-router-dom'
|
||||
import { BrowserRouter, Navigate, Route, Routes, useParams } from 'react-router-dom'
|
||||
import AppShell from './components/AppShell'
|
||||
import BeckenPage from './pages/BeckenPage'
|
||||
import BeckenDetailPage from './pages/BeckenDetailPage'
|
||||
@@ -28,6 +28,11 @@ import WebseiteVorschauPage from './pages/WebseiteVorschauPage'
|
||||
import AnfragenPage from './pages/AnfragenPage'
|
||||
import AnfrageDetailPage from './pages/AnfrageDetailPage'
|
||||
|
||||
function BeckenRedirect() {
|
||||
const { '*': splat } = useParams()
|
||||
return <Navigate to={`/gehege${splat ? `/${splat}` : ''}`} replace />
|
||||
}
|
||||
|
||||
export default function App() {
|
||||
return (
|
||||
<BrowserRouter>
|
||||
@@ -48,7 +53,9 @@ export default function App() {
|
||||
<Route path=":id/bearbeiten" element={<WurfFormPage />} />
|
||||
</Route>
|
||||
{/* FEAT-2: Kontakte ersetzt das Züchter-Platzhalter-Routing (Breeder -> Contact) */}
|
||||
<Route path="becken">
|
||||
{/* GEHEGE-RENAME: /becken → /gehege; redirect preserves bookmarks */}
|
||||
<Route path="becken/*" element={<BeckenRedirect />} />
|
||||
<Route path="gehege">
|
||||
<Route index element={<BeckenPage />} />
|
||||
<Route path="neu" element={<BeckenFormPage />} />
|
||||
<Route path=":id" element={<BeckenDetailPage />} />
|
||||
|
||||
@@ -19,7 +19,7 @@ const PRIMARY: NavItem[] = [
|
||||
{ to: '/genetik', label: de.nav.genetics, icon: '🧬' },
|
||||
]
|
||||
const SECONDARY: NavItem[] = [
|
||||
{ to: '/becken', label: de.nav.enclosures, icon: '🛁' },
|
||||
{ to: '/gehege', label: de.nav.enclosures, icon: '🏜️' },
|
||||
{ to: '/kontakte', label: de.nav.contacts, icon: '📇' },
|
||||
{ to: '/abgabe', label: de.nav.forSale, icon: '🏡' },
|
||||
// INBOX-1: Anfragen-Posteingang
|
||||
|
||||
@@ -44,7 +44,7 @@ export default function BeckenDetailPage() {
|
||||
setDeleteError(null)
|
||||
const result = await removal.run()
|
||||
if (result.ok) {
|
||||
navigate('/becken')
|
||||
navigate('/gehege')
|
||||
} else if (result.cause instanceof ApiError && result.cause.status === 409) {
|
||||
// Backend meldet Konflikt, wenn noch Tiere im Becken wohnen.
|
||||
setDeleteError(t.delete.conflict)
|
||||
@@ -58,7 +58,7 @@ export default function BeckenDetailPage() {
|
||||
return (
|
||||
<section className="page">
|
||||
<p className="muted">{enclosure.error ?? t.detail.notFound}</p>
|
||||
<Link to="/becken" className="btn">
|
||||
<Link to="/gehege" className="btn">
|
||||
{t.detail.back}
|
||||
</Link>
|
||||
</section>
|
||||
@@ -81,7 +81,7 @@ export default function BeckenDetailPage() {
|
||||
)}
|
||||
</div>
|
||||
<div className="head-actions">
|
||||
<Link to={`/becken/${e.id}/bearbeiten`} className="btn btn--primary">
|
||||
<Link to={`/gehege/${e.id}/bearbeiten`} className="btn btn--primary">
|
||||
{t.detail.edit}
|
||||
</Link>
|
||||
<button
|
||||
@@ -92,7 +92,7 @@ export default function BeckenDetailPage() {
|
||||
>
|
||||
{t.delete.action}
|
||||
</button>
|
||||
<Link to="/becken" className="btn">
|
||||
<Link to="/gehege" className="btn">
|
||||
{t.detail.back}
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
@@ -45,7 +45,7 @@ export default function BeckenFormPage() {
|
||||
}
|
||||
setErrors({})
|
||||
const result = await mutation.run({ name: form.name.trim(), notes: nn(form.notes) })
|
||||
if (result.ok) navigate(`/becken/${result.value.id}`)
|
||||
if (result.ok) navigate(`/gehege/${result.value.id}`)
|
||||
// On failure mutation.error drives the inline alert; run() never throws.
|
||||
}
|
||||
|
||||
@@ -81,7 +81,7 @@ export default function BeckenFormPage() {
|
||||
<button type="submit" className="btn btn--primary" disabled={mutation.pending}>
|
||||
{mutation.pending ? t.form.saving : t.form.save}
|
||||
</button>
|
||||
<Link to={isEdit && id ? `/becken/${id}` : '/becken'} className="btn">
|
||||
<Link to={isEdit && id ? `/gehege/${id}` : '/gehege'} className="btn">
|
||||
{t.form.cancel}
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
@@ -35,7 +35,7 @@ export default function BeckenPage() {
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
<Link to="/becken/neu" className="btn btn--primary">
|
||||
<Link to="/gehege/neu" className="btn btn--primary">
|
||||
+ {t.newButton}
|
||||
</Link>
|
||||
</header>
|
||||
@@ -72,7 +72,7 @@ export default function BeckenPage() {
|
||||
<ul className="card-list">
|
||||
{items.map((e) => (
|
||||
<li key={e.id}>
|
||||
<Link to={`/becken/${e.id}`} className="gerbil-card">
|
||||
<Link to={`/gehege/${e.id}`} className="gerbil-card">
|
||||
<span className="gerbil-card__name">{e.name}</span>
|
||||
<span className="gerbil-card__meta">{e.notes ?? ''}</span>
|
||||
</Link>
|
||||
|
||||
@@ -38,12 +38,12 @@ const sections: Section[] = [
|
||||
<p>Die Navigation erreichst du unten (Smartphone) oder links (Laptop). Mit <strong>„{nav.more}"</strong> öffnest du alle weiteren Bereiche.</p>
|
||||
<p>Empfohlene Reihenfolge beim ersten Mal:</p>
|
||||
<ol>
|
||||
<li>Becken anlegen (wo leben deine Tiere?)</li>
|
||||
<li>Gehege anlegen (wo leben deine Tiere?)</li>
|
||||
<li>Rennmäuse anlegen mit Foto</li>
|
||||
<li>Würfe eintragen</li>
|
||||
<li>Genetik erkunden</li>
|
||||
</ol>
|
||||
<p className="hilfe-hint">Tipp: Lege zuerst die Becken an — dann kannst du beim Erfassen der Tiere direkt das richtige Becken auswählen.</p>
|
||||
<p className="hilfe-hint">Tipp: Lege zuerst die Gehege an — dann kannst du beim Erfassen der Tiere direkt das richtige Gehege auswählen.</p>
|
||||
</>
|
||||
),
|
||||
},
|
||||
@@ -53,7 +53,7 @@ const sections: Section[] = [
|
||||
content: (
|
||||
<>
|
||||
<p>Unter <strong>„{nav.gerbils}"</strong> siehst du alle deine Rennmäuse. Mit <strong>„{g.newButton}"</strong> legst du ein neues Tier an.</p>
|
||||
<p>Pflichtfelder sind <strong>„{g.fields.name}"</strong> und <strong>„{g.fields.gender}"</strong>. Optional kannst du Geburtsdatum, Farbschlag, Genotyp, Becken und Herkunft eintragen.</p>
|
||||
<p>Pflichtfelder sind <strong>„{g.fields.name}"</strong> und <strong>„{g.fields.gender}"</strong>. Optional kannst du Geburtsdatum, Farbschlag, Genotyp, Gehege und Herkunft eintragen.</p>
|
||||
<p>Auf der Detailseite findest du drei Tabs:</p>
|
||||
<ul>
|
||||
<li><strong>„{g.detail.tabs.photos}"</strong> — Fotos hochladen; das erste Foto wird als Profilfoto angezeigt.</li>
|
||||
@@ -69,9 +69,9 @@ const sections: Section[] = [
|
||||
title: t.sections.becken,
|
||||
content: (
|
||||
<>
|
||||
<p>Unter <strong>„{nav.enclosures}"</strong> verwaltest du deine Gehege. Mit <strong>„{b.newButton}"</strong> legst du ein neues Becken an (nur Name ist Pflicht).</p>
|
||||
<p>Unter <strong>„{nav.enclosures}"</strong> verwaltest du deine Gehege. Mit <strong>„{b.newButton}"</strong> legst du ein neues Gehege an (nur Name ist Pflicht).</p>
|
||||
<p>Die Detailseite zeigt dir die aktuellen <strong>„{b.occupancy.title}"</strong> — mit Links direkt zur Tierakte. So siehst du auf einen Blick, wer wo lebt.</p>
|
||||
<p>Ein Becken lässt sich nur löschen, wenn es leer ist — das schützt vor versehentlichem Datenverlust.</p>
|
||||
<p>Ein Gehege lässt sich nur löschen, wenn es leer ist — das schützt vor versehentlichem Datenverlust.</p>
|
||||
<p>Unter <strong>„{nav.contacts}"</strong> kannst du Züchter, Käufer und andere Kontakte anlegen. Diese lassen sich dann als Herkunft oder Abnehmer bei Tieren eintragen.</p>
|
||||
</>
|
||||
),
|
||||
|
||||
@@ -14,8 +14,8 @@ export const de = {
|
||||
litters: 'Würfe',
|
||||
breeders: 'Züchter',
|
||||
genetics: 'Genetik',
|
||||
// FEAT-2 (Oscar): Becken + Kontakte
|
||||
enclosures: 'Becken',
|
||||
// FEAT-2 (Oscar): Becken + Kontakte (GEHEGE-RENAME: Becken → Gehege)
|
||||
enclosures: 'Gehege',
|
||||
contacts: 'Kontakte',
|
||||
// FEAT-7 (Kelly): Statistik
|
||||
statistics: 'Statistik',
|
||||
@@ -82,7 +82,7 @@ export const de = {
|
||||
causeOfDeath: 'Todesursache',
|
||||
goHomeDate: 'Abgabedatum',
|
||||
litter: 'Wurf',
|
||||
enclosure: 'Becken',
|
||||
enclosure: 'Gehege',
|
||||
colorVariety: 'Farbschlag',
|
||||
origin: 'Herkunft',
|
||||
receiver: 'Abnehmer',
|
||||
@@ -253,8 +253,8 @@ export const de = {
|
||||
markMultiAction: 'Ausgewählte zur Abgabe stellen',
|
||||
grouping: {
|
||||
title: 'Gruppen',
|
||||
byEnclosure: 'Nach Becken vorgeschlagen',
|
||||
ungrouped: 'Ohne Becken',
|
||||
byEnclosure: 'Nach Gehege vorgeschlagen',
|
||||
ungrouped: 'Ohne Gehege',
|
||||
moveTo: 'Verschieben nach',
|
||||
newGroup: 'Neue Gruppe',
|
||||
groupLabel: 'Gruppe',
|
||||
@@ -298,12 +298,12 @@ export const de = {
|
||||
notConfigured: 'KI-Funktion: API-Schlüssel noch nicht konfiguriert.',
|
||||
},
|
||||
},
|
||||
// ── FEAT-2 (Oscar): Becken (Enclosures) ──
|
||||
// ── FEAT-2 (Oscar): Gehege (Enclosures) — GEHEGE-RENAME: Becken → Gehege ──
|
||||
becken: {
|
||||
title: 'Becken',
|
||||
newButton: 'Neues Becken',
|
||||
empty: 'Keine Becken gefunden.',
|
||||
countLabel: 'Becken',
|
||||
title: 'Gehege',
|
||||
newButton: 'Neues Gehege',
|
||||
empty: 'Keine Gehege gefunden.',
|
||||
countLabel: 'Gehege',
|
||||
searchPlaceholder: 'Name suchen …',
|
||||
fields: {
|
||||
name: 'Name',
|
||||
@@ -311,18 +311,18 @@ export const de = {
|
||||
},
|
||||
occupancy: {
|
||||
title: 'Bewohner',
|
||||
empty: 'Dieses Becken ist derzeit leer.',
|
||||
empty: 'Dieses Gehege ist derzeit leer.',
|
||||
countOne: 'Tier',
|
||||
countMany: 'Tiere',
|
||||
},
|
||||
detail: {
|
||||
edit: 'Bearbeiten',
|
||||
back: 'Zurück zur Liste',
|
||||
notFound: 'Dieses Becken wurde nicht gefunden.',
|
||||
notFound: 'Dieses Gehege wurde nicht gefunden.',
|
||||
},
|
||||
form: {
|
||||
createTitle: 'Neues Becken anlegen',
|
||||
editTitle: 'Becken bearbeiten',
|
||||
createTitle: 'Neues Gehege anlegen',
|
||||
editTitle: 'Gehege bearbeiten',
|
||||
save: 'Speichern',
|
||||
cancel: 'Abbrechen',
|
||||
saving: 'Speichern …',
|
||||
@@ -332,9 +332,9 @@ export const de = {
|
||||
},
|
||||
delete: {
|
||||
action: 'Löschen',
|
||||
confirmMessage: 'Soll dieses Becken wirklich gelöscht werden?',
|
||||
confirmMessage: 'Soll dieses Gehege wirklich gelöscht werden?',
|
||||
conflict:
|
||||
'Becken ist nicht leer — bitte zuerst alle Tiere in ein anderes Becken umsetzen.',
|
||||
'Gehege ist nicht leer — bitte zuerst alle Tiere in ein anderes Gehege umsetzen.',
|
||||
},
|
||||
},
|
||||
// ── FEAT-4 (Kelly): Stammbaum (Ahnentafel) ──
|
||||
@@ -731,7 +731,7 @@ export const de = {
|
||||
sections: {
|
||||
ersteSchritte: 'Erste Schritte',
|
||||
tiere: 'Rennmäuse anlegen & Fotos',
|
||||
becken: 'Becken',
|
||||
becken: 'Gehege',
|
||||
wuerfe: 'Würfe & Jungtiere',
|
||||
genetik: 'Probeverpaarung & Genetik',
|
||||
stammbaum: 'Stammbaum',
|
||||
|
||||
Reference in New Issue
Block a user