import React, { useEffect, useRef } from 'react'; import { View, Text, StyleSheet, TouchableOpacity, TextInput, Dimensions, ActivityIndicator, Platform, Animated, Easing } from 'react-native'; import * as Haptics from 'expo-haptics'; import { LinearGradient } from 'expo-linear-gradient'; import { MaterialCommunityIcons, Feather } from '@expo/vector-icons'; import { useAppTheme } from '../context/ThemeContext'; const { width } = Dimensions.get('window'); // ── AICard: Premium Clean Card ─────────────────────── export const AICard = ({ children, style, delay = 0, variant = 'white' }: any) => { const { isDark, colors } = useAppTheme(); const fadeAnim = useRef(new Animated.Value(0)).current; const slideAnim = useRef(new Animated.Value(30)).current; useEffect(() => { Animated.parallel([ Animated.timing(fadeAnim, { toValue: 1, duration: 500, delay, useNativeDriver: true, }), Animated.timing(slideAnim, { toValue: 0, duration: 500, delay, easing: Easing.out(Easing.back(1.5)), useNativeDriver: true, }) ]).start(); }, [delay]); let bg: string; if (variant === 'white') bg = colors.surface; else if (variant === 'lime') bg = colors.primary; else if (variant === 'dark') bg = colors.secondary; else bg = variant; return ( {children} ); }; // ── AIButton: High-End CTA Button ──────────────────── export const AIButton = ({ title, onPress, loading, icon, color, style, textStyle }: any) => { const { isDark, colors } = useAppTheme(); const handlePress = () => { Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Medium); if (onPress) onPress(); }; const defaultBg = colors.primary; const defaultText = colors.secondary; const btnBg = color || defaultBg; const isLimeBg = btnBg === colors.primary; const resolvedTextColor = textStyle?.color || (isLimeBg ? colors.secondary : defaultText); return ( {loading ? ( ) : ( {icon && ( )} {title} )} ); }; // ── AIInput: Themed Input Field ────────────────────── export const AIInput = ({ label, icon, placeholder, value, onChangeText, secure, isPassword, style, keyboardType, autoCapitalize = 'none' }: any) => { const { colors } = useAppTheme(); const [showPass, setShowPass] = React.useState(false); const isSecure = secure || isPassword; return ( {label && ( {label} )} {icon && ( )} {isSecure && ( setShowPass(!showPass)} style={{ padding: 8 }}> )} ); }; // ── AISectionHeader: Section Title ─────────────────── export const AISectionHeader = ({ title, subtitle, action, onAction, style }: any) => { const { colors } = useAppTheme(); return ( {title} {subtitle && ( {subtitle} )} {action && ( {action} )} ); }; // ── AILimeBadge: Pill badge with lime accent ────────── export const AILimeBadge = ({ label, style }: any) => { const { colors } = useAppTheme(); return ( {label} ); }; // ── AISkeleton: Premium Shimmer Loader ──────────────── export const AISkeleton = ({ width, height, radius = 12, style }: any) => { const { isDark, colors } = useAppTheme(); const shimmerAnim = useRef(new Animated.Value(0)).current; useEffect(() => { Animated.loop( Animated.timing(shimmerAnim, { toValue: 1, duration: 1500, easing: Easing.linear, useNativeDriver: true, }) ).start(); }, []); const translateX = shimmerAnim.interpolate({ inputRange: [0, 1], outputRange: [-300, 300] }); const bg = colors.surface; const highlight = colors.surfaceElevated; return ( ); }; export const AIPressable = ({ children, onPress, style, containerStyle }: any) => { const scale = useRef(new Animated.Value(1)).current; const handlePressIn = () => { Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light); Animated.spring(scale, { toValue: 0.97, damping: 10, stiffness: 300, useNativeDriver: true }).start(); }; const handlePressOut = () => { Animated.spring(scale, { toValue: 1, damping: 10, stiffness: 300, useNativeDriver: true }).start(); }; return ( {children} ); }; // ── AISuccess: Animated Checkmark ────────────────── export const AISuccess = ({ size = 80 }: { size?: number }) => { const { colors } = useAppTheme(); const scale = useRef(new Animated.Value(0)).current; useEffect(() => { Animated.spring(scale, { toValue: 1, damping: 12, stiffness: 200, useNativeDriver: true }).start(); }, []); return ( ); }; const styles = StyleSheet.create({ card: { borderRadius: 24, borderWidth: 1, padding: 20, overflow: 'hidden', shadowOffset: { width: 0, height: 4 }, shadowOpacity: 0.06, shadowRadius: 16, elevation: 3 }, button: { height: 58, borderRadius: 16, alignItems: 'center', justifyContent: 'center', paddingHorizontal: 24 }, buttonContent: { flexDirection: 'row', alignItems: 'center' }, buttonText: { fontSize: 16, fontFamily: 'Outfit_700Bold' }, inputGroup: { marginBottom: 18 }, inputLabel: { fontSize: 12, fontFamily: 'Outfit_600SemiBold', marginBottom: 8, marginLeft: 2, textTransform: 'uppercase', letterSpacing: 0.5 }, inputField: { flexDirection: 'row', alignItems: 'center', height: 56, borderRadius: 14, borderWidth: 1, paddingHorizontal: 16 }, textInput: { flex: 1, fontSize: 15, fontFamily: 'Outfit_500Medium' }, sectionHeader: { flexDirection: 'row', alignItems: 'center', paddingHorizontal: 24, marginBottom: 14 }, sectionTitle: { fontSize: 20, fontFamily: 'Outfit_700Bold' }, sectionSub: { fontSize: 13, fontFamily: 'Outfit_400Regular', marginTop: 2 }, sectionAction: { fontSize: 13, fontFamily: 'Outfit_600SemiBold' }, limeBadge: { alignSelf: 'flex-start', paddingHorizontal: 10, paddingVertical: 4, borderRadius: 8 }, limeBadgeText: { fontSize: 11, fontFamily: 'Outfit_700Bold', textTransform: 'uppercase', letterSpacing: 0.5 }, successCircle: { borderRadius: 100, alignItems: 'center', justifyContent: 'center' }, });