/**
* 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' },
})
}