redesign completed

alot of work ahead
This commit is contained in:
dimitar committed 2025-11-26 02:31:46 +01:00
1 parent 73d2c4c1ed
commit febcdc111e
18 files changed
+1591 -845

No files matched your search

+179 -357
View File
@@ -1,239 +1,118 @@
import React, { useEffect, useRef } from "react";
import {
View,
Text,
StyleSheet,
ScrollView,
TouchableOpacity,
Animated,
} from "react-native";
import { View, Text, StyleSheet, ScrollView, RefreshControl, Image } from "react-native";
import { useUser } from "@clerk/clerk-expo";
import { Ionicons } from "@expo/vector-icons";
import { useRouter } from "expo-router";
import { LinearGradient } from "expo-linear-gradient";
import { useState, useCallback } from "react";
import { theme } from "../../styles/theme";
import { ActivityWidget } from "../../components/ActivityWidget";
import { QuickActionGrid } from "../../components/QuickActionGrid";
import { Ionicons } from "@expo/vector-icons";
export default function HomeScreen() {
const { user, isLoaded } = useUser();
const router = useRouter();
const fadeAnim = useRef(new Animated.Value(0)).current;
const { user } = useUser();
const [refreshing, setRefreshing] = useState(false);
useEffect(() => {
Animated.timing(fadeAnim, {
toValue: 1,
duration: 500,
useNativeDriver: true,
}).start();
const onRefresh = useCallback(() => {
setRefreshing(true);
setTimeout(() => {
setRefreshing(false);
}, 2000);
}, []);
if (!isLoaded || !user) {
return (
<View style={styles.container}>
<Text>Loading...</Text>
</View>
);
}
const firstName = user.firstName || "User";
const greeting = getGreeting();
const getGreeting = () => {
const hour = new Date().getHours();
if (hour < 12) return "Good Morning";
if (hour < 18) return "Good Afternoon";
return "Good Evening";
};
return (
<ScrollView style={styles.container}>
<Animated.View style={[styles.content, { opacity: fadeAnim }]}>
{/* Gradient Header */}
<LinearGradient
colors={theme.gradients.primary}
start={{ x: 0, y: 0 }}
end={{ x: 1, y: 1 }}
style={styles.header}
>
<Text style={styles.greeting}>{greeting}!</Text>
<Text style={styles.name}>{firstName}</Text>
</LinearGradient>
{/* Quick Stats with Glassmorphism */}
<View style={styles.statsContainer}>
<LinearGradient
colors={['rgba(59, 130, 246, 0.1)', 'rgba(139, 92, 246, 0.1)']}
style={[styles.statCard, theme.shadows.medium]}
>
<View style={styles.statIconContainer}>
<LinearGradient
colors={theme.gradients.primary}
style={styles.statIconGradient}
>
<Ionicons name="calendar-outline" size={24} color="#fff" />
</LinearGradient>
</View>
<Text style={styles.statValue}>0</Text>
<Text style={styles.statLabel}>This Month</Text>
</LinearGradient>
<LinearGradient
colors={['rgba(239, 68, 68, 0.1)', 'rgba(236, 72, 153, 0.1)']}
style={[styles.statCard, theme.shadows.medium]}
>
<View style={styles.statIconContainer}>
<LinearGradient
colors={theme.gradients.danger}
style={styles.statIconGradient}
>
<Ionicons name="flame-outline" size={24} color="#fff" />
</LinearGradient>
</View>
<Text style={styles.statValue}>0</Text>
<Text style={styles.statLabel}>Day Streak</Text>
</LinearGradient>
<LinearGradient
colors={['rgba(245, 158, 11, 0.1)', 'rgba(217, 119, 6, 0.1)']}
style={[styles.statCard, theme.shadows.medium]}
>
<View style={styles.statIconContainer}>
<LinearGradient
colors={theme.gradients.warning}
style={styles.statIconGradient}
>
<Ionicons name="trophy-outline" size={24} color="#fff" />
</LinearGradient>
</View>
<Text style={styles.statValue}>0</Text>
<Text style={styles.statLabel}>Total Visits</Text>
</LinearGradient>
</View>
{/* Quick Actions */}
<View style={styles.section}>
<Text style={styles.sectionTitle}>Quick Actions</Text>
<TouchableOpacity
style={[styles.actionButton, theme.shadows.medium]}
onPress={() => router.push("/fitness-profile")}
activeOpacity={0.7}
>
<LinearGradient
colors={['rgba(236, 72, 153, 0.15)', 'rgba(236, 72, 153, 0.05)']}
style={styles.actionIcon}
>
<Ionicons name="fitness-outline" size={24} color="#ec4899" />
</LinearGradient>
<View style={styles.actionContent}>
<Text style={styles.actionTitle}>Fitness Profile</Text>
<Text style={styles.actionSubtitle}>
Manage your fitness information
</Text>
</View>
<Ionicons name="chevron-forward" size={20} color="#9ca3af" />
</TouchableOpacity>
<TouchableOpacity
style={[styles.actionButton, theme.shadows.medium]}
activeOpacity={0.7}
>
<LinearGradient
colors={['rgba(59, 130, 246, 0.15)', 'rgba(59, 130, 246, 0.05)']}
style={styles.actionIcon}
>
<Ionicons name="log-in-outline" size={24} color="#2563eb" />
</LinearGradient>
<View style={styles.actionContent}>
<Text style={styles.actionTitle}>Check In</Text>
<Text style={styles.actionSubtitle}>
Start your workout session
</Text>
</View>
<Ionicons name="chevron-forward" size={20} color="#9ca3af" />
</TouchableOpacity>
<TouchableOpacity
style={[styles.actionButton, theme.shadows.medium]}
activeOpacity={0.7}
>
<LinearGradient
colors={['rgba(16, 185, 129, 0.15)', 'rgba(16, 185, 129, 0.05)']}
style={styles.actionIcon}
>
<Ionicons name="calendar-outline" size={24} color="#10b981" />
</LinearGradient>
<View style={styles.actionContent}>
<Text style={styles.actionTitle}>View Schedule</Text>
<Text style={styles.actionSubtitle}>
Check your upcoming classes
</Text>
</View>
<Ionicons name="chevron-forward" size={20} color="#9ca3af" />
</TouchableOpacity>
<TouchableOpacity
style={[styles.actionButton, theme.shadows.medium]}
activeOpacity={0.7}
>
<LinearGradient
colors={['rgba(139, 92, 246, 0.15)', 'rgba(139, 92, 246, 0.05)']}
style={styles.actionIcon}
>
<Ionicons name="card-outline" size={24} color="#8b5cf6" />
</LinearGradient>
<View style={styles.actionContent}>
<Text style={styles.actionTitle}>Payments</Text>
<Text style={styles.actionSubtitle}>View payment history</Text>
</View>
<Ionicons name="chevron-forward" size={20} color="#9ca3af" />
</TouchableOpacity>
</View>
{/* Membership Info with Gradient */}
<View style={styles.section}>
<Text style={styles.sectionTitle}>Membership</Text>
<LinearGradient
colors={theme.gradients.primary}
start={{ x: 0, y: 0 }}
end={{ x: 1, y: 1 }}
style={[styles.membershipCard, theme.shadows.strong]}
>
<View style={styles.membershipHeader}>
<Text style={styles.membershipType}>Basic Plan</Text>
<View style={styles.statusBadge}>
<Text style={styles.statusText}>Active</Text>
<View style={styles.container}>
<ScrollView
contentContainerStyle={styles.scrollContent}
refreshControl={
<RefreshControl refreshing={refreshing} onRefresh={onRefresh} tintColor={theme.colors.primary} />
}
>
{/* Header Section */}
<View style={styles.header}>
<View>
<Text style={styles.greeting}>{getGreeting()},</Text>
<Text style={styles.name}>{user?.firstName || "Athlete"}</Text>
</View>
<View style={styles.avatarContainer}>
{user?.imageUrl ? (
<Image source={{ uri: user.imageUrl }} style={styles.avatar} />
) : (
<View style={styles.placeholderAvatar}>
<Ionicons name="person" size={24} color="#fff" />
</View>
</View>
<Text style={styles.membershipEmail}>
{user.primaryEmailAddress?.emailAddress}
</Text>
<Text style={styles.membershipDate}>
Member since {new Date(user.createdAt!).toLocaleDateString()}
</Text>
</LinearGradient>
</View>
{/* Recent Activity */}
<View style={styles.section}>
<Text style={styles.sectionTitle}>Recent Activity</Text>
<View style={[styles.emptyState, theme.shadows.medium]}>
<View style={styles.emptyIconContainer}>
<LinearGradient
colors={['rgba(209, 213, 219, 0.3)', 'rgba(209, 213, 219, 0.1)']}
style={styles.emptyIconGradient}
>
<Ionicons name="barbell-outline" size={48} color="#9ca3af" />
</LinearGradient>
</View>
<Text style={styles.emptyStateText}>No recent activity</Text>
<Text style={styles.emptyStateSubtext}>
Check in to start tracking your workouts
</Text>
)}
</View>
</View>
</Animated.View>
</ScrollView>
);
}
function getGreeting(): string {
const hour = new Date().getHours();
if (hour < 12) return "Good morning";
if (hour < 18) return "Good afternoon";
return "Good evening";
{/* Activity Widget */}
<ActivityWidget
steps={8432}
calories={640}
duration={45}
/>
{/* Quick Actions */}
<QuickActionGrid />
{/* Recent Activity Section */}
<View style={styles.section}>
<View style={styles.sectionHeader}>
<Text style={styles.sectionTitle}>Recent Activity</Text>
<Text style={styles.seeAll}>See All</Text>
</View>
<View style={styles.activityCard}>
<LinearGradient
colors={['rgba(255, 255, 255, 0.8)', 'rgba(255, 255, 255, 0.5)']}
style={[styles.recentItem, theme.shadows.subtle]}
>
<View style={styles.recentIconContainer}>
<LinearGradient
colors={theme.gradients.primary}
style={styles.recentIcon}
>
<Ionicons name="barbell" size={20} color="#fff" />
</LinearGradient>
</View>
<View style={styles.recentInfo}>
<Text style={styles.recentTitle}>Upper Body Power</Text>
<Text style={styles.recentSubtitle}>Today, 10:00 AM</Text>
</View>
<Text style={styles.recentValue}>45m</Text>
</LinearGradient>
<LinearGradient
colors={['rgba(255, 255, 255, 0.8)', 'rgba(255, 255, 255, 0.5)']}
style={[styles.recentItem, theme.shadows.subtle]}
>
<View style={styles.recentIconContainer}>
<LinearGradient
colors={theme.gradients.success}
style={styles.recentIcon}
>
<Ionicons name="bicycle" size={20} color="#fff" />
</LinearGradient>
</View>
<View style={styles.recentInfo}>
<Text style={styles.recentTitle}>Morning Cardio</Text>
<Text style={styles.recentSubtitle}>Yesterday, 7:30 AM</Text>
</View>
<Text style={styles.recentValue}>30m</Text>
</LinearGradient>
</View>
</View>
{/* Bottom Spacer for Tab Bar */}
<View style={{ height: 100 }} />
</ScrollView>
</View>
);
}
const styles = StyleSheet.create({
@@ -241,167 +120,110 @@ const styles = StyleSheet.create({
flex: 1,
backgroundColor: theme.colors.background,
},
content: {
paddingBottom: 20,
scrollContent: {
paddingTop: 60,
},
header: {
padding: 24,
paddingTop: 60,
paddingBottom: 32,
borderBottomLeftRadius: theme.borderRadius['2xl'],
borderBottomRightRadius: theme.borderRadius['2xl'],
marginBottom: 20,
flexDirection: "row",
justifyContent: "space-between",
alignItems: "center",
paddingHorizontal: 24,
marginBottom: 32,
},
greeting: {
fontSize: theme.typography.fontSize.base,
color: "rgba(255, 255, 255, 0.9)",
fontSize: 16,
color: theme.colors.gray600,
fontWeight: "500",
marginBottom: 4,
},
name: {
fontSize: theme.typography.fontSize['4xl'],
fontWeight: theme.typography.fontWeight.bold,
color: theme.colors.white,
},
statsContainer: {
flexDirection: "row",
justifyContent: "space-between",
paddingHorizontal: 16,
marginBottom: 24,
gap: 12,
},
statCard: {
flex: 1,
backgroundColor: theme.colors.white,
borderRadius: theme.borderRadius.xl,
padding: 16,
alignItems: "center",
borderWidth: 1,
borderColor: "rgba(255, 255, 255, 0.3)",
},
statIconContainer: {
marginBottom: 8,
},
statIconGradient: {
width: 48,
height: 48,
borderRadius: 24,
justifyContent: "center",
alignItems: "center",
},
statValue: {
fontSize: theme.typography.fontSize['2xl'],
fontWeight: theme.typography.fontWeight.bold,
fontSize: 32,
fontWeight: "800",
color: theme.colors.gray900,
marginTop: 4,
marginBottom: 4,
letterSpacing: -0.5,
},
statLabel: {
fontSize: theme.typography.fontSize.xs,
color: theme.colors.gray600,
textAlign: "center",
fontWeight: theme.typography.fontWeight.medium,
avatarContainer: {
shadowColor: "#000",
shadowOffset: { width: 0, height: 4 },
shadowOpacity: 0.1,
shadowRadius: 12,
elevation: 5,
},
section: {
marginBottom: 24,
paddingHorizontal: 20,
},
sectionTitle: {
fontSize: theme.typography.fontSize.xl,
fontWeight: theme.typography.fontWeight.semibold,
color: theme.colors.gray900,
marginBottom: 12,
},
actionButton: {
flexDirection: "row",
alignItems: "center",
backgroundColor: theme.colors.white,
borderRadius: theme.borderRadius.xl,
padding: 16,
marginBottom: 12,
},
actionIcon: {
avatar: {
width: 56,
height: 56,
borderRadius: 28,
borderRadius: 20,
borderWidth: 2,
borderColor: "#fff",
},
placeholderAvatar: {
width: 56,
height: 56,
borderRadius: 20,
backgroundColor: theme.colors.primary,
justifyContent: "center",
alignItems: "center",
marginRight: 12,
borderWidth: 2,
borderColor: "#fff",
},
actionContent: {
flex: 1,
section: {
paddingHorizontal: 20,
marginBottom: 24,
},
actionTitle: {
fontSize: theme.typography.fontSize.base,
fontWeight: theme.typography.fontWeight.semibold,
color: theme.colors.gray900,
marginBottom: 2,
},
actionSubtitle: {
fontSize: theme.typography.fontSize.sm,
color: theme.colors.gray600,
},
membershipCard: {
borderRadius: theme.borderRadius.xl,
padding: 20,
},
membershipHeader: {
sectionHeader: {
flexDirection: "row",
justifyContent: "space-between",
alignItems: "center",
marginBottom: 12,
},
membershipType: {
fontSize: theme.typography.fontSize.xl,
fontWeight: theme.typography.fontWeight.semibold,
color: theme.colors.white,
},
statusBadge: {
backgroundColor: "rgba(255, 255, 255, 0.25)",
paddingHorizontal: 12,
paddingVertical: 6,
borderRadius: theme.borderRadius.lg,
borderWidth: 1,
borderColor: "rgba(255, 255, 255, 0.3)",
},
statusText: {
fontSize: theme.typography.fontSize.xs,
fontWeight: theme.typography.fontWeight.semibold,
color: theme.colors.white,
},
membershipEmail: {
fontSize: theme.typography.fontSize.sm,
color: "rgba(255, 255, 255, 0.9)",
marginBottom: 4,
},
membershipDate: {
fontSize: theme.typography.fontSize.xs,
color: "rgba(255, 255, 255, 0.7)",
},
emptyState: {
backgroundColor: theme.colors.white,
borderRadius: theme.borderRadius.xl,
padding: 32,
alignItems: "center",
},
emptyIconContainer: {
marginBottom: 16,
},
emptyIconGradient: {
width: 96,
height: 96,
borderRadius: 48,
sectionTitle: {
fontSize: 18,
fontWeight: "700",
color: theme.colors.gray900,
},
seeAll: {
fontSize: 14,
color: theme.colors.primary,
fontWeight: "600",
},
activityCard: {
gap: 12,
},
recentItem: {
flexDirection: "row",
alignItems: "center",
padding: 16,
borderRadius: 20,
backgroundColor: "#fff",
borderWidth: 1,
borderColor: "rgba(255, 255, 255, 0.6)",
},
recentIconContainer: {
marginRight: 16,
},
recentIcon: {
width: 48,
height: 48,
borderRadius: 16,
justifyContent: "center",
alignItems: "center",
},
emptyStateText: {
fontSize: theme.typography.fontSize.base,
fontWeight: theme.typography.fontWeight.semibold,
color: theme.colors.gray700,
recentInfo: {
flex: 1,
},
recentTitle: {
fontSize: 16,
fontWeight: "600",
color: theme.colors.gray900,
marginBottom: 4,
},
emptyStateSubtext: {
fontSize: theme.typography.fontSize.sm,
recentSubtitle: {
fontSize: 12,
color: theme.colors.gray500,
textAlign: "center",
},
recentValue: {
fontSize: 14,
fontWeight: "600",
color: theme.colors.gray900,
},
});