working on onboarding flow

This commit is contained in:
dimitar committed 2025-12-13 06:26:23 +01:00
1 parent 868eaa5e3d
commit d3a36b6103
19 files changed
+2062 -393

No files matched your search

+96 -5
View File
@@ -1,4 +1,4 @@
import React, { useState } from "react";
import React, { useState, useEffect } from "react";
import {
View,
Text,
@@ -18,6 +18,32 @@ export default function OnboardingScreen() {
const { getToken } = useAuth();
const router = useRouter();
const [isSubmitting, setIsSubmitting] = useState(false);
const [gyms, setGyms] = useState<
Array<{ id: string; name: string; location?: string }>
>([]);
const [gymsLoading, setGymsLoading] = useState<boolean>(false);
const [selectedGymId, setSelectedGymId] = useState<string | null>(null);
useEffect(() => {
const loadGyms = async () => {
try {
setGymsLoading(true);
const token = await getToken();
const res = await fetch("/api/gyms", {
headers: token ? { Authorization: `Bearer ${token}` } : undefined,
});
const data = await res.json();
if (Array.isArray(data)) {
setGyms(data);
}
} catch (e) {
console.error("Failed to fetch gyms:", e);
} finally {
setGymsLoading(false);
}
};
loadGyms();
}, []);
const [fitnessProfile, setFitnessProfile] = useState({
height: "",
weight: "",
@@ -41,6 +67,26 @@ export default function OnboardingScreen() {
return;
}
const token = await getToken();
if (!token) {
throw new Error("Authentication token not available");
}
// If gym was selected or cleared, patch user's gym selection first
// selectedGymId: string gym id, or null to proceed without gym
try {
await fetch("/api/users/gym", {
method: "PATCH",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${token}`,
},
body: JSON.stringify({ gymId: selectedGymId }),
});
} catch (e) {
console.warn("Failed to update gym selection:", e);
}
const fitnessData = {
clientId: user.id,
height: parseFloat(fitnessProfile.height),
@@ -59,10 +105,6 @@ export default function OnboardingScreen() {
workoutFrequency: parseInt(fitnessProfile.workoutFrequency) || 3,
};
const token = await getToken();
if (!token) {
throw new Error("Authentication token not available");
}
await fitnessProfileApi.createFitnessProfile(fitnessData, token);
router.replace("/(tabs)");
} catch (error) {
@@ -213,6 +255,55 @@ export default function OnboardingScreen() {
placeholder="Number of workouts per week"
/>
<Text style={styles.label}>Select a Gym</Text>
{gymsLoading ? (
<ActivityIndicator />
) : (
<ScrollView
horizontal
showsHorizontalScrollIndicator={false}
style={{ marginBottom: 16 }}
>
<View style={{ flexDirection: "row" }}>
<TouchableOpacity
style={[
styles.levelButton,
selectedGymId === null && styles.selectedButton,
]}
onPress={() => setSelectedGymId(null)}
>
<Text
style={[
styles.levelButtonText,
selectedGymId === null && styles.selectedButtonText,
]}
>
Proceed without gym
</Text>
</TouchableOpacity>
{gyms.map((gym) => (
<TouchableOpacity
key={gym.id}
style={[
styles.levelButton,
selectedGymId === gym.id && styles.selectedButton,
]}
onPress={() => setSelectedGymId(gym.id)}
>
<Text
style={[
styles.levelButtonText,
selectedGymId === gym.id && styles.selectedButtonText,
]}
>
{gym.name}
</Text>
</TouchableOpacity>
))}
</View>
</ScrollView>
)}
<TouchableOpacity
style={styles.submitButton}
onPress={handleSubmit}