fitness profile fix

This commit is contained in:
echo 2026-03-18 00:35:21 +01:00
parent 0776517fb7
commit 7f22a39886
3 changed files with 314 additions and 216 deletions

Binary file not shown.

View File

@ -96,9 +96,13 @@ export default function OnboardingScreen() {
const fitnessData = { const fitnessData = {
userId: user.id, userId: user.id,
height: parseFloat(fitnessProfile.height), height: fitnessProfile.height
weight: parseFloat(fitnessProfile.weight), ? parseFloat(fitnessProfile.height)
age: parseInt(fitnessProfile.age), : undefined,
weight: fitnessProfile.weight
? parseFloat(fitnessProfile.weight)
: undefined,
age: fitnessProfile.age ? parseInt(fitnessProfile.age, 10) : undefined,
fitnessGoals: fitnessProfile.goals ? [fitnessProfile.goals] : [], fitnessGoals: fitnessProfile.goals ? [fitnessProfile.goals] : [],
medicalConditions: fitnessProfile.medicalConditions || undefined, medicalConditions: fitnessProfile.medicalConditions || undefined,
allergies: fitnessProfile.dietaryRestrictions || undefined, allergies: fitnessProfile.dietaryRestrictions || undefined,

View File

@ -13,8 +13,10 @@ import {
import { useRouter, Stack } from "expo-router"; import { useRouter, Stack } from "expo-router";
import { useAuth } from "@clerk/clerk-expo"; import { useAuth } from "@clerk/clerk-expo";
import { Ionicons } from "@expo/vector-icons"; import { Ionicons } from "@expo/vector-icons";
import { LinearGradient } from "expo-linear-gradient"; import { useTheme } from "../contexts/ThemeContext";
import { theme } from "../styles/theme"; import { MinimalCard } from "../components/MinimalCard";
import { MinimalButton } from "../components/MinimalButton";
import { IconContainer } from "../components/IconContainer";
import { API_BASE_URL } from "../config/api"; import { API_BASE_URL } from "../config/api";
interface FitnessProfileData { interface FitnessProfileData {
@ -30,13 +32,13 @@ interface FitnessProfileData {
} }
const GENDER_OPTIONS = [ const GENDER_OPTIONS = [
{ label: "Male", value: "male", icon: "male" }, { label: "Male", value: "male", icon: "male-outline" },
{ label: "Female", value: "female", icon: "female" }, { label: "Female", value: "female", icon: "female-outline" },
{ label: "Other", value: "other", icon: "transgender" }, { label: "Other", value: "other", icon: "transgender-outline" },
{ {
label: "Prefer not to say", label: "Prefer not to say",
value: "prefer_not_to_say", value: "prefer_not_to_say",
icon: "help-circle", icon: "help-circle-outline",
}, },
]; ];
@ -45,31 +47,26 @@ const FITNESS_GOAL_OPTIONS = [
label: "Weight Loss", label: "Weight Loss",
value: "weight_loss", value: "weight_loss",
icon: "trending-down", icon: "trending-down",
color: theme.colors.danger, color: "#FF3B3B",
}, },
{ {
label: "Muscle Gain", label: "Muscle Gain",
value: "muscle_gain", value: "muscle_gain",
icon: "barbell", icon: "barbell",
color: theme.colors.primary, color: "#0066FF",
},
{
label: "Endurance",
value: "endurance",
icon: "bicycle",
color: theme.colors.success,
}, },
{ label: "Endurance", value: "endurance", icon: "bicycle", color: "#00D26A" },
{ {
label: "Flexibility", label: "Flexibility",
value: "flexibility", value: "flexibility",
icon: "body", icon: "body",
color: theme.colors.purple, color: "#7B2CBF",
}, },
{ {
label: "General Fitness", label: "General Fitness",
value: "general_fitness", value: "general_fitness",
icon: "fitness", icon: "fitness",
color: theme.colors.warning, color: "#FFB800",
}, },
]; ];
@ -99,6 +96,7 @@ const ACTIVITY_LEVEL_OPTIONS = [
export default function FitnessProfileScreen() { export default function FitnessProfileScreen() {
const router = useRouter(); const router = useRouter();
const { colors, typography } = useTheme();
const { userId, getToken } = useAuth(); const { userId, getToken } = useAuth();
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const [fetchingProfile, setFetchingProfile] = useState(true); const [fetchingProfile, setFetchingProfile] = useState(true);
@ -124,7 +122,6 @@ export default function FitnessProfileScreen() {
if (response.ok) { if (response.ok) {
const data = await response.json(); const data = await response.json();
if (data.profile) { if (data.profile) {
// Normalize old activity level values to new schema
let activityLevel = data.profile.activityLevel || ""; let activityLevel = data.profile.activityLevel || "";
if (activityLevel === "light") activityLevel = "lightly_active"; if (activityLevel === "light") activityLevel = "lightly_active";
if (activityLevel === "moderate") activityLevel = "moderately_active"; if (activityLevel === "moderate") activityLevel = "moderately_active";
@ -159,8 +156,6 @@ export default function FitnessProfileScreen() {
setLoading(true); setLoading(true);
const token = await getToken(); const token = await getToken();
// Prepare data with userId and convert fitnessGoal to fitnessGoals array
// Convert empty strings to undefined for optional enum fields
const dataToSave = { const dataToSave = {
userId: userId, userId: userId,
height: profileData.height, height: profileData.height,
@ -205,8 +200,13 @@ export default function FitnessProfileScreen() {
if (fetchingProfile) { if (fetchingProfile) {
return ( return (
<View style={styles.loadingContainer}> <View
<ActivityIndicator size="large" color={theme.colors.primary} /> style={[
styles.loadingContainer,
{ backgroundColor: colors.background },
]}
>
<ActivityIndicator size="large" color={colors.primary} />
</View> </View>
); );
} }
@ -214,18 +214,28 @@ export default function FitnessProfileScreen() {
return ( return (
<> <>
<Stack.Screen options={{ headerShown: false }} /> <Stack.Screen options={{ headerShown: false }} />
<View style={styles.container}> <View style={[styles.container, { backgroundColor: colors.background }]}>
{/* Header */} {/* Header */}
<LinearGradient colors={theme.gradients.primary} style={styles.header}> <View
style={[
styles.header,
{
backgroundColor: colors.primary,
paddingTop: Platform.OS === "ios" ? 60 : 40,
},
]}
>
<TouchableOpacity <TouchableOpacity
style={styles.backButton} style={styles.backButton}
onPress={() => router.back()} onPress={() => router.back()}
> >
<Ionicons name="arrow-back" size={24} color="#fff" /> <Ionicons name="arrow-back" size={24} color="#fff" />
</TouchableOpacity> </TouchableOpacity>
<Text style={styles.headerTitle}>Fitness Profile</Text> <Text style={[typography.h2, { color: "#fff" }]}>
Fitness Profile
</Text>
<View style={{ width: 40 }} /> <View style={{ width: 40 }} />
</LinearGradient> </View>
<ScrollView <ScrollView
style={styles.scrollView} style={styles.scrollView}
@ -234,19 +244,41 @@ export default function FitnessProfileScreen() {
> >
{/* Basic Information */} {/* Basic Information */}
<View style={styles.section}> <View style={styles.section}>
<Text style={styles.sectionTitle}>Basic Information</Text> <Text
<View style={styles.card}> style={[
<View style={styles.row}> typography.h3,
{ color: colors.textPrimary, marginBottom: 16 },
]}
>
Basic Information
</Text>
<MinimalCard variant="elevated" style={styles.card}>
<View style={styles.inputRow}>
<View style={styles.inputGroup}> <View style={styles.inputGroup}>
<Text style={styles.label}>Height (cm)</Text> <Text
<View style={styles.inputContainer}> style={[
typography.label,
{ color: colors.textSecondary, marginBottom: 8 },
]}
>
HEIGHT (CM)
</Text>
<View
style={[
styles.inputContainer,
{
backgroundColor: colors.surfaceElevated,
borderColor: colors.border,
},
]}
>
<Ionicons <Ionicons
name="resize-outline" name="resize"
size={20} size={20}
color={theme.colors.gray400} color={colors.textTertiary}
/> />
<TextInput <TextInput
style={styles.input} style={[styles.input, { color: colors.textPrimary }]}
value={profileData.height?.toString() || ""} value={profileData.height?.toString() || ""}
onChangeText={(text) => onChangeText={(text) =>
updateField( updateField(
@ -256,20 +288,35 @@ export default function FitnessProfileScreen() {
} }
keyboardType="decimal-pad" keyboardType="decimal-pad"
placeholder="175" placeholder="175"
placeholderTextColor={theme.colors.gray400} placeholderTextColor={colors.textTertiary}
/> />
</View> </View>
</View> </View>
<View style={styles.inputGroup}> <View style={styles.inputGroup}>
<Text style={styles.label}>Weight (kg)</Text> <Text
<View style={styles.inputContainer}> style={[
typography.label,
{ color: colors.textSecondary, marginBottom: 8 },
]}
>
WEIGHT (KG)
</Text>
<View
style={[
styles.inputContainer,
{
backgroundColor: colors.surfaceElevated,
borderColor: colors.border,
},
]}
>
<Ionicons <Ionicons
name="scale-outline" name="scale"
size={20} size={20}
color={theme.colors.gray400} color={colors.textTertiary}
/> />
<TextInput <TextInput
style={styles.input} style={[styles.input, { color: colors.textPrimary }]}
value={profileData.weight?.toString() || ""} value={profileData.weight?.toString() || ""}
onChangeText={(text) => onChangeText={(text) =>
updateField( updateField(
@ -279,45 +326,75 @@ export default function FitnessProfileScreen() {
} }
keyboardType="decimal-pad" keyboardType="decimal-pad"
placeholder="70" placeholder="70"
placeholderTextColor={theme.colors.gray400} placeholderTextColor={colors.textTertiary}
/> />
</View> </View>
</View> </View>
</View> </View>
<View style={styles.inputGroup}> <View style={styles.inputGroup}>
<Text style={styles.label}>Age</Text> <Text
<View style={styles.inputContainer}> style={[
typography.label,
{ color: colors.textSecondary, marginBottom: 8 },
]}
>
AGE
</Text>
<View
style={[
styles.inputContainer,
{
backgroundColor: colors.surfaceElevated,
borderColor: colors.border,
},
]}
>
<Ionicons <Ionicons
name="calendar-outline" name="calendar"
size={20} size={20}
color={theme.colors.gray400} color={colors.textTertiary}
/> />
<TextInput <TextInput
style={styles.input} style={[styles.input, { color: colors.textPrimary }]}
value={profileData.age?.toString() || ""} value={profileData.age?.toString() || ""}
onChangeText={(text) => onChangeText={(text) =>
updateField("age", text ? parseInt(text, 10) : undefined) updateField("age", text ? parseInt(text, 10) : undefined)
} }
keyboardType="number-pad" keyboardType="number-pad"
placeholder="25" placeholder="25"
placeholderTextColor={theme.colors.gray400} placeholderTextColor={colors.textTertiary}
/> />
</View> </View>
</View> </View>
</View> </MinimalCard>
</View> </View>
{/* Gender Selection */} {/* Gender Selection */}
<View style={styles.section}> <View style={styles.section}>
<Text style={styles.sectionTitle}>Gender</Text> <Text
<View style={styles.optionsRow}> style={[
typography.h3,
{ color: colors.textPrimary, marginBottom: 16 },
]}
>
Gender
</Text>
<View style={styles.genderRow}>
{GENDER_OPTIONS.map((option) => ( {GENDER_OPTIONS.map((option) => (
<TouchableOpacity <TouchableOpacity
key={option.value} key={option.value}
style={[ style={[
styles.optionCard, styles.genderCard,
profileData.gender === option.value && {
styles.optionCardActive, backgroundColor:
profileData.gender === option.value
? colors.primary
: colors.surfaceElevated,
borderColor:
profileData.gender === option.value
? colors.primary
: colors.border,
},
]} ]}
onPress={() => updateField("gender", option.value)} onPress={() => updateField("gender", option.value)}
> >
@ -326,15 +403,22 @@ export default function FitnessProfileScreen() {
size={24} size={24}
color={ color={
profileData.gender === option.value profileData.gender === option.value
? theme.colors.primary ? "#fff"
: theme.colors.gray400 : colors.textTertiary
} }
/> />
<Text <Text
style={[ style={[
styles.optionLabel, typography.caption,
profileData.gender === option.value && {
styles.optionLabelActive, color:
profileData.gender === option.value
? "#fff"
: colors.textSecondary,
fontWeight:
profileData.gender === option.value ? "700" : "500",
marginTop: 6,
},
]} ]}
> >
{option.label} {option.label}
@ -346,8 +430,15 @@ export default function FitnessProfileScreen() {
{/* Fitness Goal */} {/* Fitness Goal */}
<View style={styles.section}> <View style={styles.section}>
<Text style={styles.sectionTitle}>Primary Fitness Goal</Text> <Text
<View style={styles.card}> style={[
typography.h3,
{ color: colors.textPrimary, marginBottom: 16 },
]}
>
Primary Fitness Goal
</Text>
<MinimalCard variant="elevated" style={styles.card}>
{FITNESS_GOAL_OPTIONS.map((option, index) => ( {FITNESS_GOAL_OPTIONS.map((option, index) => (
<React.Fragment key={option.value}> <React.Fragment key={option.value}>
<TouchableOpacity <TouchableOpacity
@ -366,27 +457,46 @@ export default function FitnessProfileScreen() {
color={option.color} color={option.color}
/> />
</View> </View>
<Text style={styles.listItemText}>{option.label}</Text> <Text
style={[
typography.bodyEmphasis,
{ color: colors.textPrimary, flex: 1 },
]}
>
{option.label}
</Text>
{profileData.fitnessGoal === option.value && ( {profileData.fitnessGoal === option.value && (
<Ionicons <Ionicons
name="checkmark-circle" name="checkmark-circle"
size={24} size={24}
color={theme.colors.primary} color={colors.primary}
/> />
)} )}
</TouchableOpacity> </TouchableOpacity>
{index < FITNESS_GOAL_OPTIONS.length - 1 && ( {index < FITNESS_GOAL_OPTIONS.length - 1 && (
<View style={styles.divider} /> <View
style={[
styles.divider,
{ backgroundColor: colors.border },
]}
/>
)} )}
</React.Fragment> </React.Fragment>
))} ))}
</View> </MinimalCard>
</View> </View>
{/* Activity Level */} {/* Activity Level */}
<View style={styles.section}> <View style={styles.section}>
<Text style={styles.sectionTitle}>Activity Level</Text> <Text
<View style={styles.card}> style={[
typography.h3,
{ color: colors.textPrimary, marginBottom: 16 },
]}
>
Activity Level
</Text>
<MinimalCard variant="elevated" style={styles.card}>
{ACTIVITY_LEVEL_OPTIONS.map((option, index) => ( {ACTIVITY_LEVEL_OPTIONS.map((option, index) => (
<React.Fragment key={option.value}> <React.Fragment key={option.value}>
<TouchableOpacity <TouchableOpacity
@ -394,8 +504,20 @@ export default function FitnessProfileScreen() {
onPress={() => updateField("activityLevel", option.value)} onPress={() => updateField("activityLevel", option.value)}
> >
<View style={{ flex: 1 }}> <View style={{ flex: 1 }}>
<Text style={styles.listItemText}>{option.label}</Text> <Text
<Text style={styles.listItemDescription}> style={[
typography.bodyEmphasis,
{ color: colors.textPrimary },
]}
>
{option.label}
</Text>
<Text
style={[
typography.caption,
{ color: colors.textTertiary, marginTop: 2 },
]}
>
{option.description} {option.description}
</Text> </Text>
</View> </View>
@ -403,90 +525,141 @@ export default function FitnessProfileScreen() {
<Ionicons <Ionicons
name="checkmark-circle" name="checkmark-circle"
size={24} size={24}
color={theme.colors.primary} color={colors.primary}
/> />
)} )}
</TouchableOpacity> </TouchableOpacity>
{index < ACTIVITY_LEVEL_OPTIONS.length - 1 && ( {index < ACTIVITY_LEVEL_OPTIONS.length - 1 && (
<View style={styles.divider} /> <View
style={[
styles.divider,
{ backgroundColor: colors.border },
]}
/>
)} )}
</React.Fragment> </React.Fragment>
))} ))}
</View> </MinimalCard>
</View> </View>
{/* Health Information */} {/* Health Information */}
<View style={styles.section}> <View style={styles.section}>
<Text style={styles.sectionTitle}> <Text
Health Information (Optional) style={[
typography.h3,
{ color: colors.textPrimary, marginBottom: 16 },
]}
>
Health Information
</Text> </Text>
<View style={styles.card}> <MinimalCard variant="elevated" style={styles.card}>
<View style={styles.inputGroup}> <View style={styles.inputGroup}>
<Text style={styles.label}>Medical Conditions</Text> <Text
style={[
typography.label,
{ color: colors.textSecondary, marginBottom: 8 },
]}
>
MEDICAL CONDITIONS
</Text>
<TextInput <TextInput
style={[styles.textArea]} style={[
styles.textArea,
{
backgroundColor: colors.surfaceElevated,
borderColor: colors.border,
color: colors.textPrimary,
},
]}
value={profileData.medicalConditions || ""} value={profileData.medicalConditions || ""}
onChangeText={(text) => onChangeText={(text) =>
updateField("medicalConditions", text) updateField("medicalConditions", text)
} }
placeholder="e.g., Asthma, diabetes..." placeholder="e.g., Asthma, diabetes..."
placeholderTextColor={theme.colors.gray400} placeholderTextColor={colors.textTertiary}
multiline multiline
numberOfLines={3} numberOfLines={3}
textAlignVertical="top" textAlignVertical="top"
/> />
</View> </View>
<View style={styles.inputGroup}> <View style={styles.inputGroup}>
<Text style={styles.label}>Allergies</Text> <Text
style={[
typography.label,
{ color: colors.textSecondary, marginBottom: 8 },
]}
>
ALLERGIES
</Text>
<TextInput <TextInput
style={[styles.textArea]} style={[
styles.textArea,
{
backgroundColor: colors.surfaceElevated,
borderColor: colors.border,
color: colors.textPrimary,
},
]}
value={profileData.allergies || ""} value={profileData.allergies || ""}
onChangeText={(text) => updateField("allergies", text)} onChangeText={(text) => updateField("allergies", text)}
placeholder="e.g., Peanuts, latex..." placeholder="e.g., Peanuts, latex..."
placeholderTextColor={theme.colors.gray400} placeholderTextColor={colors.textTertiary}
multiline multiline
numberOfLines={3} numberOfLines={3}
textAlignVertical="top" textAlignVertical="top"
/> />
</View> </View>
<View style={styles.inputGroup}> <View style={styles.inputGroup}>
<Text style={styles.label}>Injuries</Text> <Text
style={[
typography.label,
{ color: colors.textSecondary, marginBottom: 8 },
]}
>
INJURIES
</Text>
<TextInput <TextInput
style={[styles.textArea]} style={[
styles.textArea,
{
backgroundColor: colors.surfaceElevated,
borderColor: colors.border,
color: colors.textPrimary,
},
]}
value={profileData.injuries || ""} value={profileData.injuries || ""}
onChangeText={(text) => updateField("injuries", text)} onChangeText={(text) => updateField("injuries", text)}
placeholder="e.g., Previous knee injury..." placeholder="e.g., Previous knee injury..."
placeholderTextColor={theme.colors.gray400} placeholderTextColor={colors.textTertiary}
multiline multiline
numberOfLines={3} numberOfLines={3}
textAlignVertical="top" textAlignVertical="top"
/> />
</View> </View>
</View> </MinimalCard>
</View> </View>
<View style={{ height: 120 }} />
</ScrollView> </ScrollView>
{/* Save Button */} {/* Save Button */}
<View style={styles.footer}> <View
<TouchableOpacity style={[
style={[styles.saveButton, loading && styles.saveButtonDisabled]} styles.footer,
{
backgroundColor: colors.background,
borderTopColor: colors.border,
},
]}
>
<MinimalButton
title="Save Profile"
onPress={handleSave} onPress={handleSave}
disabled={loading} variant="primary"
> size="xl"
<LinearGradient fullWidth
colors={theme.gradients.primary} loading={loading}
style={styles.saveButtonGradient} />
>
{loading ? (
<ActivityIndicator color="#fff" />
) : (
<>
<Ionicons name="checkmark-circle" size={20} color="#fff" />
<Text style={styles.saveButtonText}>Save Profile</Text>
</>
)}
</LinearGradient>
</TouchableOpacity>
</View> </View>
</View> </View>
</> </>
@ -496,35 +669,27 @@ export default function FitnessProfileScreen() {
const styles = StyleSheet.create({ const styles = StyleSheet.create({
container: { container: {
flex: 1, flex: 1,
backgroundColor: theme.colors.background,
}, },
loadingContainer: { loadingContainer: {
flex: 1, flex: 1,
justifyContent: "center", justifyContent: "center",
alignItems: "center", alignItems: "center",
backgroundColor: theme.colors.background,
}, },
header: { header: {
flexDirection: "row", flexDirection: "row",
alignItems: "center", alignItems: "center",
justifyContent: "space-between", justifyContent: "space-between",
paddingTop: Platform.OS === "ios" ? 60 : 40,
paddingBottom: 20, paddingBottom: 20,
paddingHorizontal: 20, paddingHorizontal: 20,
}, },
backButton: { backButton: {
width: 40, width: 40,
height: 40, height: 40,
borderRadius: 20, borderRadius: 12,
backgroundColor: "rgba(255, 255, 255, 0.2)", backgroundColor: "rgba(255, 255, 255, 0.2)",
justifyContent: "center", justifyContent: "center",
alignItems: "center", alignItems: "center",
}, },
headerTitle: {
fontSize: theme.typography.fontSize["2xl"],
fontWeight: theme.typography.fontWeight.bold,
color: "#fff",
},
scrollView: { scrollView: {
flex: 1, flex: 1,
}, },
@ -533,118 +698,69 @@ const styles = StyleSheet.create({
paddingBottom: 100, paddingBottom: 100,
}, },
section: { section: {
marginBottom: 24, marginBottom: 28,
},
sectionTitle: {
fontSize: theme.typography.fontSize.lg,
fontWeight: theme.typography.fontWeight.bold,
color: theme.colors.gray900,
marginBottom: 12,
}, },
card: { card: {
backgroundColor: "#fff", padding: 4,
borderRadius: theme.borderRadius.xl,
padding: 16,
...theme.shadows.subtle,
borderWidth: 1,
borderColor: theme.colors.gray100,
}, },
row: { inputRow: {
flexDirection: "row", flexDirection: "row",
gap: 12, gap: 12,
marginBottom: 16,
}, },
inputGroup: { inputGroup: {
flex: 1, flex: 1,
marginBottom: 16, marginBottom: 4,
},
label: {
fontSize: theme.typography.fontSize.sm,
fontWeight: theme.typography.fontWeight.semibold,
color: theme.colors.gray700,
marginBottom: 8,
}, },
inputContainer: { inputContainer: {
flexDirection: "row", flexDirection: "row",
alignItems: "center", alignItems: "center",
backgroundColor: theme.colors.gray50, borderRadius: 14,
borderRadius: theme.borderRadius.lg, borderWidth: 1.5,
borderWidth: 1, paddingHorizontal: 14,
borderColor: theme.colors.gray200, gap: 10,
paddingHorizontal: 12,
gap: 8,
}, },
input: { input: {
flex: 1, flex: 1,
paddingVertical: 12, paddingVertical: 14,
fontSize: theme.typography.fontSize.base, fontSize: 16,
color: theme.colors.gray900, fontWeight: "600",
}, },
textArea: { textArea: {
backgroundColor: theme.colors.gray50, borderRadius: 14,
borderRadius: theme.borderRadius.lg, borderWidth: 1.5,
borderWidth: 1, padding: 14,
borderColor: theme.colors.gray200, fontSize: 16,
padding: 12, minHeight: 90,
fontSize: theme.typography.fontSize.base,
color: theme.colors.gray900,
minHeight: 80,
}, },
optionsRow: { genderRow: {
flexDirection: "row", flexDirection: "row",
gap: 12, gap: 10,
}, },
optionCard: { genderCard: {
flex: 1, flex: 1,
backgroundColor: "#fff", paddingVertical: 16,
borderRadius: theme.borderRadius.lg, paddingHorizontal: 8,
padding: 16, borderRadius: 14,
alignItems: "center",
gap: 8,
borderWidth: 2, borderWidth: 2,
borderColor: theme.colors.gray200, alignItems: "center",
...theme.shadows.subtle,
},
optionCardActive: {
borderColor: theme.colors.primary,
backgroundColor: `${theme.colors.primary}10`,
},
optionLabel: {
fontSize: theme.typography.fontSize.sm,
fontWeight: theme.typography.fontWeight.medium,
color: theme.colors.gray600,
},
optionLabelActive: {
color: theme.colors.primary,
fontWeight: theme.typography.fontWeight.bold,
}, },
listItem: { listItem: {
flexDirection: "row", flexDirection: "row",
alignItems: "center", alignItems: "center",
paddingVertical: 12, paddingVertical: 14,
gap: 12, paddingHorizontal: 12,
gap: 14,
}, },
iconCircle: { iconCircle: {
width: 40, width: 44,
height: 40, height: 44,
borderRadius: 20, borderRadius: 12,
justifyContent: "center", justifyContent: "center",
alignItems: "center", alignItems: "center",
}, },
listItemText: {
flex: 1,
fontSize: theme.typography.fontSize.base,
fontWeight: theme.typography.fontWeight.medium,
color: theme.colors.gray900,
},
listItemDescription: {
fontSize: theme.typography.fontSize.xs,
color: theme.colors.gray500,
marginTop: 2,
},
divider: { divider: {
height: 1, height: 1,
backgroundColor: theme.colors.gray100, marginLeft: 58,
}, },
footer: { footer: {
position: "absolute", position: "absolute",
@ -652,29 +768,7 @@ const styles = StyleSheet.create({
left: 0, left: 0,
right: 0, right: 0,
padding: 20, padding: 20,
paddingBottom: Platform.OS === "ios" ? 40 : 20, paddingBottom: 34,
backgroundColor: "#fff",
borderTopWidth: 1, borderTopWidth: 1,
borderTopColor: theme.colors.gray100,
...theme.shadows.medium,
},
saveButton: {
borderRadius: theme.borderRadius.lg,
overflow: "hidden",
},
saveButtonGradient: {
flexDirection: "row",
alignItems: "center",
justifyContent: "center",
paddingVertical: 16,
gap: 8,
},
saveButtonDisabled: {
opacity: 0.6,
},
saveButtonText: {
fontSize: theme.typography.fontSize.base,
fontWeight: theme.typography.fontWeight.bold,
color: "#fff",
}, },
}); });