diff --git a/mobile/app/onboarding/pet.tsx b/mobile/app/onboarding/pet.tsx index 969627e..8105700 100644 --- a/mobile/app/onboarding/pet.tsx +++ b/mobile/app/onboarding/pet.tsx @@ -57,6 +57,7 @@ export default function OnboardingPetScreen() { const [adoptionStory, setAdoptionStory] = useState(""); const [createdPet, setCreatedPet] = useState<{ id: string; name: string } | null>(null); const [createError, setCreateError] = useState(null); + const [photoUri, setPhotoUri] = useState(undefined); const pendingLegal = useQuery({ ...trpc.legal.getPendingUpdate.queryOptions(), staleTime: Infinity }); const consentStatus = useQuery({ ...trpc.legal.getUploadConsentStatus.queryOptions(), staleTime: Infinity }); @@ -188,7 +189,16 @@ export default function OnboardingPetScreen() { /> ); } else if (current === "photo" && createdPet) { - content = ; + content = ( + { + setPhotoUri(uri); + next(); + }} + /> + ); } else if (current === "spiders") { content = ; } else if (current === "source") { @@ -200,7 +210,7 @@ export default function OnboardingPetScreen() { ); } else { - content = ; + content = ; } return ( diff --git a/mobile/found.md b/mobile/found.md index 904f20d..df43175 100644 --- a/mobile/found.md +++ b/mobile/found.md @@ -218,3 +218,6 @@ Neu 7: - [x] Wunsch 09.10. (Obsidian „Mobile - UI Rework“): „Freunde einladen“ in den Einstellungen sieht nach AI-Slop aus; Onboarding dynamischer machen statt statischer Seiten. Nachtrag beim Test: Die Detailseite „Freunde einladen“ passte nicht mehr zum neuen Design. → **Umgesetzt (09.10.):** Neue `InviteCard` (`src/components/referrals/`) in den Einstellungen und oben auf `/invite`: Rang mit Abzeichen (ohne Rang gestrichelt „Dein erster Rang wartet“), markierbarer Code (Kopieren-Knopf bräuchte natives Modul), animierter Fortschrittsbalken, „Link teilen“. `/invite` neu: Ränge als Zeitleiste mit „Als Nächstes“, Status-Etiketten bei eingeladenen Tieren. Onboarding (`app/onboarding/pet.tsx` + `src/components/onboarding/flow/`): Willkommen mit 3 Regel-Karten + beiden Bestätigungen auf einer Seite → Name (Buchstabe live) → Tierart als Chips + Rasse → Beschreibung/Geschichte (legt Tier an) → Foto → Spinnen-Schalter (entfällt bei Spinne) → Herkunft (nur erstes Tier) → Abschluss mit Pfoten-Konfetti; Fortschrittsbalken, Zurück (nicht nach dem Anlegen), Android-Zurück-Geste geht einen Schritt zurück. Fund: Neue Nutzer sahen auf „Bevor es losgeht“ alle 7 Änderungsnotizen der Rechtstexte statt der Regeln — Regeln jetzt als feste App-Texte, `legal.acknowledge` unverändert (Web-Onboarding hat dasselbe Problem noch). Typecheck + Lint sauber, live im Android-Emulator (Dunkelmodus) getestet: Karte, `/invite`, kompletter Onboarding-Durchlauf mit Testtier „Testi“ (danach über „Tier löschen“ entfernt, DB geprüft). Einmal reagierte „Profil anlegen“ erst beim zweiten Tippen, nicht reproduziert. Hellmodus und iOS nicht auf Gerät geprüft. Per OTA ausgeliefert 09.10. (Runtime 1.0.6, Android + iOS). + +- [x] Gefunden 09.10. (Video-Aufnahmen): Nach dem Onboarding zeigte „Meine Tiere“ das neue Tier nur mit Anfangsbuchstaben, obwohl das Foto hochgeladen war (bis zum App-Neustart). + → **Behoben (09.10.):** `AvatarStep` lädt nach dem Upload die Tierliste neu (`pets.list` invalidiert). Außerdem zeigt der Abschluss-Screen des Onboardings jetzt das hochgeladene Foto statt des Buchstabens. Typecheck + Lint sauber, live im Emulator geprüft (Liste zeigt Foto sofort, Abschluss mit Foto). diff --git a/mobile/src/components/onboarding/AvatarStep.tsx b/mobile/src/components/onboarding/AvatarStep.tsx index 46e4f25..195fdd2 100644 --- a/mobile/src/components/onboarding/AvatarStep.tsx +++ b/mobile/src/components/onboarding/AvatarStep.tsx @@ -2,7 +2,7 @@ import { useCallback, useMemo, useState } from "react"; import { View, Text, Image as RNImage, Pressable, ActivityIndicator, StyleSheet, Alert } from "react-native"; import * as ImagePicker from "expo-image-picker"; import { useTranslation } from "react-i18next"; -import { useMutation } from "@tanstack/react-query"; +import { useMutation, useQueryClient } from "@tanstack/react-query"; import { ImagePlus, Camera } from "lucide-react-native"; import { useTRPC } from "../../api/trpc"; import { uploadPickedImage } from "../../lib/upload"; @@ -14,7 +14,8 @@ import { useTheme } from "../../context/ThemeContext"; type Props = { petId: string; petName: string; - onDone: () => void; + /** Called with the local photo URI once uploaded, or without one when skipped. */ + onDone: (uploadedPhotoUri?: string) => void; }; /** @@ -34,6 +35,8 @@ export function AvatarStep({ petId, petName, onDone }: Props) { const [error, setError] = useState(null); const getPresignedUrlMutation = useMutation(trpc.media.getPresignedUrl.mutationOptions()); + const queryClient = useQueryClient(); + const [uploadedUri, setUploadedUri] = useState(undefined); const confirmUploadMutation = useMutation(trpc.media.confirmUpload.mutationOptions()); const pickAndUpload = useCallback( @@ -47,11 +50,14 @@ export function AvatarStep({ petId, petName, onDone }: Props) { try { const { key } = await uploadPickedImage(picked, (file) => getPresignedUrlMutation.mutateAsync({ petId, ...file })); await confirmUploadMutation.mutateAsync({ petId, key }); + setUploadedUri(picked.uri); + // Lists still showed the letter avatar after onboarding until the app restarted. + queryClient.invalidateQueries({ queryKey: trpc.pets.list.queryOptions().queryKey }); } catch { setError(t("onboarding.uploadError")); } }, - [petId, getPresignedUrlMutation, confirmUploadMutation] + [petId, getPresignedUrlMutation, confirmUploadMutation, queryClient, trpc, t] ); const pickFromGallery = useCallback(async () => { @@ -67,7 +73,7 @@ export function AvatarStep({ petId, petName, onDone }: Props) { return; } await pickAndUpload(() => ImagePicker.launchCameraAsync({ quality: 0.8 })); - }, [pickAndUpload]); + }, [pickAndUpload, t]); const isUploading = getPresignedUrlMutation.isPending || confirmUploadMutation.isPending; @@ -78,7 +84,7 @@ export function AvatarStep({ petId, petName, onDone }: Props) { subtitle={t("onboarding.photoSubtitle", { name: petName })} footer={ // Ohne „Überspringen“-Link (Apple 5.1.1(iv)): „Weiter“ führt auch ohne Foto weiter. -