Build Routes tab with paginated list and Zod-validated API responses

Routes tab (Phase 3.1):
- Paginated FlatList fetching from Journal REST API
- Route cards with name, distance (km), elevation gain, day count
- Pull-to-refresh, loading spinner, error state with retry, empty state
- Safe area insets for notch and tab bar

API client:
- Import types from @trails-cool/api instead of hand-written interfaces
- Parse list/detail responses through Zod schemas at runtime
- Add zod as mobile app dependency

i18n:
- Add mobile namespace (en + de) for routes, activities, profile, login

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Ullrich Schäfer 2026-04-13 01:10:09 +02:00
parent 05659bcfc1
commit 77e3c1b1ee
No known key found for this signature in database
GPG key ID: A32FF691A0F752D9
8 changed files with 224 additions and 24 deletions

View file

@ -10,8 +10,8 @@ export const supportedLngs = ["en", "de"] as const;
export type SupportedLng = (typeof supportedLngs)[number];
export const resources = {
en: { common: en.common, planner: en.planner, journal: en.journal },
de: { common: de.common, planner: de.planner, journal: de.journal },
en: { common: en.common, planner: en.planner, journal: en.journal, mobile: en.mobile },
de: { common: de.common, planner: de.planner, journal: de.journal, mobile: de.mobile },
} as const;
const commonOptions = {

View file

@ -274,4 +274,26 @@ export default {
registerWithMagicLink: "Per Magic Link registrieren",
},
},
mobile: {
routes: {
empty: "Noch keine Routen",
emptyHint: "Erstelle deine erste Route im Planner",
retry: "Erneut versuchen",
},
activities: {
empty: "Noch keine Aktivitäten",
emptyHint: "Zeichne deine erste Aktivität auf oder importiere sie",
},
profile: {
logOut: "Abmelden",
switchServer: "Server wechseln",
switchServerConfirm: "Du wirst abgemeldet und lokale Daten werden gelöscht. Fortfahren?",
},
login: {
subtitle: "Bei deinem Journal anmelden",
signIn: "Anmelden",
connectDifferentServer: "Mit anderem Server verbinden",
serverUrl: "Server-URL",
},
},
} as const;

View file

@ -274,4 +274,26 @@ export default {
registerWithMagicLink: "Register with Magic Link",
},
},
mobile: {
routes: {
empty: "No routes yet",
emptyHint: "Create your first route in the Planner",
retry: "Retry",
},
activities: {
empty: "No activities yet",
emptyHint: "Record or import your first activity",
},
profile: {
logOut: "Log Out",
switchServer: "Switch Server",
switchServerConfirm: "This will log you out and clear local data. Continue?",
},
login: {
subtitle: "Sign in to your Journal",
signIn: "Sign In",
connectDifferentServer: "Connect to a different server",
serverUrl: "Server URL",
},
},
} as const;