831 lines
24 KiB
TypeScript
831 lines
24 KiB
TypeScript
import {
|
|
View,
|
|
Text,
|
|
StyleSheet,
|
|
TouchableOpacity,
|
|
Image,
|
|
Alert,
|
|
ScrollView,
|
|
ActivityIndicator,
|
|
} from "react-native";
|
|
import { useUser, useClerk, useAuth } from "@clerk/clerk-expo";
|
|
import { useRouter } from "expo-router";
|
|
import { Ionicons } from "@expo/vector-icons";
|
|
import { useState, useEffect } from "react";
|
|
import { useTheme } from "../../contexts/ThemeContext";
|
|
import { MinimalCard } from "../../components/MinimalCard";
|
|
import { ListItem } from "../../components/ListItem";
|
|
import { MinimalButton } from "../../components/MinimalButton";
|
|
import { Badge } from "../../components/Badge";
|
|
import { IconContainer } from "../../components/IconContainer";
|
|
import { fitnessProfileApi, FitnessProfile } from "../../api/fitnessProfile";
|
|
import { gymsApi, type Gym } from "../../api/gyms";
|
|
import { useMembership } from "../../hooks/useMembership";
|
|
import log from "../../utils/logger";
|
|
|
|
export default function ProfileScreen() {
|
|
const { user } = useUser();
|
|
const { signOut } = useClerk();
|
|
const router = useRouter();
|
|
const { colors, typography, theme: activeTheme, setTheme } = useTheme();
|
|
const { getToken } = useAuth();
|
|
const { membershipType } = useMembership();
|
|
|
|
const [gyms, setGyms] = useState<Gym[]>([]);
|
|
const [gymsLoading, setGymsLoading] = useState(false);
|
|
const [selectedGymId, setSelectedGymId] = useState<string | null>(null);
|
|
const [currentGymId, setCurrentGymId] = useState<string | null>(null);
|
|
const [currentGymName, setCurrentGymName] = useState<string | null>(null);
|
|
const [showGymDropdown, setShowGymDropdown] = useState(false);
|
|
const [fitnessProfile, setFitnessProfile] = useState<FitnessProfile | null>(
|
|
null,
|
|
);
|
|
const [profileLoading, setProfileLoading] = useState(false);
|
|
|
|
useEffect(() => {
|
|
const gid =
|
|
((user?.publicMetadata as any)?.gymId as string | undefined) ?? null;
|
|
setCurrentGymId(gid ?? null);
|
|
if (gid && gyms.length > 0) {
|
|
const g = gyms.find((x) => x.id === gid);
|
|
setCurrentGymName(g?.name ?? null);
|
|
if (selectedGymId === null) setSelectedGymId(gid);
|
|
}
|
|
}, [user?.publicMetadata, gyms]);
|
|
|
|
useEffect(() => {
|
|
loadGyms();
|
|
loadFitnessProfile();
|
|
}, []);
|
|
|
|
const loadFitnessProfile = async () => {
|
|
try {
|
|
setProfileLoading(true);
|
|
const token = await getToken();
|
|
if (!token) return;
|
|
const profile = await fitnessProfileApi.getFitnessProfile(token);
|
|
setFitnessProfile(profile);
|
|
} catch (error) {
|
|
log.error("Failed to load fitness profile", error);
|
|
} finally {
|
|
setProfileLoading(false);
|
|
}
|
|
};
|
|
|
|
const loadGyms = async () => {
|
|
try {
|
|
setGymsLoading(true);
|
|
const token = await getToken();
|
|
const list = await gymsApi.getGyms(token);
|
|
setGyms(list);
|
|
const gid =
|
|
currentGymId ??
|
|
((user?.publicMetadata as any)?.gymId as string | undefined) ??
|
|
null;
|
|
if (gid) {
|
|
const g = list.find((x) => x.id === gid);
|
|
setCurrentGymId(gid);
|
|
setCurrentGymName(g?.name ?? null);
|
|
if (selectedGymId === null) setSelectedGymId(gid);
|
|
}
|
|
} catch (err) {
|
|
log.error("Failed to fetch gyms", err);
|
|
setGyms([]);
|
|
} finally {
|
|
setGymsLoading(false);
|
|
}
|
|
};
|
|
|
|
const handleApplyGym = async () => {
|
|
try {
|
|
const token = await getToken();
|
|
await gymsApi.updateUserGym(selectedGymId, token);
|
|
setCurrentGymId(selectedGymId);
|
|
setCurrentGymName(
|
|
selectedGymId
|
|
? (gyms.find((g) => g.id === selectedGymId)?.name ?? null)
|
|
: null,
|
|
);
|
|
try {
|
|
await (user as any)?.reload?.();
|
|
} catch (e) {
|
|
log.debug("Failed to reload user after gym update", { error: e });
|
|
}
|
|
Alert.alert(
|
|
"Success",
|
|
selectedGymId ? "Gym selected successfully" : "Proceeding without gym",
|
|
);
|
|
} catch (err) {
|
|
log.error("Failed to update gym selection", err);
|
|
Alert.alert("Error", "Failed to update gym selection");
|
|
}
|
|
};
|
|
|
|
const handleSignOut = async () => {
|
|
try {
|
|
await signOut();
|
|
} catch (err) {
|
|
log.error("Failed to sign out", err);
|
|
}
|
|
};
|
|
|
|
const confirmSignOut = () => {
|
|
Alert.alert("Sign Out", "Are you sure you want to sign out?", [
|
|
{ text: "Cancel", style: "cancel" },
|
|
{ text: "Sign Out", style: "destructive", onPress: handleSignOut },
|
|
]);
|
|
};
|
|
|
|
const handleThemeChange = () => {
|
|
Alert.alert("Choose Theme", "Select your preferred theme", [
|
|
{
|
|
text: "Light",
|
|
onPress: () => setTheme("light"),
|
|
},
|
|
{
|
|
text: "Dark",
|
|
onPress: () => setTheme("dark"),
|
|
},
|
|
{
|
|
text: "System",
|
|
onPress: () => setTheme("system"),
|
|
},
|
|
{ text: "Cancel", style: "cancel" },
|
|
]);
|
|
};
|
|
|
|
const getThemeLabel = () => {
|
|
if (activeTheme === "light") return "Light";
|
|
if (activeTheme === "dark") return "Dark";
|
|
return "System";
|
|
};
|
|
|
|
return (
|
|
<ScrollView
|
|
style={[styles.container, { backgroundColor: colors.background }]}
|
|
contentContainerStyle={styles.content}
|
|
>
|
|
{/* Header Card */}
|
|
<MinimalCard
|
|
variant="elevated"
|
|
style={[styles.profileCard, { backgroundColor: colors.primary }]}
|
|
>
|
|
<View style={styles.avatarContainer}>
|
|
{user?.imageUrl ? (
|
|
<Image source={{ uri: user.imageUrl }} style={styles.avatar} />
|
|
) : (
|
|
<View
|
|
style={[
|
|
styles.placeholderAvatar,
|
|
{
|
|
backgroundColor: colors.white,
|
|
borderWidth: 3,
|
|
borderColor: colors.white,
|
|
},
|
|
]}
|
|
>
|
|
<Ionicons name="person" size={40} color={colors.primary} />
|
|
</View>
|
|
)}
|
|
</View>
|
|
<Text
|
|
style={[
|
|
typography.h1,
|
|
{ color: colors.white, marginTop: 16, fontSize: 28 },
|
|
]}
|
|
>
|
|
{user?.fullName || "User"}
|
|
</Text>
|
|
<Text
|
|
style={[
|
|
typography.body,
|
|
{ color: "rgba(255,255,255,0.8)", marginTop: 4 },
|
|
]}
|
|
>
|
|
{user?.primaryEmailAddress?.emailAddress}
|
|
</Text>
|
|
<Badge
|
|
label={`${membershipType.toUpperCase()} Member`}
|
|
variant={membershipType === "basic" ? "neutral" : "success"}
|
|
style={{ marginTop: 12 }}
|
|
/>
|
|
</MinimalCard>
|
|
|
|
{/* Theme Settings */}
|
|
<View style={styles.section}>
|
|
<Text
|
|
style={[
|
|
typography.h3,
|
|
{ color: colors.textPrimary, marginBottom: 12 },
|
|
]}
|
|
>
|
|
Appearance
|
|
</Text>
|
|
<MinimalCard variant="default">
|
|
<ListItem
|
|
title="Theme"
|
|
subtitle={`Current: ${getThemeLabel()}`}
|
|
leftIcon={
|
|
<IconContainer
|
|
variant="colored"
|
|
backgroundColor={`${colors.accent}20`}
|
|
>
|
|
<Ionicons
|
|
name="color-palette"
|
|
size={20}
|
|
color={colors.accent}
|
|
/>
|
|
</IconContainer>
|
|
}
|
|
rightElement={
|
|
<Ionicons
|
|
name="chevron-forward"
|
|
size={20}
|
|
color={colors.textTertiary}
|
|
/>
|
|
}
|
|
onPress={handleThemeChange}
|
|
/>
|
|
</MinimalCard>
|
|
</View>
|
|
|
|
{/* Account Settings */}
|
|
<View style={styles.section}>
|
|
<Text
|
|
style={[
|
|
typography.h3,
|
|
{ color: colors.textPrimary, marginBottom: 12 },
|
|
]}
|
|
>
|
|
Account
|
|
</Text>
|
|
<MinimalCard variant="default">
|
|
<ListItem
|
|
title="Personal Details"
|
|
leftIcon={
|
|
<IconContainer
|
|
variant="colored"
|
|
backgroundColor={`${colors.primary}20`}
|
|
>
|
|
<Ionicons
|
|
name="person-outline"
|
|
size={20}
|
|
color={colors.primary}
|
|
/>
|
|
</IconContainer>
|
|
}
|
|
rightElement={
|
|
<Ionicons
|
|
name="chevron-forward"
|
|
size={20}
|
|
color={colors.textTertiary}
|
|
/>
|
|
}
|
|
onPress={() => router.push("/personal-details")}
|
|
/>
|
|
<View style={[styles.divider, { backgroundColor: colors.border }]} />
|
|
|
|
{/* Fitness Profile Card */}
|
|
<TouchableOpacity
|
|
onPress={() => router.push("/fitness-profile")}
|
|
activeOpacity={0.85}
|
|
>
|
|
<MinimalCard variant="elevated" style={styles.fitnessProfileCard}>
|
|
<View style={styles.fitnessProfileHeader}>
|
|
<View
|
|
style={[
|
|
styles.fitnessProfileIcon,
|
|
{ backgroundColor: colors.success },
|
|
]}
|
|
>
|
|
<Ionicons name="fitness" size={24} color={colors.white} />
|
|
</View>
|
|
<View style={{ flex: 1, marginLeft: 14 }}>
|
|
<Text style={[typography.h4, { color: colors.textPrimary }]}>
|
|
Fitness Profile
|
|
</Text>
|
|
<Text
|
|
style={[
|
|
typography.caption,
|
|
{ color: colors.textTertiary, marginTop: 2 },
|
|
]}
|
|
>
|
|
{fitnessProfile ? "Tap to edit" : "Set up your profile"}
|
|
</Text>
|
|
</View>
|
|
<View
|
|
style={[
|
|
styles.editButton,
|
|
{ backgroundColor: colors.primary },
|
|
]}
|
|
>
|
|
<Ionicons name="pencil" size={16} color={colors.white} />
|
|
</View>
|
|
</View>
|
|
|
|
{profileLoading ? (
|
|
<View style={styles.profileLoading}>
|
|
<ActivityIndicator color={colors.primary} />
|
|
</View>
|
|
) : fitnessProfile ? (
|
|
<View
|
|
style={[
|
|
styles.fitnessProfileStats,
|
|
{ borderTopColor: colors.border },
|
|
]}
|
|
>
|
|
<View style={styles.profileStat}>
|
|
<Text
|
|
style={[
|
|
typography.statLarge,
|
|
{ color: colors.primary, fontSize: 28 },
|
|
]}
|
|
>
|
|
{fitnessProfile.height || "-"}
|
|
</Text>
|
|
<Text
|
|
style={[
|
|
typography.caption,
|
|
{ color: colors.textTertiary },
|
|
]}
|
|
>
|
|
Height (cm)
|
|
</Text>
|
|
</View>
|
|
<View
|
|
style={[
|
|
styles.profileStatDivider,
|
|
{ backgroundColor: colors.border },
|
|
]}
|
|
/>
|
|
<View style={styles.profileStat}>
|
|
<Text
|
|
style={[
|
|
typography.statLarge,
|
|
{ color: colors.success, fontSize: 28 },
|
|
]}
|
|
>
|
|
{fitnessProfile.weight || "-"}
|
|
</Text>
|
|
<Text
|
|
style={[
|
|
typography.caption,
|
|
{ color: colors.textTertiary },
|
|
]}
|
|
>
|
|
Weight (kg)
|
|
</Text>
|
|
</View>
|
|
<View
|
|
style={[
|
|
styles.profileStatDivider,
|
|
{ backgroundColor: colors.border },
|
|
]}
|
|
/>
|
|
<View style={styles.profileStat}>
|
|
<Text
|
|
style={[
|
|
typography.statLarge,
|
|
{ color: colors.warning, fontSize: 28 },
|
|
]}
|
|
>
|
|
{fitnessProfile.age || "-"}
|
|
</Text>
|
|
<Text
|
|
style={[
|
|
typography.caption,
|
|
{ color: colors.textTertiary },
|
|
]}
|
|
>
|
|
Age
|
|
</Text>
|
|
</View>
|
|
</View>
|
|
) : (
|
|
<View
|
|
style={[styles.noProfile, { borderTopColor: colors.border }]}
|
|
>
|
|
<Text
|
|
style={[typography.body, { color: colors.textSecondary }]}
|
|
>
|
|
Complete your fitness profile to get personalized
|
|
recommendations
|
|
</Text>
|
|
<MinimalButton
|
|
title="Set Up Profile"
|
|
variant="primary"
|
|
size="sm"
|
|
style={{ marginTop: 12 }}
|
|
onPress={() => router.push("/fitness-profile")}
|
|
/>
|
|
</View>
|
|
)}
|
|
</MinimalCard>
|
|
</TouchableOpacity>
|
|
|
|
<View style={[styles.divider, { backgroundColor: colors.border }]} />
|
|
<ListItem
|
|
title="Notifications"
|
|
leftIcon={
|
|
<IconContainer
|
|
variant="colored"
|
|
backgroundColor={`${colors.warning}20`}
|
|
>
|
|
<Ionicons
|
|
name="notifications-outline"
|
|
size={20}
|
|
color={colors.warning}
|
|
/>
|
|
</IconContainer>
|
|
}
|
|
rightElement={
|
|
<Ionicons
|
|
name="chevron-forward"
|
|
size={20}
|
|
color={colors.textTertiary}
|
|
/>
|
|
}
|
|
/>
|
|
</MinimalCard>
|
|
</View>
|
|
|
|
{/* Gym Selection */}
|
|
<View style={styles.section}>
|
|
<Text
|
|
style={[
|
|
typography.h3,
|
|
{ color: colors.textPrimary, marginBottom: 12 },
|
|
]}
|
|
>
|
|
Gym Selection
|
|
</Text>
|
|
|
|
<TouchableOpacity
|
|
onPress={() => setShowGymDropdown(!showGymDropdown)}
|
|
activeOpacity={0.85}
|
|
>
|
|
<MinimalCard variant="bordered" style={styles.dropdownCard}>
|
|
<View style={styles.dropdownHeader}>
|
|
<View>
|
|
<Text
|
|
style={[typography.caption, { color: colors.textTertiary }]}
|
|
>
|
|
Current Gym
|
|
</Text>
|
|
<Text
|
|
style={[
|
|
typography.bodyEmphasis,
|
|
{ color: colors.textPrimary, marginTop: 2 },
|
|
]}
|
|
>
|
|
{currentGymName || "No gym selected"}
|
|
</Text>
|
|
</View>
|
|
<View
|
|
style={[
|
|
styles.dropdownIcon,
|
|
{ backgroundColor: colors.surfaceElevated },
|
|
]}
|
|
>
|
|
<Ionicons
|
|
name={showGymDropdown ? "chevron-up" : "chevron-down"}
|
|
size={20}
|
|
color={colors.textSecondary}
|
|
/>
|
|
</View>
|
|
</View>
|
|
</MinimalCard>
|
|
</TouchableOpacity>
|
|
|
|
{showGymDropdown && (
|
|
<MinimalCard variant="elevated" style={styles.dropdownOptions}>
|
|
{gymsLoading ? (
|
|
<View style={styles.loadingContainer}>
|
|
<ActivityIndicator color={colors.primary} />
|
|
</View>
|
|
) : (
|
|
<>
|
|
<TouchableOpacity
|
|
style={[
|
|
styles.dropdownOption,
|
|
selectedGymId === null && {
|
|
backgroundColor: `${colors.primary}15`,
|
|
},
|
|
]}
|
|
onPress={() => {
|
|
setSelectedGymId(null);
|
|
setShowGymDropdown(false);
|
|
}}
|
|
>
|
|
<Text
|
|
style={[
|
|
typography.body,
|
|
{
|
|
color:
|
|
selectedGymId === null
|
|
? colors.primary
|
|
: colors.textSecondary,
|
|
fontWeight: selectedGymId === null ? "600" : "400",
|
|
},
|
|
]}
|
|
>
|
|
No Gym
|
|
</Text>
|
|
{selectedGymId === null && (
|
|
<Ionicons
|
|
name="checkmark"
|
|
size={20}
|
|
color={colors.primary}
|
|
/>
|
|
)}
|
|
</TouchableOpacity>
|
|
{gyms.map((gym) => (
|
|
<TouchableOpacity
|
|
key={gym.id}
|
|
style={[
|
|
styles.dropdownOption,
|
|
selectedGymId === gym.id && {
|
|
backgroundColor: `${colors.primary}15`,
|
|
},
|
|
]}
|
|
onPress={() => {
|
|
setSelectedGymId(gym.id);
|
|
setShowGymDropdown(false);
|
|
}}
|
|
>
|
|
<View style={{ flex: 1 }}>
|
|
<Text
|
|
style={[
|
|
typography.body,
|
|
{
|
|
color:
|
|
selectedGymId === gym.id
|
|
? colors.primary
|
|
: colors.textSecondary,
|
|
fontWeight:
|
|
selectedGymId === gym.id ? "600" : "400",
|
|
},
|
|
]}
|
|
>
|
|
{gym.name}
|
|
</Text>
|
|
{gym.location && (
|
|
<Text
|
|
style={[
|
|
typography.caption,
|
|
{ color: colors.textTertiary, marginTop: 2 },
|
|
]}
|
|
>
|
|
{gym.location}
|
|
</Text>
|
|
)}
|
|
</View>
|
|
{selectedGymId === gym.id && (
|
|
<Ionicons
|
|
name="checkmark"
|
|
size={20}
|
|
color={colors.primary}
|
|
/>
|
|
)}
|
|
</TouchableOpacity>
|
|
))}
|
|
{selectedGymId !== currentGymId && (
|
|
<MinimalButton
|
|
title="Apply Selection"
|
|
onPress={handleApplyGym}
|
|
variant="primary"
|
|
size="lg"
|
|
fullWidth
|
|
style={{ marginTop: 12 }}
|
|
/>
|
|
)}
|
|
</>
|
|
)}
|
|
</MinimalCard>
|
|
)}
|
|
</View>
|
|
|
|
{/* Support */}
|
|
<View style={styles.section}>
|
|
<Text
|
|
style={[
|
|
typography.h3,
|
|
{ color: colors.textPrimary, marginBottom: 12 },
|
|
]}
|
|
>
|
|
Support
|
|
</Text>
|
|
<MinimalCard variant="default">
|
|
<ListItem
|
|
title="Help Center"
|
|
leftIcon={
|
|
<IconContainer
|
|
variant="colored"
|
|
backgroundColor={`${colors.info}20`}
|
|
>
|
|
<Ionicons
|
|
name="help-circle-outline"
|
|
size={20}
|
|
color={colors.info}
|
|
/>
|
|
</IconContainer>
|
|
}
|
|
rightElement={
|
|
<Ionicons
|
|
name="chevron-forward"
|
|
size={20}
|
|
color={colors.textTertiary}
|
|
/>
|
|
}
|
|
/>
|
|
<View style={[styles.divider, { backgroundColor: colors.border }]} />
|
|
<ListItem
|
|
title="Privacy & Security"
|
|
leftIcon={
|
|
<IconContainer variant="subtle">
|
|
<Ionicons
|
|
name="shield-checkmark-outline"
|
|
size={20}
|
|
color={colors.textSecondary}
|
|
/>
|
|
</IconContainer>
|
|
}
|
|
rightElement={
|
|
<Ionicons
|
|
name="chevron-forward"
|
|
size={20}
|
|
color={colors.textTertiary}
|
|
/>
|
|
}
|
|
/>
|
|
</MinimalCard>
|
|
</View>
|
|
|
|
{/* Sign Out */}
|
|
<View style={styles.section}>
|
|
<MinimalButton
|
|
title="Sign Out"
|
|
onPress={confirmSignOut}
|
|
variant="danger"
|
|
size="lg"
|
|
/>
|
|
</View>
|
|
|
|
<Text
|
|
style={[
|
|
typography.caption,
|
|
{
|
|
color: colors.textTertiary,
|
|
textAlign: "center",
|
|
marginBottom: 100,
|
|
},
|
|
]}
|
|
>
|
|
Version 1.0.0
|
|
</Text>
|
|
</ScrollView>
|
|
);
|
|
}
|
|
|
|
const styles = StyleSheet.create({
|
|
container: {
|
|
flex: 1,
|
|
},
|
|
content: {
|
|
padding: 20,
|
|
paddingTop: 60,
|
|
paddingBottom: 100,
|
|
},
|
|
profileCard: {
|
|
alignItems: "center",
|
|
paddingVertical: 32,
|
|
marginBottom: 24,
|
|
},
|
|
avatarContainer: {
|
|
position: "relative",
|
|
},
|
|
avatar: {
|
|
width: 100,
|
|
height: 100,
|
|
borderRadius: 50,
|
|
},
|
|
placeholderAvatar: {
|
|
width: 100,
|
|
height: 100,
|
|
borderRadius: 50,
|
|
justifyContent: "center",
|
|
alignItems: "center",
|
|
},
|
|
section: {
|
|
marginBottom: 24,
|
|
},
|
|
sectionHeader: {
|
|
flexDirection: "row",
|
|
justifyContent: "space-between",
|
|
alignItems: "center",
|
|
marginBottom: 12,
|
|
},
|
|
divider: {
|
|
height: 1,
|
|
marginLeft: 52,
|
|
},
|
|
currentGym: {
|
|
marginBottom: 16,
|
|
paddingBottom: 16,
|
|
borderBottomWidth: 1,
|
|
borderBottomColor: "rgba(0, 0, 0, 0.05)",
|
|
},
|
|
loadingContainer: {
|
|
paddingVertical: 20,
|
|
alignItems: "center",
|
|
},
|
|
gymScroll: {
|
|
marginHorizontal: -16,
|
|
},
|
|
gymScrollContent: {
|
|
paddingHorizontal: 16,
|
|
gap: 8,
|
|
},
|
|
gymChip: {
|
|
paddingHorizontal: 16,
|
|
paddingVertical: 10,
|
|
borderRadius: 20,
|
|
borderWidth: 1.5,
|
|
marginRight: 8,
|
|
},
|
|
dropdownCard: {
|
|
padding: 16,
|
|
},
|
|
dropdownHeader: {
|
|
flexDirection: "row",
|
|
justifyContent: "space-between",
|
|
alignItems: "center",
|
|
},
|
|
dropdownIcon: {
|
|
width: 36,
|
|
height: 36,
|
|
borderRadius: 10,
|
|
justifyContent: "center",
|
|
alignItems: "center",
|
|
},
|
|
dropdownOptions: {
|
|
marginTop: 8,
|
|
padding: 8,
|
|
},
|
|
dropdownOption: {
|
|
flexDirection: "row",
|
|
alignItems: "center",
|
|
justifyContent: "space-between",
|
|
paddingVertical: 14,
|
|
paddingHorizontal: 16,
|
|
borderRadius: 12,
|
|
marginBottom: 4,
|
|
},
|
|
fitnessProfileCard: {
|
|
padding: 16,
|
|
},
|
|
fitnessProfileHeader: {
|
|
flexDirection: "row",
|
|
alignItems: "center",
|
|
},
|
|
fitnessProfileIcon: {
|
|
width: 48,
|
|
height: 48,
|
|
borderRadius: 14,
|
|
justifyContent: "center",
|
|
alignItems: "center",
|
|
},
|
|
editButton: {
|
|
width: 32,
|
|
height: 32,
|
|
borderRadius: 8,
|
|
justifyContent: "center",
|
|
alignItems: "center",
|
|
},
|
|
profileLoading: {
|
|
paddingVertical: 20,
|
|
alignItems: "center",
|
|
},
|
|
fitnessProfileStats: {
|
|
flexDirection: "row",
|
|
justifyContent: "space-around",
|
|
marginTop: 20,
|
|
paddingTop: 16,
|
|
borderTopWidth: 1,
|
|
},
|
|
profileStat: {
|
|
alignItems: "center",
|
|
flex: 1,
|
|
},
|
|
profileStatDivider: {
|
|
width: 1,
|
|
height: 40,
|
|
},
|
|
noProfile: {
|
|
marginTop: 16,
|
|
paddingTop: 16,
|
|
borderTopWidth: 1,
|
|
alignItems: "center",
|
|
},
|
|
});
|