fix mobile profile flow and onboarding edge cases
This commit is contained in:
parent
10b58245f5
commit
8275da687b
@ -24,7 +24,12 @@
|
|||||||
"foregroundImage": "./assets/adaptive-icon.png",
|
"foregroundImage": "./assets/adaptive-icon.png",
|
||||||
"backgroundColor": "#ffffff"
|
"backgroundColor": "#ffffff"
|
||||||
},
|
},
|
||||||
"permissions": ["CAMERA", "POST_NOTIFICATIONS"]
|
"permissions": [
|
||||||
|
"CAMERA",
|
||||||
|
"POST_NOTIFICATIONS",
|
||||||
|
"android.permission.CAMERA"
|
||||||
|
],
|
||||||
|
"package": "com.anonymous.fitai"
|
||||||
},
|
},
|
||||||
"web": {
|
"web": {
|
||||||
"favicon": "./assets/favicon.png"
|
"favicon": "./assets/favicon.png"
|
||||||
|
|||||||
@ -1,11 +1,11 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
preset: 'react-native',
|
preset: "react-native",
|
||||||
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'],
|
moduleFileExtensions: ["ts", "tsx", "js", "jsx", "json", "node"],
|
||||||
setupFilesAfterEnv: ['<rootDir>/jest.setup.js'],
|
setupFilesAfterEnv: ["<rootDir>/jest.setup.js"],
|
||||||
moduleNameMapping: {
|
moduleNameMapper: {
|
||||||
'^@/(.*)$': '<rootDir>/src/$1',
|
"^@/(.*)$": "<rootDir>/src/$1",
|
||||||
},
|
},
|
||||||
transformIgnorePatterns: [
|
transformIgnorePatterns: [
|
||||||
'node_modules/(?!(jest-)?react-native|@react-native|expo|@expo|@react-navigation)',
|
"node_modules/(?!(jest-)?react-native|@react-native|expo|@expo|@react-navigation)",
|
||||||
],
|
],
|
||||||
}
|
};
|
||||||
|
|||||||
@ -33,6 +33,7 @@ export default function TabLayout() {
|
|||||||
const token = await getToken();
|
const token = await getToken();
|
||||||
if (!token) {
|
if (!token) {
|
||||||
log.warn("No token available for onboarding check");
|
log.warn("No token available for onboarding check");
|
||||||
|
setOnboardingChecked(true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -16,8 +16,7 @@ import { Ionicons } from "@expo/vector-icons";
|
|||||||
import { useTheme } from "../contexts/ThemeContext";
|
import { useTheme } from "../contexts/ThemeContext";
|
||||||
import { MinimalCard } from "../components/MinimalCard";
|
import { MinimalCard } from "../components/MinimalCard";
|
||||||
import { MinimalButton } from "../components/MinimalButton";
|
import { MinimalButton } from "../components/MinimalButton";
|
||||||
import { IconContainer } from "../components/IconContainer";
|
import { fitnessProfileApi, type FitnessProfile } from "../api/fitnessProfile";
|
||||||
import { API_BASE_URL } from "../config/api";
|
|
||||||
|
|
||||||
interface FitnessProfileData {
|
interface FitnessProfileData {
|
||||||
height?: number;
|
height?: number;
|
||||||
@ -110,39 +109,31 @@ export default function FitnessProfileScreen() {
|
|||||||
try {
|
try {
|
||||||
setFetchingProfile(true);
|
setFetchingProfile(true);
|
||||||
const token = await getToken();
|
const token = await getToken();
|
||||||
const response = await fetch(
|
if (!token || !userId) {
|
||||||
`${API_BASE_URL}/api/profile/fitness?userId=${userId}`,
|
return;
|
||||||
{
|
}
|
||||||
headers: {
|
|
||||||
Authorization: `Bearer ${token}`,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
if (response.ok) {
|
const profile = await fitnessProfileApi.getFitnessProfile(token);
|
||||||
const data = await response.json();
|
|
||||||
if (data.profile) {
|
|
||||||
let activityLevel = data.profile.activityLevel || "";
|
|
||||||
if (activityLevel === "light") activityLevel = "lightly_active";
|
|
||||||
if (activityLevel === "moderate") activityLevel = "moderately_active";
|
|
||||||
if (activityLevel === "active") activityLevel = "very_active";
|
|
||||||
|
|
||||||
setProfileData({
|
if (profile) {
|
||||||
height: data.profile.height,
|
let activityLevel = profile.activityLevel || "";
|
||||||
weight: data.profile.weight,
|
if (activityLevel === "light") activityLevel = "lightly_active";
|
||||||
age: data.profile.age,
|
if (activityLevel === "moderate") activityLevel = "moderately_active";
|
||||||
gender: data.profile.gender || "",
|
if (activityLevel === "active") activityLevel = "very_active";
|
||||||
fitnessGoal: Array.isArray(data.profile.fitnessGoals)
|
|
||||||
? data.profile.fitnessGoals[0]
|
setProfileData({
|
||||||
: typeof data.profile.fitnessGoals === "string"
|
height: profile.height,
|
||||||
? JSON.parse(data.profile.fitnessGoals)[0]
|
weight: profile.weight,
|
||||||
: "",
|
age: profile.age,
|
||||||
activityLevel: activityLevel,
|
gender: profile.gender || "",
|
||||||
medicalConditions: data.profile.medicalConditions || "",
|
fitnessGoal: Array.isArray(profile.fitnessGoals)
|
||||||
allergies: data.profile.allergies || "",
|
? profile.fitnessGoals[0]
|
||||||
injuries: data.profile.injuries || "",
|
: "",
|
||||||
});
|
activityLevel: activityLevel,
|
||||||
}
|
medicalConditions: profile.medicalConditions || "",
|
||||||
|
allergies: profile.allergies || "",
|
||||||
|
injuries: profile.injuries || "",
|
||||||
|
});
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error fetching profile:", error);
|
console.error("Error fetching profile:", error);
|
||||||
@ -155,37 +146,31 @@ export default function FitnessProfileScreen() {
|
|||||||
try {
|
try {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
const token = await getToken();
|
const token = await getToken();
|
||||||
|
if (!token || !userId) {
|
||||||
|
Alert.alert("Error", "Authentication required");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const dataToSave = {
|
const dataToSave: Omit<FitnessProfile, "id"> = {
|
||||||
userId: userId,
|
userId: userId,
|
||||||
height: profileData.height,
|
height: profileData.height,
|
||||||
weight: profileData.weight,
|
weight: profileData.weight,
|
||||||
age: profileData.age,
|
age: profileData.age,
|
||||||
gender: profileData.gender || undefined,
|
gender: (profileData.gender as FitnessProfile["gender"]) || undefined,
|
||||||
fitnessGoals: profileData.fitnessGoal ? [profileData.fitnessGoal] : [],
|
fitnessGoals: profileData.fitnessGoal ? [profileData.fitnessGoal] : [],
|
||||||
activityLevel: profileData.activityLevel || undefined,
|
activityLevel:
|
||||||
|
(profileData.activityLevel as FitnessProfile["activityLevel"]) ||
|
||||||
|
undefined,
|
||||||
medicalConditions: profileData.medicalConditions,
|
medicalConditions: profileData.medicalConditions,
|
||||||
allergies: profileData.allergies,
|
allergies: profileData.allergies,
|
||||||
injuries: profileData.injuries,
|
injuries: profileData.injuries,
|
||||||
};
|
};
|
||||||
|
|
||||||
const response = await fetch(`${API_BASE_URL}/api/profile/fitness`, {
|
await fitnessProfileApi.createFitnessProfile(dataToSave, token);
|
||||||
method: "POST",
|
|
||||||
headers: {
|
|
||||||
"Content-Type": "application/json",
|
|
||||||
Authorization: `Bearer ${token}`,
|
|
||||||
},
|
|
||||||
body: JSON.stringify(dataToSave),
|
|
||||||
});
|
|
||||||
|
|
||||||
if (response.ok) {
|
Alert.alert("Success", "Fitness profile saved successfully!", [
|
||||||
Alert.alert("Success", "Fitness profile saved successfully!", [
|
{ text: "OK", onPress: () => router.back() },
|
||||||
{ text: "OK", onPress: () => router.back() },
|
]);
|
||||||
]);
|
|
||||||
} else {
|
|
||||||
const error = await response.json();
|
|
||||||
Alert.alert("Error", error.error || "Failed to save profile");
|
|
||||||
}
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error saving profile:", error);
|
console.error("Error saving profile:", error);
|
||||||
Alert.alert("Error", "Failed to save fitness profile");
|
Alert.alert("Error", "Failed to save fitness profile");
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user