redesign take 1

This commit is contained in:
dimitar committed 2026-03-11 08:22:48 +01:00
1 parent 1143f8ca02
commit e3a3c3fccf
19 files changed
+2783 -1493

No files matched your search

+373 -159
View File
@@ -7,28 +7,28 @@ import {
Image,
} from "react-native";
import { useUser } from "@clerk/clerk-expo";
import { LinearGradient } from "expo-linear-gradient";
import { useState, useCallback, useEffect } from "react";
import { useFocusEffect } from "@react-navigation/native";
import AsyncStorage from "@react-native-async-storage/async-storage";
import { theme } from "../../styles/theme";
import { ActivityWidget } from "../../components/ActivityWidget";
import { QuickActionGrid } from "../../components/QuickActionGrid";
import { Ionicons } from "@expo/vector-icons";
import { useTheme } from "../../contexts/ThemeContext";
import { useStatistics } from "../../contexts/StatisticsContext";
import { MinimalCard } from "../../components/MinimalCard";
import { SectionHeader } from "../../components/SectionHeader";
import { IconContainer } from "../../components/IconContainer";
import { ProgressBar } from "../../components/ProgressBar";
import { TrackMealModal } from "../../components/TrackMealModal";
import { AddWaterModal } from "../../components/AddWaterModal";
import { HydrationWidget } from "../../components/HydrationWidget";
import { NutritionWidget } from "../../components/NutritionWidget";
import { WeeklyProgressWidget } from "../../components/WeeklyProgressWidget";
import { ScanFoodModal } from "../../components/ScanFoodModal";
import { useStatistics } from "../../contexts/StatisticsContext";
import { Ionicons } from "@expo/vector-icons";
const CALORIE_GOAL = 2000; // kcal
const WATER_GOAL = 2000; // ml
export default function HomeScreen() {
const { user } = useUser();
const { refetchStatistics, forceRefresh } = useStatistics();
const { colors, typography } = useTheme();
const { refetchStatistics, forceRefresh, statistics, loading } =
useStatistics();
const [refreshing, setRefreshing] = useState(false);
const [trackMealModalVisible, setTrackMealModalVisible] = useState(false);
const [addWaterModalVisible, setAddWaterModalVisible] = useState(false);
@@ -45,7 +45,6 @@ export default function HomeScreen() {
const onRefresh = useCallback(async () => {
setRefreshing(true);
// Force refetch statistics bypassing cache
await forceRefresh();
setRefreshing(false);
}, [forceRefresh]);
@@ -168,57 +167,358 @@ export default function HomeScreen() {
return () => clearTimeout(midnightTimer);
}, []);
const checkInsThisWeek = statistics?.attendance.checkInsThisWeek || 0;
const currentStreak = statistics?.attendance.currentStreak || 0;
return (
<View style={styles.container}>
<View style={[styles.container, { backgroundColor: colors.background }]}>
<ScrollView
contentContainerStyle={styles.scrollContent}
refreshControl={
<RefreshControl
refreshing={refreshing}
onRefresh={onRefresh}
tintColor={theme.colors.primary}
tintColor={colors.primary}
/>
}
>
{/* Header Section */}
<View style={styles.header}>
<View>
<Text style={styles.greeting}>{getGreeting()},</Text>
<Text style={styles.name}>{user?.firstName || "Athlete"}</Text>
<Text style={[typography.body, { color: colors.textSecondary }]}>
{getGreeting()},
</Text>
<Text
style={[
typography.h1,
{ color: colors.textPrimary, marginTop: 4 },
]}
>
{user?.firstName || "Athlete"}
</Text>
</View>
<View style={styles.avatarContainer}>
<View>
{user?.imageUrl ? (
<Image source={{ uri: user.imageUrl }} style={styles.avatar} />
) : (
<View style={styles.placeholderAvatar}>
<Ionicons name="person" size={24} color="#fff" />
<View
style={[
styles.placeholderAvatar,
{ backgroundColor: colors.primary },
]}
>
<Ionicons name="person" size={24} color={colors.white} />
</View>
)}
</View>
</View>
{/* Activity Widget */}
<ActivityWidget calories={calories} />
{/* Daily Stats Card */}
<View style={styles.section}>
<MinimalCard variant="elevated">
<View style={styles.statsRow}>
<View style={styles.statItem}>
<IconContainer
variant="colored"
backgroundColor={`${colors.info}20`}
>
<Ionicons
name="checkmark-circle"
size={24}
color={colors.info}
/>
</IconContainer>
<Text
style={[
typography.stat,
{ color: colors.textPrimary, marginTop: 8 },
]}
>
{checkInsThisWeek}
</Text>
<Text
style={[typography.caption, { color: colors.textTertiary }]}
>
This Week
</Text>
</View>
{/* Quick Action Grid */}
<QuickActionGrid
onTrackMealPress={() => setTrackMealModalVisible(true)}
onAddWaterPress={() => setAddWaterModalVisible(true)}
onScanFoodPress={() => setScanFoodModalVisible(true)}
onLogWorkoutPress={() => {
// TODO: Implement workout logging
console.log("Log workout tapped");
}}
/>
<View
style={[styles.divider, { backgroundColor: colors.border }]}
/>
{/* Nutrition Widget */}
<NutritionWidget current={calories} goal={CALORIE_GOAL} />
<View style={styles.statItem}>
<IconContainer
variant="colored"
backgroundColor={`${colors.danger}20`}
>
<Ionicons name="flame" size={24} color={colors.danger} />
</IconContainer>
<Text
style={[
typography.stat,
{ color: colors.textPrimary, marginTop: 8 },
]}
>
{calories}
</Text>
<Text
style={[typography.caption, { color: colors.textTertiary }]}
>
Kcal
</Text>
</View>
{/* Hydration Widget */}
<HydrationWidget current={waterIntake} goal={WATER_GOAL} />
<View
style={[styles.divider, { backgroundColor: colors.border }]}
/>
{/* Weekly Progress Widget */}
<WeeklyProgressWidget />
<View style={styles.statItem}>
<IconContainer
variant="colored"
backgroundColor={`${colors.success}20`}
>
<Ionicons name="trophy" size={24} color={colors.success} />
</IconContainer>
<Text
style={[
typography.stat,
{ color: colors.textPrimary, marginTop: 8 },
]}
>
{currentStreak}
</Text>
<Text
style={[typography.caption, { color: colors.textTertiary }]}
>
Day Streak
</Text>
</View>
</View>
</MinimalCard>
</View>
{/* Quick Actions */}
<View style={styles.section}>
<SectionHeader title="Quick Actions" />
<View style={styles.actionGrid}>
<MinimalCard
variant="default"
onPress={() => {
console.log("Log workout tapped");
}}
style={styles.actionCard}
>
<IconContainer
variant="colored"
backgroundColor={`${colors.primary}20`}
>
<Ionicons name="barbell" size={24} color={colors.primary} />
</IconContainer>
<Text
style={[
typography.h3,
{ color: colors.textPrimary, marginTop: 8 },
]}
>
Log Workout
</Text>
</MinimalCard>
<MinimalCard
variant="default"
onPress={() => setTrackMealModalVisible(true)}
style={styles.actionCard}
>
<IconContainer
variant="colored"
backgroundColor={`${colors.success}20`}
>
<Ionicons name="restaurant" size={24} color={colors.success} />
</IconContainer>
<Text
style={[
typography.h3,
{ color: colors.textPrimary, marginTop: 8 },
]}
>
Track Meal
</Text>
</MinimalCard>
<MinimalCard
variant="default"
onPress={() => setAddWaterModalVisible(true)}
style={styles.actionCard}
>
<IconContainer
variant="colored"
backgroundColor={`${colors.info}20`}
>
<Ionicons name="water" size={24} color={colors.info} />
</IconContainer>
<Text
style={[
typography.h3,
{ color: colors.textPrimary, marginTop: 8 },
]}
>
Add Water
</Text>
</MinimalCard>
<MinimalCard
variant="default"
onPress={() => setScanFoodModalVisible(true)}
style={styles.actionCard}
>
<IconContainer
variant="colored"
backgroundColor={`${colors.accent}20`}
>
<Ionicons name="scan" size={24} color={colors.accent} />
</IconContainer>
<Text
style={[
typography.h3,
{ color: colors.textPrimary, marginTop: 8 },
]}
>
Scan Food
</Text>
</MinimalCard>
</View>
</View>
{/* Nutrition Progress */}
<View style={styles.section}>
<SectionHeader title="Nutrition" />
<MinimalCard variant="default">
<View style={styles.progressHeader}>
<View style={styles.progressLabelRow}>
<Ionicons name="flame" size={20} color={colors.textSecondary} />
<Text
style={[
typography.h3,
{ color: colors.textPrimary, marginLeft: 8 },
]}
>
Calories
</Text>
</View>
<Text
style={[typography.bodyEmphasis, { color: colors.textPrimary }]}
>
{calories} / {CALORIE_GOAL}
</Text>
</View>
<ProgressBar
progress={calories / CALORIE_GOAL}
color={colors.danger}
style={{ marginTop: 12 }}
/>
</MinimalCard>
</View>
{/* Hydration Progress */}
<View style={styles.section}>
<MinimalCard variant="default">
<View style={styles.progressHeader}>
<View style={styles.progressLabelRow}>
<Ionicons name="water" size={20} color={colors.textSecondary} />
<Text
style={[
typography.h3,
{ color: colors.textPrimary, marginLeft: 8 },
]}
>
Hydration
</Text>
</View>
<Text
style={[typography.bodyEmphasis, { color: colors.textPrimary }]}
>
{waterIntake} / {WATER_GOAL} ml
</Text>
</View>
<ProgressBar
progress={waterIntake / WATER_GOAL}
color={colors.info}
style={{ marginTop: 12 }}
/>
</MinimalCard>
</View>
{/* Recent Activity */}
<View style={styles.section}>
<SectionHeader
title="Recent Activity"
actionLabel="See All"
onActionPress={() => console.log("See all tapped")}
/>
<View style={styles.activityList}>
<MinimalCard variant="default" style={styles.activityItem}>
<IconContainer
variant="colored"
backgroundColor={`${colors.primary}20`}
>
<Ionicons name="barbell" size={20} color={colors.primary} />
</IconContainer>
<View style={styles.activityInfo}>
<Text style={[typography.h3, { color: colors.textPrimary }]}>
Upper Body Power
</Text>
<Text
style={[
typography.caption,
{ color: colors.textTertiary, marginTop: 2 },
]}
>
Today, 10:00 AM
</Text>
</View>
<Text
style={[
typography.bodyEmphasis,
{ color: colors.textSecondary },
]}
>
45m
</Text>
</MinimalCard>
<MinimalCard variant="default" style={styles.activityItem}>
<IconContainer
variant="colored"
backgroundColor={`${colors.success}20`}
>
<Ionicons name="bicycle" size={20} color={colors.success} />
</IconContainer>
<View style={styles.activityInfo}>
<Text style={[typography.h3, { color: colors.textPrimary }]}>
Morning Cardio
</Text>
<Text
style={[
typography.caption,
{ color: colors.textTertiary, marginTop: 2 },
]}
>
Yesterday, 7:30 AM
</Text>
</View>
<Text
style={[
typography.bodyEmphasis,
{ color: colors.textSecondary },
]}
>
30m
</Text>
</MinimalCard>
</View>
</View>
<TrackMealModal
visible={trackMealModalVisible}
@@ -240,54 +540,6 @@ export default function HomeScreen() {
onAddFood={handleAddScannedFood}
/>
{/* 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>
@@ -298,7 +550,6 @@ export default function HomeScreen() {
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: theme.colors.background,
},
scrollContent: {
paddingTop: 60,
@@ -308,102 +559,65 @@ const styles = StyleSheet.create({
justifyContent: "space-between",
alignItems: "center",
paddingHorizontal: 24,
marginBottom: 32,
},
greeting: {
fontSize: 16,
color: theme.colors.gray600,
fontWeight: "500",
marginBottom: 4,
},
name: {
fontSize: 32,
fontWeight: "800",
color: theme.colors.gray900,
letterSpacing: -0.5,
},
avatarContainer: {
shadowColor: "#000",
shadowOffset: { width: 0, height: 4 },
shadowOpacity: 0.1,
shadowRadius: 12,
elevation: 5,
marginBottom: 24,
},
avatar: {
width: 56,
height: 56,
borderRadius: 20,
borderWidth: 2,
borderColor: "#fff",
borderRadius: 28,
},
placeholderAvatar: {
width: 56,
height: 56,
borderRadius: 20,
backgroundColor: theme.colors.primary,
borderRadius: 28,
justifyContent: "center",
alignItems: "center",
borderWidth: 2,
borderColor: "#fff",
},
section: {
paddingHorizontal: 20,
paddingHorizontal: 24,
marginBottom: 24,
},
sectionHeader: {
statsRow: {
flexDirection: "row",
justifyContent: "space-between",
alignItems: "center",
marginBottom: 16,
},
sectionTitle: {
fontSize: 18,
fontWeight: "700",
color: theme.colors.gray900,
},
seeAll: {
fontSize: 14,
color: theme.colors.primary,
fontWeight: "600",
},
activityCard: {
gap: 12,
},
recentItem: {
flexDirection: "row",
statItem: {
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",
},
recentInfo: {
flex: 1,
},
recentTitle: {
fontSize: 16,
fontWeight: "600",
color: theme.colors.gray900,
marginBottom: 4,
divider: {
width: 1,
height: 60,
},
recentSubtitle: {
fontSize: 12,
color: theme.colors.gray500,
actionGrid: {
flexDirection: "row",
flexWrap: "wrap",
gap: 12,
},
recentValue: {
fontSize: 14,
fontWeight: "600",
color: theme.colors.gray900,
actionCard: {
width: "48%",
alignItems: "center",
paddingVertical: 20,
},
progressHeader: {
flexDirection: "row",
justifyContent: "space-between",
alignItems: "center",
},
progressLabelRow: {
flexDirection: "row",
alignItems: "center",
},
activityList: {
gap: 12,
},
activityItem: {
flexDirection: "row",
alignItems: "center",
gap: 12,
},
activityInfo: {
flex: 1,
},
});