Moves the mobile app from a connectivity scaffold to a real Phase 1 app: - Migrate off Expo Go onto a local custom dev client (expo-dev-client, built via expo prebuild + expo run:android against the local Android SDK — no EAS account needed). Needed because react-native-mmkv requires native code Expo Go doesn't ship. - Persisted, MMKV-backed TanStack Query cache (PersistQueryClientProvider) plus expo-image, so a relaunch renders the last-known feed/pets/ notifications instantly instead of a blank screen while refetching. - ActivePetContext: every pet-scoped procedure requires an explicit petId server-side (no server-side "current pet"), ported from web's ActivePetContext, MMKV-backed instead of localStorage. - Bottom Tabs (Feed/Explore/Notifications/Pets) mirroring the web app's actual mobile nav, with Messages as a header button rather than a tab (matches web). Feed, PostCard, PawButton reactions, pet discovery grid, notifications list, and a conversations list are all wired to the real backend and verified against the live database. - Design tokens/components extended with PostCard/PawButton/PetAvatar/ PetIdentityBadges, all styled from the existing src/theme/tokens.ts. - Fixed a react/react-dom version mismatch surfaced along the way, and handle Clerk's needs_client_trust (Device Trust) sign-in status with an email-code step. Verified end-to-end in the Android emulator against pawfeed.org: feed scrolls and paginates with real posts/images, paw reactions toggle optimistically and persist, pet switching updates every screen, and notifications/explore show live data.
22 lines
983 B
TypeScript
22 lines
983 B
TypeScript
/**
|
|
* Ports of web's src/lib/pet-display-name.ts and format-relative-time.ts.
|
|
* Hardcoded German strings rather than next-intl (mobile has no i18n system
|
|
* yet — the whole app is German-only for now, matching sign-in.tsx).
|
|
*/
|
|
export function formatPetName(pet: { name: string; nickname?: string | null }): string {
|
|
return pet.nickname ? `${pet.name} (${pet.nickname})` : pet.name;
|
|
}
|
|
|
|
export function formatRelativeTime(date: Date | string): string {
|
|
const diffMs = Date.now() - new Date(date).getTime();
|
|
const diffSecs = Math.floor(diffMs / 1000);
|
|
const diffMins = Math.floor(diffSecs / 60);
|
|
const diffHours = Math.floor(diffMins / 60);
|
|
const diffDays = Math.floor(diffHours / 24);
|
|
if (diffSecs < 60) return "gerade eben";
|
|
if (diffMins < 60) return `vor ${diffMins} Min.`;
|
|
if (diffHours < 24) return `vor ${diffHours} Std.`;
|
|
if (diffDays < 7) return `vor ${diffDays} Tag${diffDays === 1 ? "" : "en"}`;
|
|
return new Date(date).toLocaleDateString("de-DE");
|
|
}
|