import { HeaderBar } from '@/components/ui/HeaderBar'; import { Colors } from '@/constants/Colors'; import { useAppDispatch, useAppSelector } from '@/hooks/redux'; import { useAuthGuard } from '@/hooks/useAuthGuard'; import { initChallenge } from '@/store/challengeSlice'; import { estimateSessionMinutesWithCustom } from '@/utils/pilatesPlan'; import { Ionicons } from '@expo/vector-icons'; import { useRouter } from 'expo-router'; import React, { useEffect, useMemo } from 'react'; import { Dimensions, FlatList, SafeAreaView, StyleSheet, Text, TouchableOpacity, View } from 'react-native'; export default function ChallengeHomeScreen() { const dispatch = useAppDispatch(); const router = useRouter(); const { ensureLoggedIn } = useAuthGuard(); const challenge = useAppSelector((s) => (s as any).challenge); useEffect(() => { dispatch(initChallenge()); }, [dispatch]); const progress = useMemo(() => { const total = challenge?.days?.length || 30; const done = challenge?.days?.filter((d: any) => d.status === 'completed').length || 0; return total ? done / total : 0; }, [challenge?.days]); return ( router.back()} withSafeTop={false} transparent /> 专注核心、体态与柔韧 · 连续完成解锁徽章 {/* 进度环与统计 */} {Math.round((progress || 0) * 100)}% {challenge?.streak ?? 0} 天连续 {(challenge?.days?.filter((d: any) => d.status === 'completed').length) ?? 0} / 30 完成 {/* 日历格子(简单 6x5 网格) */} String(item.plan.dayNumber)} numColumns={5} columnWrapperStyle={{ justifyContent: 'space-between', marginBottom: 12 }} contentContainerStyle={{ paddingHorizontal: 20, paddingTop: 10, paddingBottom: 40 }} renderItem={({ item }) => { const { plan, status } = item; const isLocked = status === 'locked'; const isCompleted = status === 'completed'; const minutes = estimateSessionMinutesWithCustom(plan, item.custom); return ( { if (!(await ensureLoggedIn({ redirectTo: '/challenge', redirectParams: {} }))) return; router.push({ pathname: '/challenge/day', params: { day: String(plan.dayNumber) } }); }} style={[styles.dayCell, isLocked && styles.dayCellLocked, isCompleted && styles.dayCellCompleted]} activeOpacity={0.8} > {plan.dayNumber} {minutes}′ {isCompleted && } {isLocked && } ); }} /> {/* 底部 CTA */} { if (!(await ensureLoggedIn({ redirectTo: '/challenge' }))) return; router.push({ pathname: '/challenge/day', params: { day: String((challenge?.days?.find((d: any) => d.status === 'available')?.plan.dayNumber) || 1) } }); }}> 开始今日训练 ); } const { width } = Dimensions.get('window'); const cellSize = (width - 40 - 4 * 12) / 5; // 20 padding *2, 12 spacing *4 const styles = StyleSheet.create({ safeArea: { flex: 1, backgroundColor: '#F7F8FA' }, container: { flex: 1, backgroundColor: '#F7F8FA' }, header: { paddingHorizontal: 20, paddingTop: 10 }, headerRow: { flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between' }, backButton: { width: 32, height: 32, borderRadius: 16, alignItems: 'center', justifyContent: 'center', backgroundColor: '#E5E7EB' }, headerTitle: { fontSize: 22, fontWeight: '800', color: '#1A1A1A' }, subtitle: { marginTop: 6, fontSize: 12, color: '#6B7280' }, summaryCard: { marginTop: 16, marginHorizontal: 20, backgroundColor: '#FFFFFF', borderRadius: 16, padding: 16, flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between', shadowColor: '#000', shadowOpacity: 0.06, shadowRadius: 12, shadowOffset: { width: 0, height: 6 }, elevation: 3, }, summaryLeft: { flexDirection: 'row', alignItems: 'center' }, progressPill: { width: 120, height: 10, borderRadius: 999, backgroundColor: '#E5E7EB', overflow: 'hidden' }, progressFill: { height: '100%', backgroundColor: Colors.light.accentGreen }, progressText: { marginLeft: 12, fontWeight: '700', color: '#111827' }, summaryRight: {}, summaryItem: { fontSize: 12, color: '#6B7280' }, summaryItemValue: { fontWeight: '800', color: '#111827' }, dayCell: { width: cellSize, height: cellSize, borderRadius: 16, backgroundColor: '#FFFFFF', alignItems: 'center', justifyContent: 'center', shadowColor: '#000', shadowOpacity: 0.06, shadowRadius: 12, shadowOffset: { width: 0, height: 6 }, elevation: 3, }, dayCellLocked: { backgroundColor: '#F3F4F6' }, dayCellCompleted: { backgroundColor: '#ECFDF5', borderWidth: 1, borderColor: '#A7F3D0' }, dayNumber: { fontWeight: '800', color: '#111827', fontSize: 16 }, dayNumberLocked: { color: '#9CA3AF' }, dayMinutes: { marginTop: 4, fontSize: 12, color: '#6B7280' }, bottomBar: { padding: 20 }, startButton: { backgroundColor: Colors.light.accentGreen, paddingVertical: 14, borderRadius: 999, alignItems: 'center' }, startButtonText: { color: '#192126', fontWeight: '800', fontSize: 16 }, });