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