diff --git a/mobile/app/(app)/_layout.tsx b/mobile/app/(app)/_layout.tsx index 5cabd39..e338305 100644 --- a/mobile/app/(app)/_layout.tsx +++ b/mobile/app/(app)/_layout.tsx @@ -50,6 +50,7 @@ export default function AppLayout() { + makeStyles(colors), [colors]); + const { getToken, signOut } = useAuth(); + const { pets, clearActivePetId } = useActivePet(); + const queryClient = useQueryClient(); + const [petName, setPetName] = useState(""); + const [isDeleting, setIsDeleting] = useState(false); + const [error, setError] = useState(null); + + const isValidName = pets.some((pet) => pet.name.toLowerCase() === petName.trim().toLowerCase()); + + const deleteAccount = async () => { + setIsDeleting(true); + setError(null); + try { + const token = await getToken(); + const res = await fetch(`${env.apiUrl}/api/account/delete`, { + method: "POST", + headers: { + "Content-Type": "application/json", + ...(token ? { authorization: `Bearer ${token}` } : {}), + }, + body: JSON.stringify({ petNameConfirmation: petName.trim() }), + }); + if (!res.ok) { + const data = (await res.json().catch(() => ({}))) as { error?: string }; + throw new Error(data.error ?? t("deleteAccount.genericError")); + } + } catch (err) { + Sentry.captureException(err); + setError(err instanceof Error ? err.message : t("deleteAccount.genericError")); + setIsDeleting(false); + return; + } + + // The Clerk user no longer exists server-side, so signOut() may reject — + // either way the local session is cleared and useProtectedRoute() sends + // the user back to sign-in. + queryClient.clear(); + clearActivePetId(); + Alert.alert(t("deleteAccount.doneTitle")); + await signOut().catch(() => undefined); + }; + + const confirmDelete = () => { + Alert.alert(t("deleteAccount.finalConfirmTitle"), t("deleteAccount.finalConfirmMessage"), [ + { text: t("common.cancel"), style: "cancel" }, + { text: t("deleteAccount.confirmDelete"), style: "destructive", onPress: () => void deleteAccount() }, + ]); + }; + + return ( + + + + + {t("deleteAccount.warningTitle")} + + {t("deleteAccount.warningIntro")} + + + {DELETED_ITEMS.map((item) => ( + + ✕ + {t(`deleteAccount.${item}`)} + + ))} + + + {t("deleteAccount.confirmIntro")} + + {error ? {error} : null} + +