import { CHALLENGES, type Challenge } from '@/app/(tabs)/challenges'; import { HeaderBar } from '@/components/ui/HeaderBar'; import { Colors } from '@/constants/Colors'; import { useColorScheme } from '@/hooks/useColorScheme'; import { Ionicons } from '@expo/vector-icons'; import { LinearGradient } from 'expo-linear-gradient'; import { useLocalSearchParams, useRouter } from 'expo-router'; import React, { useMemo, useState } from 'react'; import { Dimensions, Image, Platform, ScrollView, Share, StatusBar, StyleSheet, Text, TouchableOpacity, View, } from 'react-native'; import { SafeAreaView, useSafeAreaInsets } from 'react-native-safe-area-context'; const { width } = Dimensions.get('window'); const HERO_HEIGHT = width * 0.86; const BADGE_SIZE = 120; type ChallengeDetail = { badgeImage: string; periodLabel: string; durationLabel: string; requirementLabel: string; summary?: string; participantsCount: number; rankingDescription?: string; rankings: Record; highlightTitle: string; highlightSubtitle: string; ctaLabel: string; }; type RankingItem = { id: string; name: string; avatar: string; metric: string; badge?: string; }; const DETAIL_PRESETS: Record = { 'hydration-hippo': { badgeImage: 'https://images.unsplash.com/photo-1616628182503-5ef2941510da?auto=format&fit=crop&w=240&q=80', periodLabel: '9月01日 - 9月30日 · 剩余 4 天', durationLabel: '30 天', requirementLabel: '喝水 1500ml 15 天以上', summary: '与河马一起练就最佳补水习惯,让身体如湖水般澄澈充盈。', participantsCount: 9009, rankingDescription: '榜单实时更新,记录每位补水达人每日平均饮水量。', rankings: { all: [ { id: 'all-1', name: '湖光暮色', avatar: 'https://images.unsplash.com/photo-1500648767791-00dcc994a43e?auto=format&fit=crop&w=140&q=80', metric: '平均 3,200 ml', badge: '金冠冠军', }, { id: 'all-2', name: '温柔潮汐', avatar: 'https://images.unsplash.com/photo-1524504388940-b1c1722653e1?auto=format&fit=crop&w=140&q=80', metric: '平均 2,980 ml', }, { id: 'all-3', name: '晨雾河岸', avatar: 'https://images.unsplash.com/photo-1544723795-432537f48b2b?auto=format&fit=crop&w=140&q=80', metric: '平均 2,860 ml', }, ], male: [ { id: 'male-1', name: '北岸微风', avatar: 'https://images.unsplash.com/photo-1488426862026-3ee34a7d66df?auto=format&fit=crop&w=140&q=80', metric: '平均 3,120 ml', }, { id: 'male-2', name: '静水晚霞', avatar: 'https://images.unsplash.com/photo-1524504388940-b1c1722653e1?auto=format&fit=crop&w=140&q=80', metric: '平均 2,940 ml', }, ], female: [ { id: 'female-1', name: '露珠初晓', avatar: 'https://images.unsplash.com/photo-1544723795-3fb6469f5b39?auto=format&fit=crop&w=140&q=80', metric: '平均 3,060 ml', }, { id: 'female-2', name: '桔梗水语', avatar: 'https://images.unsplash.com/photo-1521572267360-ee0c2909d518?auto=format&fit=crop&w=140&q=80', metric: '平均 2,880 ml', }, ], }, highlightTitle: '分享一次,免费参与', highlightSubtitle: '解锁高级会员,无限加入挑战', ctaLabel: '马上分享激励好友', }, }; const DEFAULT_DETAIL: ChallengeDetail = { badgeImage: 'https://images.unsplash.com/photo-1524504388940-b1c1722653e1?auto=format&fit=crop&w=240&q=80', periodLabel: '本周进行中', durationLabel: '30 天', requirementLabel: '保持专注完成每日任务', participantsCount: 3200, highlightTitle: '立即参加,点燃动力', highlightSubtitle: '邀请好友一起坚持,更容易收获成果', ctaLabel: '立即加入挑战', rankings: { all: [], }, }; const SEGMENTS = [ { key: 'all', label: '全部' }, { key: 'male', label: '男生' }, { key: 'female', label: '女生' }, ] as const; type SegmentKey = (typeof SEGMENTS)[number]['key']; export default function ChallengeDetailScreen() { const { id } = useLocalSearchParams<{ id?: string }>(); const router = useRouter(); const theme = (useColorScheme() ?? 'light') as 'light' | 'dark'; const colorTokens = Colors[theme]; const insets = useSafeAreaInsets(); const challenge = useMemo(() => { if (!id) return undefined; return CHALLENGES.find((item) => item.id === id); }, [id]); const detail = useMemo(() => { if (!id) return DEFAULT_DETAIL; return DETAIL_PRESETS[id] ?? { ...DEFAULT_DETAIL, periodLabel: challenge?.dateRange ?? DEFAULT_DETAIL.periodLabel, highlightTitle: `加入 ${challenge?.title ?? '挑战'}`, }; }, [challenge?.dateRange, challenge?.title, id]); const [segment, setSegment] = useState('all'); const rankingData = detail.rankings[segment] ?? detail.rankings.all ?? []; const handleShare = async () => { if (!challenge) { return; } try { await Share.share({ title: challenge.title, message: `我正在参与「${challenge.title}」,一起坚持吧!`, url: challenge.image, }); } catch (error) { console.warn('分享失败', error); } }; const handleJoin = () => { // 当前没有具体业务流程,先回退到挑战列表 router.back(); }; if (!challenge) { return ( router.back()} withSafeTop transparent={false} /> 未找到该挑战,稍后再试试吧。 ); } return ( } /> {detail.periodLabel} {challenge.title} {detail.summary ? {detail.summary} : null} {challenge.dateRange} {detail.durationLabel} {detail.requirementLabel} 按日打卡自动累计 {detail.participantsCount.toLocaleString('zh-CN')} 人正在参与 {challenge.avatars.slice(0, 6).map((avatar, index) => ( 0 && styles.avatarOffset]} /> ))} 更多 排行榜 查看全部 {detail.rankingDescription ? ( {detail.rankingDescription} ) : null} {SEGMENTS.map(({ key, label }) => { const isActive = segment === key; const disabled = !(detail.rankings[key] && detail.rankings[key].length); return ( { if (disabled) return; setSegment(key); }} > {label} ); })} {rankingData.length ? ( rankingData.map((item, index) => ( 0 && styles.rankingRowDivider]}> {index + 1} {item.name} {item.metric} {item.badge ? {item.badge} : null} )) ) : ( 榜单即将开启,快来抢占席位。 )} {detail.highlightTitle} {detail.highlightSubtitle} {detail.ctaLabel} ); } const styles = StyleSheet.create({ safeArea: { flex: 1, backgroundColor: '#f3f4fb', }, headerOverlay: { position: 'absolute', left: 0, right: 0, top: 0, zIndex: 20, }, heroContainer: { height: HERO_HEIGHT, width: '100%', overflow: 'hidden', borderBottomLeftRadius: 36, borderBottomRightRadius: 36, }, heroImage: { width: '100%', height: '100%', }, scrollView: { flex: 1, }, scrollContent: { paddingBottom: Platform.select({ ios: 40, default: 28 }), }, badgeWrapper: { alignItems: 'center', marginTop: -BADGE_SIZE / 2, }, badgeShadow: { width: BADGE_SIZE, height: BADGE_SIZE, borderRadius: BADGE_SIZE / 2, backgroundColor: '#fff', padding: 12, shadowColor: 'rgba(17, 24, 39, 0.2)', shadowOpacity: 0.25, shadowRadius: 18, shadowOffset: { width: 0, height: 10 }, elevation: 12, }, badgeImage: { flex: 1, borderRadius: BADGE_SIZE / 2, }, headerTextBlock: { paddingHorizontal: 24, marginTop: 24, alignItems: 'center', }, periodLabel: { fontSize: 14, color: '#596095', letterSpacing: 0.2, }, title: { marginTop: 10, fontSize: 24, fontWeight: '800', color: '#1c1f3a', textAlign: 'center', }, summary: { marginTop: 12, fontSize: 14, lineHeight: 20, color: '#7080b4', textAlign: 'center', }, detailCard: { marginTop: 28, marginHorizontal: 20, padding: 20, borderRadius: 28, backgroundColor: '#ffffff', shadowColor: 'rgba(30, 41, 59, 0.18)', shadowOpacity: 0.2, shadowRadius: 20, shadowOffset: { width: 0, height: 12 }, elevation: 8, gap: 20, }, detailRow: { flexDirection: 'row', alignItems: 'center', }, detailIconWrapper: { width: 42, height: 42, borderRadius: 21, backgroundColor: '#EFF1FF', alignItems: 'center', justifyContent: 'center', }, detailTextWrapper: { marginLeft: 14, }, detailLabel: { fontSize: 15, fontWeight: '600', color: '#1c1f3a', }, detailMeta: { marginTop: 4, fontSize: 12, color: '#6f7ba7', }, avatarRow: { flexDirection: 'row', alignItems: 'center', marginTop: 12, }, avatar: { width: 36, height: 36, borderRadius: 18, borderWidth: 2, borderColor: '#fff', }, avatarOffset: { marginLeft: -12, }, moreAvatarButton: { marginLeft: 12, paddingHorizontal: 12, paddingVertical: 6, borderRadius: 14, backgroundColor: '#EEF0FF', }, moreAvatarText: { fontSize: 12, color: '#4F5BD5', fontWeight: '600', }, sectionHeader: { marginTop: 36, marginHorizontal: 24, flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between', }, sectionTitle: { fontSize: 18, fontWeight: '700', color: '#1c1f3a', }, sectionAction: { fontSize: 13, fontWeight: '600', color: '#5F6BF0', }, sectionSubtitle: { marginTop: 8, marginHorizontal: 24, fontSize: 13, color: '#6f7ba7', lineHeight: 18, }, segmentedControl: { marginTop: 20, marginHorizontal: 24, borderRadius: 20, backgroundColor: '#EAECFB', padding: 4, flexDirection: 'row', }, segmentButton: { flex: 1, paddingVertical: 8, borderRadius: 16, alignItems: 'center', justifyContent: 'center', }, segmentButtonActive: { backgroundColor: '#fff', shadowColor: 'rgba(79, 91, 213, 0.25)', shadowOpacity: 0.3, shadowRadius: 10, shadowOffset: { width: 0, height: 6 }, elevation: 4, }, segmentDisabled: { opacity: 0.5, }, segmentLabel: { fontSize: 13, fontWeight: '600', color: '#6372C6', }, segmentLabelActive: { color: '#4F5BD5', }, segmentLabelDisabled: { color: '#9AA3CF', }, rankingCard: { marginTop: 20, marginHorizontal: 24, borderRadius: 24, backgroundColor: '#ffffff', paddingVertical: 10, shadowColor: 'rgba(30, 41, 59, 0.12)', shadowOpacity: 0.16, shadowRadius: 18, shadowOffset: { width: 0, height: 10 }, elevation: 6, }, rankingRow: { flexDirection: 'row', alignItems: 'center', paddingVertical: 12, paddingHorizontal: 18, }, rankingRowDivider: { borderTopWidth: StyleSheet.hairlineWidth, borderTopColor: '#E5E7FF', }, rankingOrderCircle: { width: 32, height: 32, borderRadius: 16, alignItems: 'center', justifyContent: 'center', backgroundColor: '#EEF0FF', marginRight: 12, }, rankingOrder: { fontSize: 15, fontWeight: '700', color: '#4F5BD5', }, rankingAvatar: { width: 44, height: 44, borderRadius: 22, marginRight: 14, }, rankingInfo: { flex: 1, }, rankingName: { fontSize: 15, fontWeight: '700', color: '#1c1f3a', }, rankingMetric: { marginTop: 4, fontSize: 13, color: '#6f7ba7', }, rankingBadge: { fontSize: 12, color: '#A67CFF', fontWeight: '700', }, emptyRanking: { paddingVertical: 40, alignItems: 'center', }, emptyRankingText: { fontSize: 14, color: '#6f7ba7', }, highlightCard: { marginTop: 32, marginHorizontal: 24, borderRadius: 28, paddingVertical: 28, paddingHorizontal: 24, overflow: 'hidden', }, highlightTitle: { fontSize: 18, fontWeight: '800', color: '#ffffff', }, highlightSubtitle: { marginTop: 10, fontSize: 14, color: 'rgba(255,255,255,0.85)', lineHeight: 20, }, highlightButton: { marginTop: 22, backgroundColor: 'rgba(255,255,255,0.18)', paddingVertical: 12, borderRadius: 22, alignItems: 'center', borderWidth: 1, borderColor: 'rgba(247,248,255,0.5)', }, highlightButtonLabel: { fontSize: 15, fontWeight: '700', color: '#ffffff', }, circularButton: { width: 40, height: 40, borderRadius: 20, backgroundColor: 'rgba(255,255,255,0.24)', alignItems: 'center', justifyContent: 'center', borderWidth: 1, borderColor: 'rgba(255,255,255,0.45)', }, shareIcon: { fontSize: 18, color: '#ffffff', fontWeight: '700', }, missingContainer: { flex: 1, alignItems: 'center', justifyContent: 'center', paddingHorizontal: 32, }, missingText: { fontSize: 16, textAlign: 'center', }, });