/** * TabataFit Workout Complete Screen * Celebration + stats driven by progressStore. */ import { useEffect, useMemo, useRef } from 'react' import { View, Text as RNText, StyleSheet, ScrollView, Animated, } from 'react-native' import { useRouter, useLocalSearchParams } from 'expo-router' import { useSafeAreaInsets } from 'react-native-safe-area-context' import { Icon, type IconName } from '@/src/shared/components/Icon' import { useTranslation } from 'react-i18next' import * as Sharing from 'expo-sharing' import { useHaptics } from '@/src/shared/hooks' import { useProgressStore } from '@/src/shared/stores' import { NativeButton } from '@/src/shared/components/native' import { useThemeColors } from '@/src/shared/theme' import type { ThemeColors } from '@/src/shared/theme/types' import { TYPOGRAPHY } from '@/src/shared/constants/typography' import { SPACING, LAYOUT } from '@/src/shared/constants/spacing' import { RADIUS } from '@/src/shared/constants/borderRadius' import { SPRING } from '@/src/shared/constants/animations' import { GREEN, NAVY, TEXT, BORDER_COLORS } from '@/src/shared/constants/colors' function StatCard({ value, label, icon, delay = 0, }: { value: string | number label: string icon: IconName delay?: number }) { const colors = useThemeColors() const styles = useMemo(() => createStyles(colors), [colors]) const scaleAnim = useRef(new Animated.Value(0)).current useEffect(() => { Animated.sequence([ Animated.delay(delay), Animated.spring(scaleAnim, { toValue: 1, ...SPRING.BOUNCY, useNativeDriver: true }), ]).start() }, [delay]) return ( {value} {label} ) } export default function WorkoutCompleteScreen() { 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 history = useProgressStore((s) => s.history) const streak = useProgressStore((s) => s.streak) const weeklyCount = useProgressStore((s) => s.getWeeklyCount()) // Latest session (the one we just completed) const latest = history[0] const resultMinutes = latest ? Math.round(latest.durationSeconds / 60) : 0 const handleGoHome = () => { haptics.buttonTap() router.replace('/') } const handleShare = async () => { haptics.selection() const isAvailable = await Sharing.isAvailableAsync() if (isAvailable) { await Sharing.shareAsync('https://tabatafit.app', { dialogTitle: t('screens:complete.shareTitle', { minutes: resultMinutes }), }) } } useEffect(() => { haptics.workoutComplete() }, []) return ( {/* Celebration */} 🎉 {t('screens:complete.title')} {/* Stats Grid */} {/* Streak */} {t('screens:complete.streakDays', { count: streak.current })} {t('screens:complete.streakRecord', { count: streak.longest })} {/* Share */} {/* Fixed Bottom Button */} ) } function createStyles(colors: ThemeColors) { return StyleSheet.create({ container: { flex: 1, backgroundColor: colors.bg.base }, scrollContent: { paddingHorizontal: LAYOUT.SCREEN_PADDING }, celebrationSection: { alignItems: 'center', paddingVertical: SPACING[8] }, celebrationEmoji: { fontSize: 64, marginBottom: SPACING[4] }, celebrationTitle: { ...TYPOGRAPHY.TITLE_1, color: TEXT.PRIMARY, letterSpacing: 1 }, statsGrid: { flexDirection: 'row', gap: SPACING[3], marginBottom: SPACING[6] }, statCard: { flex: 1, padding: SPACING[3], borderRadius: RADIUS.LG, backgroundColor: colors.surface.default.backgroundColor, alignItems: 'center', borderWidth: 1, borderColor: colors.surface.default.borderColor, borderCurve: 'continuous', }, statValue: { ...TYPOGRAPHY.TITLE_1, color: TEXT.PRIMARY, marginTop: SPACING[2], fontVariant: ['tabular-nums'] }, statLabel: { ...TYPOGRAPHY.CAPTION_2, color: TEXT.TERTIARY, marginTop: SPACING[1] }, divider: { height: 1, backgroundColor: BORDER_COLORS.DIM, marginVertical: SPACING[2] }, streakSection: { flexDirection: 'row', alignItems: 'center', paddingVertical: SPACING[4], gap: SPACING[4] }, streakBadge: { width: 64, height: 64, borderRadius: RADIUS.FULL, alignItems: 'center', justifyContent: 'center' }, streakInfo: { flex: 1 }, streakTitle: { ...TYPOGRAPHY.TITLE_2, color: TEXT.PRIMARY }, streakSubtitle: { ...TYPOGRAPHY.BODY, color: TEXT.TERTIARY, marginTop: SPACING[1] }, shareSection: { paddingVertical: SPACING[4], alignItems: 'center' }, bottomBar: { position: 'absolute', bottom: 0, left: 0, right: 0, paddingHorizontal: LAYOUT.SCREEN_PADDING, paddingTop: SPACING[4], backgroundColor: colors.bg.base, borderTopWidth: 1, borderTopColor: BORDER_COLORS.DIM, }, homeButtonContainer: { height: 56, justifyContent: 'center' }, }) }