/** * TabataFit Program Detail Screen * Shows week progression and workout list */ import { View, StyleSheet, ScrollView, Pressable } from 'react-native' import { useRouter, useLocalSearchParams } from 'expo-router' import { useSafeAreaInsets } from 'react-native-safe-area-context' import { LinearGradient } from 'expo-linear-gradient' import { Icon } from '@/src/shared/components/Icon' import { useMemo } from 'react' import { useTranslation } from 'react-i18next' import { useHaptics } from '@/src/shared/hooks' import { useProgramStore } from '@/src/shared/stores' import { PROGRAMS } from '@/src/shared/data/programs' import { StyledText } from '@/src/shared/components/StyledText' import { useThemeColors, BRAND } 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' import type { ProgramId } from '@/src/shared/types' const FONTS = { LARGE_TITLE: 28, TITLE: 24, TITLE_2: 20, HEADLINE: 17, BODY: 16, CAPTION: 13, SMALL: 12, } export default function ProgramDetailScreen() { const { id } = useLocalSearchParams<{ id: string }>() const programId = id as ProgramId const { t } = useTranslation('screens') const insets = useSafeAreaInsets() const router = useRouter() const haptics = useHaptics() const colors = useThemeColors() const styles = useMemo(() => createStyles(colors), [colors]) const program = PROGRAMS[programId] const selectProgram = useProgramStore((s) => s.selectProgram) const progress = useProgramStore((s) => s.programsProgress[programId]) const isWeekUnlocked = useProgramStore((s) => s.isWeekUnlocked) const getCurrentWorkout = useProgramStore((s) => s.getCurrentWorkout) const completion = useProgramStore((s) => s.getProgramCompletion(programId)) if (!program) { return ( Program not found ) } const handleStartProgram = () => { haptics.buttonTap() selectProgram(programId) const currentWorkout = getCurrentWorkout(programId) if (currentWorkout) { router.push(`/workout/${currentWorkout.id}`) } } const handleWorkoutPress = (workoutId: string, weekNumber: number) => { haptics.buttonTap() router.push(`/workout/${workoutId}`) } return ( {/* Header */} router.back()}> {program.title} {/* Program Overview */} {program.description} {/* Stats Row */} {program.durationWeeks} {t('programs.weeks')} {program.totalWorkouts} {t('programs.workouts')} 4 {t('programs.minutes')} {/* Equipment */} {t('programs.equipment')} {program.equipment.required.map((item) => ( {item} ))} {program.equipment.optional.map((item) => ( {item} {t('programs.optional')} ))} {/* Focus Areas */} {t('programs.focusAreas')} {program.focusAreas.map((area) => ( {area} ))} {/* Progress Overview */} {progress.completedWorkoutIds.length > 0 && ( {t('programs.yourProgress')} {completion}% {progress.completedWorkoutIds.length} {t('programs.of')} {program.totalWorkouts} {t('programs.workoutsComplete')} )} {/* Weeks */} {t('programs.trainingPlan')} {program.weeks.map((week) => { const isUnlocked = isWeekUnlocked(programId, week.weekNumber) const isCurrentWeek = progress.currentWeek === week.weekNumber const weekCompletion = week.workouts.filter(w => progress.completedWorkoutIds.includes(w.id) ).length return ( {/* Week Header */} {week.title} {!isUnlocked && ( )} {isCurrentWeek && isUnlocked && ( {t('programs.current')} )} {week.description} {weekCompletion > 0 && ( {weekCompletion}/{week.workouts.length} {t('programs.complete')} )} {/* Week Workouts */} {isUnlocked && ( {week.workouts.map((workout, index) => { const isCompleted = progress.completedWorkoutIds.includes(workout.id) const isLocked = !isCompleted && index > 0 && !progress.completedWorkoutIds.includes(week.workouts[index - 1].id) && week.weekNumber === progress.currentWeek return ( !isLocked && handleWorkoutPress(workout.id, week.weekNumber)} disabled={isLocked} > {isCompleted ? ( ) : isLocked ? ( ) : ( {index + 1} )} {workout.title} {workout.exercises.length} {t('programs.exercises')} • {workout.duration} {t('programs.min')} {!isLocked && !isCompleted && ( )} ) })} )} ) })} {/* Bottom CTA */} {progress.completedWorkoutIds.length === 0 ? t('programs.startProgram') : progress.isProgramCompleted ? t('programs.restartProgram') : t('programs.continueTraining') } ) } 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', alignItems: 'center', justifyContent: 'space-between', paddingHorizontal: LAYOUT.SCREEN_PADDING, paddingVertical: SPACING[3], }, backButton: { width: 40, height: 40, alignItems: 'center', justifyContent: 'center', }, placeholder: { width: 40, }, // Overview overviewSection: { marginTop: SPACING[2], marginBottom: SPACING[6], }, description: { marginBottom: SPACING[5], lineHeight: 24, }, statsRow: { flexDirection: 'row', justifyContent: 'space-around', marginBottom: SPACING[5], paddingVertical: SPACING[4], backgroundColor: colors.bg.surface, borderRadius: RADIUS.LG, }, statBox: { alignItems: 'center', }, // Equipment equipmentSection: { marginBottom: SPACING[4], }, equipmentList: { flexDirection: 'row', flexWrap: 'wrap', gap: SPACING[2], marginTop: SPACING[2], }, equipmentTag: { backgroundColor: colors.bg.surface, paddingHorizontal: SPACING[3], paddingVertical: SPACING[1], borderRadius: RADIUS.FULL, }, optionalTag: { opacity: 0.7, }, // Focus focusSection: { marginBottom: SPACING[4], }, focusList: { flexDirection: 'row', flexWrap: 'wrap', gap: SPACING[2], marginTop: SPACING[2], }, focusTag: { backgroundColor: `${BRAND.PRIMARY}15`, paddingHorizontal: SPACING[3], paddingVertical: SPACING[1], borderRadius: RADIUS.FULL, }, // Progress progressSection: { backgroundColor: colors.bg.surface, borderRadius: RADIUS.LG, padding: SPACING[4], marginBottom: SPACING[6], }, progressHeader: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', marginBottom: SPACING[3], }, progressBarContainer: { marginBottom: SPACING[2], }, progressBar: { height: 8, borderRadius: 4, overflow: 'hidden', }, progressFill: { height: '100%', borderRadius: 4, }, // Weeks weeksSection: { marginBottom: SPACING[6], }, weeksTitle: { marginBottom: SPACING[4], }, weekCard: { backgroundColor: colors.bg.surface, borderRadius: RADIUS.LG, marginBottom: SPACING[4], overflow: 'hidden', }, weekHeader: { padding: SPACING[4], borderBottomWidth: 1, borderBottomColor: colors.border.glass, }, weekTitleRow: { flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between', marginBottom: SPACING[1], }, currentBadge: { backgroundColor: BRAND.PRIMARY, paddingHorizontal: SPACING[2], paddingVertical: 2, borderRadius: RADIUS.SM, }, weekProgress: { marginTop: SPACING[2], }, // Workouts List workoutsList: { padding: SPACING[2], }, workoutItem: { flexDirection: 'row', alignItems: 'center', paddingVertical: SPACING[3], paddingHorizontal: SPACING[3], borderRadius: RADIUS.MD, }, workoutCompleted: { opacity: 0.7, }, workoutLocked: { opacity: 0.5, }, workoutNumber: { width: 32, height: 32, alignItems: 'center', justifyContent: 'center', marginRight: SPACING[3], }, workoutInfo: { flex: 1, }, completedText: { textDecorationLine: 'line-through', }, // Bottom Bar bottomBar: { position: 'absolute', bottom: 0, left: 0, right: 0, backgroundColor: colors.bg.base, paddingHorizontal: LAYOUT.SCREEN_PADDING, paddingTop: SPACING[3], borderTopWidth: 1, borderTopColor: colors.border.glass, }, ctaButton: { borderRadius: RADIUS.LG, overflow: 'hidden', }, ctaGradient: { flexDirection: 'row', alignItems: 'center', justifyContent: 'center', paddingVertical: SPACING[4], }, ctaIcon: { marginLeft: SPACING[2], }, }) }