import { useEffect } from "react"; import { View, Text, StyleSheet, TouchableOpacity, ScrollView, Platform, useWindowDimensions } from "react-native"; import Animated, { FadeInDown, FadeInRight, useSharedValue, useAnimatedStyle, withRepeat, withTiming, Easing, } from "react-native-reanimated"; import { LinearGradient } from "expo-linear-gradient"; import { useAuthStore, useMatchStore, usePacksStore } from "../../src/store"; import { Ionicons } from "@expo/vector-icons"; import { router } from "expo-router"; import { GradientBackground, GlassCard } from "../../src/components/ui"; import { colors, gradients, spacing, radius, typography, shadows } from "../../src/theme"; const MAX_CONTENT_WIDTH = 500; export default function HomeScreen() { const { user, partner, couple } = useAuthStore(); const { matches, newMatchesCount, fetchMatches } = useMatchStore(); const { packs, fetchPacks } = usePacksStore(); const { width } = useWindowDimensions(); useEffect(() => { fetchMatches(); fetchPacks(); }, []); const recentMatches = matches.slice(0, 3); const isWideScreen = width > MAX_CONTENT_WIDTH; const enabledPacksCount = packs.length; // Subtle pulsating animation for the CTA icon const pulseScale = useSharedValue(1); useEffect(() => { const startPulse = () => { pulseScale.value = 1; pulseScale.value = withRepeat( withTiming(1.1, { duration: 1000, easing: Easing.inOut(Easing.ease) }), -1, true ); }; const timeout = setTimeout(startPulse, 100); return () => clearTimeout(timeout); }, []); const pulseAnimatedStyle = useAnimatedStyle(() => { return { transform: [{ scale: pulseScale.value }], }; }); return ( {/* Header */} Hey, {user?.name || "there"} {partner ? ( {partner.name || partner.email?.split('@')[0] || 'Partner'} ) : couple ? ( router.push("/(app)/pairing")} > Waiting for partner ) : ( router.push("/(app)/pairing")} > Pair with partner )} router.push("/(app)/profile")} activeOpacity={0.8} > {user?.name?.[0]?.toUpperCase() || "U"} {/* Stats Row */} router.push("/(app)/matches")} activeOpacity={0.7} > 0 ? gradients.primary as [string, string] : [colors.glass.background, colors.glass.background]} style={styles.statIcon} start={{ x: 0, y: 0 }} end={{ x: 1, y: 1 }} > 0 ? colors.text : colors.primary} /> {matches.length} Matches router.push("/(app)/packs")} activeOpacity={0.7} > 0 ? gradients.primary as [string, string] : [colors.glass.background, colors.glass.background]} style={styles.statIcon} start={{ x: 0, y: 0 }} end={{ x: 1, y: 1 }} > 0 ? colors.text : colors.primary} /> {enabledPacksCount} Packs router.push("/(app)/matches")} activeOpacity={0.7} > 0 ? gradients.primary as [string, string] : [colors.glass.background, colors.glass.background]} style={styles.statIcon} start={{ x: 0, y: 0 }} end={{ x: 1, y: 1 }} > 0 ? colors.text : colors.primary} /> {newMatchesCount} New {/* Play CTA */} router.push("/(app)/swipe")} activeOpacity={0.9} > Ready to explore? Swipe through questions and discover what you both enjoy {/* Recent Matches */} {recentMatches.length > 0 && ( Recent Matches router.push("/(app)/matches")} style={styles.seeAllButton} > See all {recentMatches.map((match, index) => ( router.push(`/chat/${match.id}`)} activeOpacity={0.7} > {(match as any).question?.text || "A new match!"} {match.is_new && } ))} )} {/* Tips when no matches */} {recentMatches.length === 0 && ( Getting Started Enable question packs Choose topics you want to explore Swipe on questions Answer yes, no, or maybe Discover matches See where you both agree )} ); } const styles = StyleSheet.create({ container: { flex: 1, }, contentContainer: { flexGrow: 1, paddingBottom: Platform.OS === 'ios' ? 100 : 80, }, contentContainerWide: { alignItems: 'center', }, innerContainer: { flex: 1, width: '100%', }, innerContainerWide: { maxWidth: MAX_CONTENT_WIDTH, }, header: { paddingTop: 60, paddingHorizontal: spacing.lg, paddingBottom: spacing.lg, flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', }, headerLeft: { flex: 1, }, greeting: { ...typography.title1, color: colors.text, }, partnerBadge: { flexDirection: 'row', alignItems: 'center', backgroundColor: colors.primaryLight, paddingHorizontal: spacing.sm, paddingVertical: spacing.xs, borderRadius: radius.full, alignSelf: 'flex-start', marginTop: spacing.sm, gap: spacing.xs, }, partnerText: { ...typography.caption1, color: colors.text, fontWeight: '500', }, pairBadge: { flexDirection: 'row', alignItems: 'center', backgroundColor: colors.glass.background, paddingHorizontal: spacing.sm, paddingVertical: spacing.xs, borderRadius: radius.full, alignSelf: 'flex-start', marginTop: spacing.sm, gap: spacing.xs, }, pairText: { ...typography.caption1, color: colors.textTertiary, }, waitingBadge: { flexDirection: 'row', alignItems: 'center', backgroundColor: colors.primaryLight, paddingHorizontal: spacing.sm, paddingVertical: spacing.xs, borderRadius: radius.full, alignSelf: 'flex-start', marginTop: spacing.sm, gap: spacing.xs, }, waitingText: { ...typography.caption1, color: colors.text, fontWeight: '500', }, avatarGradient: { width: 48, height: 48, borderRadius: 24, justifyContent: 'center', alignItems: 'center', ...shadows.md, }, avatarInner: { width: 42, height: 42, borderRadius: 21, backgroundColor: colors.background, justifyContent: 'center', alignItems: 'center', }, avatarText: { ...typography.headline, color: colors.text, }, statsContainer: { flexDirection: "row", paddingHorizontal: spacing.lg, gap: spacing.sm, }, statCardWrapper: { flex: 1, }, statContent: { alignItems: "center", paddingVertical: spacing.sm, }, statIcon: { width: 36, height: 36, borderRadius: 18, justifyContent: "center", alignItems: "center", marginBottom: spacing.sm, }, statNumber: { ...typography.title2, color: colors.text, }, statLabel: { ...typography.caption2, color: colors.textSecondary, marginTop: 2, }, ctaSection: { paddingHorizontal: spacing.lg, marginTop: spacing.lg, }, ctaCard: { borderRadius: radius.xl, padding: spacing.lg, flexDirection: "row", alignItems: "center", ...shadows.lg, }, ctaContent: { flex: 1, }, ctaTitle: { ...typography.title3, color: colors.text, marginBottom: spacing.xs, }, ctaSubtitle: { ...typography.subhead, color: "rgba(255,255,255,0.8)", lineHeight: 20, }, ctaIconContainer: { width: 48, height: 48, borderRadius: 24, backgroundColor: "rgba(255,255,255,0.2)", justifyContent: "center", alignItems: "center", marginLeft: spacing.md, }, section: { paddingHorizontal: spacing.lg, marginTop: spacing.xl, }, sectionHeader: { flexDirection: "row", justifyContent: "space-between", alignItems: "center", marginBottom: spacing.md, }, sectionTitle: { ...typography.headline, color: colors.text, }, seeAllButton: { flexDirection: 'row', alignItems: 'center', gap: 2, }, seeAllText: { ...typography.subhead, color: colors.primary, }, matchCard: { marginBottom: spacing.sm, }, matchRow: { flexDirection: "row", alignItems: "center", }, matchIcon: { width: 32, height: 32, borderRadius: 16, justifyContent: "center", alignItems: "center", marginRight: spacing.md, }, matchText: { flex: 1, ...typography.body, color: colors.text, }, newBadge: { width: 8, height: 8, borderRadius: 4, backgroundColor: colors.primary, }, tipsTitle: { ...typography.caption1, color: colors.textTertiary, textTransform: 'uppercase', letterSpacing: 1.5, marginBottom: spacing.sm, marginLeft: spacing.xs, }, tipCard: { marginTop: spacing.sm, }, tipRow: { flexDirection: 'row', alignItems: 'center', }, tipIcon: { width: 36, height: 36, borderRadius: 18, backgroundColor: colors.primaryLight, justifyContent: 'center', alignItems: 'center', marginRight: spacing.md, }, tipContent: { flex: 1, }, tipText: { ...typography.body, color: colors.text, fontWeight: '500', }, tipSubtext: { ...typography.caption1, color: colors.textSecondary, marginTop: 2, }, bottomSpacer: { height: spacing.lg, }, });