/** * TabataFit Collection Detail Screen * Shows collection info + ordered workout list */ import { useMemo } from 'react' import { View, StyleSheet, ScrollView, Pressable, Text as RNText } from 'react-native' import { useRouter, useLocalSearchParams } from 'expo-router' import { useSafeAreaInsets } from 'react-native-safe-area-context' import { LinearGradient } from 'expo-linear-gradient' import Ionicons from '@expo/vector-icons/Ionicons' import { useTranslation } from 'react-i18next' import { useHaptics } from '@/src/shared/hooks' import { getCollectionById, getCollectionWorkouts, COLLECTION_COLORS } from '@/src/shared/data' import { useTranslatedCollections, useTranslatedWorkouts } from '@/src/shared/data/useTranslatedData' 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' export default function CollectionDetailScreen() { const insets = useSafeAreaInsets() const router = useRouter() const haptics = useHaptics() const { t } = useTranslation() const { id } = useLocalSearchParams<{ id: string }>() const colors = useThemeColors() const styles = useMemo(() => createStyles(colors), [colors]) const rawCollection = id ? getCollectionById(id) : null const translatedCollections = useTranslatedCollections(rawCollection ? [rawCollection] : []) const collection = translatedCollections.length > 0 ? translatedCollections[0] : null const rawWorkouts = useMemo( () => id ? getCollectionWorkouts(id).filter((w): w is NonNullable => w != null) : [], [id] ) const workouts = useTranslatedWorkouts(rawWorkouts) const collectionColor = COLLECTION_COLORS[id ?? ''] ?? BRAND.PRIMARY const handleBack = () => { haptics.selection() router.back() } const handleWorkoutPress = (workoutId: string) => { haptics.buttonTap() router.push(`/workout/${workoutId}`) } if (!collection) { return ( {t('screens:collection.notFound')} ) } const totalMinutes = workouts.reduce((sum, w) => sum + (w?.duration ?? 0), 0) const totalCalories = workouts.reduce((sum, w) => sum + (w?.calories ?? 0), 0) return ( {/* Hero Header — on gradient, text stays white */} {collection.icon} {collection.title} {collection.description} {t('plurals.workout', { count: workouts.length })} {t('screens:collection.minTotal', { count: totalMinutes })} {t('units.calUnit', { count: totalCalories })} {/* Workout List — on base bg, use theme tokens */} {workouts.map((workout, index) => { if (!workout) return null return ( handleWorkoutPress(workout.id)} > {index + 1} {workout.title} {t('durationLevel', { duration: workout.duration, level: t(`levels.${workout.level.toLowerCase()}`) })} {t('units.calUnit', { count: workout.calories })} ) })} ) } function createStyles(colors: ThemeColors) { return StyleSheet.create({ container: { flex: 1, backgroundColor: colors.bg.base, }, scrollView: { flex: 1, }, scrollContent: {}, // Hero hero: { height: 260, overflow: 'hidden', }, backButton: { width: 44, height: 44, alignItems: 'center', justifyContent: 'center', margin: SPACING[3], }, heroContent: { position: 'absolute', bottom: SPACING[5], left: SPACING[5], right: SPACING[5], }, heroIcon: { fontSize: 40, marginBottom: SPACING[2], }, heroStats: { flexDirection: 'row', gap: SPACING[4], marginTop: SPACING[3], }, heroStat: { flexDirection: 'row', alignItems: 'center', gap: SPACING[1], }, // Workout List workoutList: { paddingHorizontal: LAYOUT.SCREEN_PADDING, paddingTop: SPACING[4], gap: SPACING[2], }, workoutCard: { flexDirection: 'row', alignItems: 'center', paddingVertical: SPACING[3], paddingHorizontal: SPACING[4], backgroundColor: colors.bg.surface, borderRadius: RADIUS.LG, gap: SPACING[3], }, workoutNumber: { width: 32, height: 32, borderRadius: 16, alignItems: 'center', justifyContent: 'center', }, workoutNumberText: { fontSize: 15, fontWeight: '700', }, workoutInfo: { flex: 1, gap: 2, }, workoutMeta: { alignItems: 'flex-end', gap: 4, }, }) }