/** * TabataFit Home Screen * React Native UI — wired to shared data */ import { View, StyleSheet, ScrollView, Pressable, Dimensions, Text as RNText, Image as RNImage } from 'react-native' import { useRouter } from 'expo-router' import { useSafeAreaInsets } from 'react-native-safe-area-context' import { LinearGradient } from 'expo-linear-gradient' import { BlurView } from 'expo-blur' import Ionicons from '@expo/vector-icons/Ionicons' import { useMemo } from 'react' import { useTranslation } from 'react-i18next' import { useHaptics } from '@/src/shared/hooks' import { useUserStore, useActivityStore } from '@/src/shared/stores' import { getFeaturedWorkouts, getPopularWorkouts, COLLECTIONS, WORKOUTS, } from '@/src/shared/data' import { useTranslatedWorkouts, useTranslatedCollections } from '@/src/shared/data/useTranslatedData' import { StyledText } from '@/src/shared/components/StyledText' import { useThemeColors, BRAND, GRADIENTS } from '@/src/shared/theme' import type { ThemeColors } from '@/src/shared/theme/types' import { SPACING, LAYOUT } from '@/src/shared/constants/spacing' import { RADIUS } from '@/src/shared/constants/borderRadius' const { width: SCREEN_WIDTH } = Dimensions.get('window') const CARD_WIDTH = SCREEN_WIDTH - LAYOUT.SCREEN_PADDING * 2 const FONTS = { LARGE_TITLE: 34, TITLE: 28, TITLE_2: 22, HEADLINE: 17, BODY: 17, SUBHEADLINE: 15, CAPTION_1: 12, CAPTION_2: 11, } // ═══════════════════════════════════════════════════════════════════════════ // HELPERS // ═══════════════════════════════════════════════════════════════════════════ function PrimaryButton({ children, onPress }: { children: string; onPress?: () => void }) { const colors = useThemeColors() const styles = useMemo(() => createStyles(colors), [colors]) return ( {children} ) } function PlainButton({ children, onPress }: { children: string; onPress?: () => void }) { const colors = useThemeColors() const styles = useMemo(() => createStyles(colors), [colors]) return ( {children} ) } // ═══════════════════════════════════════════════════════════════════════════ // MAIN SCREEN // ═══════════════════════════════════════════════════════════════════════════ export default function HomeScreen() { const { t } = useTranslation() const insets = useSafeAreaInsets() const router = useRouter() const haptics = useHaptics() const colors = useThemeColors() const styles = useMemo(() => createStyles(colors), [colors]) const userName = useUserStore((s) => s.profile.name) const history = useActivityStore((s) => s.history) const recentWorkouts = useMemo(() => history.slice(0, 3), [history]) const featured = getFeaturedWorkouts()[0] ?? WORKOUTS[0] const popular = getPopularWorkouts(4) const translatedPopular = useTranslatedWorkouts(popular) const translatedCollections = useTranslatedCollections(COLLECTIONS) const greeting = (() => { const hour = new Date().getHours() if (hour < 12) return t('greetings.morning') if (hour < 18) return t('greetings.afternoon') return t('greetings.evening') })() const featuredTitle = t(`content:workouts.${featured.id}`, { defaultValue: featured.title }) const handleWorkoutPress = (id: string) => { haptics.buttonTap() router.push(`/workout/${id}`) } return ( {/* Header */} {greeting} {userName} {/* Featured */} handleWorkoutPress(featured.id)} > {featured.thumbnailUrl ? ( ) : ( )} {'🔥 ' + t('screens:home.featured')} {featuredTitle} {t('workoutMeta', { duration: featured.duration, level: t(`levels.${featured.level.toLowerCase()}`), calories: featured.calories })} handleWorkoutPress(featured.id)}>{t('start')} {/* Continue Watching — from activity store */} {recentWorkouts.length > 0 && ( {t('screens:home.recent')} {t('seeAll')} {recentWorkouts.map((result) => { const workout = WORKOUTS.find(w => w.id === result.workoutId) if (!workout) return null const workoutTitle = t(`content:workouts.${workout.id}`, { defaultValue: workout.title }) return ( handleWorkoutPress(result.workoutId)} > {workoutTitle} {t('calMin', { calories: result.calories, duration: result.durationMinutes })} ) })} )} {/* Popular This Week */} {t('screens:home.popularThisWeek')} {translatedPopular.map((item) => ( handleWorkoutPress(item.id)} > {item.title} {t('units.minUnit', { count: item.duration })} ))} {/* Collections */} {t('screens:home.collections')} {translatedCollections.map((item) => ( { haptics.buttonTap(); router.push(`/collection/${item.id}`) }}> {item.icon} {item.title} {t('plurals.workout', { count: item.workoutIds.length }) + ' \u00B7 ' + item.description} ))} ) } // ═══════════════════════════════════════════════════════════════════════════ // STYLES // ═══════════════════════════════════════════════════════════════════════════ function createStyles(colors: ThemeColors) { return StyleSheet.create({ container: { flex: 1, backgroundColor: colors.bg.base, }, scrollView: { flex: 1, }, scrollContent: { paddingHorizontal: LAYOUT.SCREEN_PADDING, }, // Header header: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', marginBottom: SPACING[6], }, profileButton: { width: 40, height: 40, alignItems: 'center', justifyContent: 'center', }, // Buttons primaryButton: { flexDirection: 'row', alignItems: 'center', backgroundColor: BRAND.PRIMARY, paddingHorizontal: SPACING[4], paddingVertical: SPACING[3], borderRadius: RADIUS.SM, }, buttonIcon: { marginRight: SPACING[2], }, primaryButtonText: { fontSize: 14, fontWeight: '600', color: '#FFFFFF', }, plainButtonText: { fontSize: FONTS.BODY, color: BRAND.PRIMARY, }, // Featured featuredCard: { width: CARD_WIDTH, height: 220, borderRadius: RADIUS.GLASS_CARD, overflow: 'hidden', marginBottom: SPACING[8], ...colors.shadow.lg, }, featuredBadge: { position: 'absolute', top: SPACING[4], left: SPACING[4], backgroundColor: 'rgba(255, 255, 255, 0.15)', paddingHorizontal: SPACING[3], paddingVertical: SPACING[1], borderRadius: RADIUS.SM, borderWidth: 1, borderColor: 'rgba(255, 255, 255, 0.2)', }, featuredBadgeText: { fontSize: 11, fontWeight: 'bold', color: '#FFFFFF', }, featuredContent: { position: 'absolute', bottom: 0, left: 0, right: 0, padding: SPACING[5], }, featuredButtons: { flexDirection: 'row', alignItems: 'center', gap: SPACING[3], marginTop: SPACING[4], }, saveButton: { width: 44, height: 44, alignItems: 'center', justifyContent: 'center', backgroundColor: 'rgba(255, 255, 255, 0.1)', borderRadius: 22, borderWidth: 1, borderColor: 'rgba(255, 255, 255, 0.15)', }, // Sections section: { marginBottom: SPACING[8], }, sectionHeader: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', marginBottom: SPACING[4], }, horizontalScroll: { gap: SPACING[3], }, // Continue Card continueCard: { width: 140, }, continueThumb: { width: 140, height: 200, borderRadius: RADIUS.LG, overflow: 'hidden', alignItems: 'center', justifyContent: 'center', marginBottom: SPACING[2], }, // Popular Card popularCard: { width: 120, }, popularThumb: { width: 120, height: 120, borderRadius: RADIUS.LG, alignItems: 'center', justifyContent: 'center', marginBottom: SPACING[2], borderWidth: 1, borderColor: colors.border.glass, backgroundColor: colors.bg.overlay1, }, // Collection Card collectionCard: { height: 80, borderRadius: RADIUS.LG, overflow: 'hidden', marginBottom: SPACING[3], borderWidth: 1, borderColor: colors.border.glass, }, collectionContent: { flex: 1, flexDirection: 'row', alignItems: 'center', paddingHorizontal: SPACING[5], }, collectionIcon: { fontSize: 28, marginRight: SPACING[4], }, collectionText: { flex: 1, }, }) }