import React, { useEffect, useState } from 'react'; import { View, Text, StyleSheet, Pressable, Platform, Image, Modal, TouchableOpacity } from 'react-native'; import { Ionicons } from '@expo/vector-icons'; import { LinearGradient } from 'expo-linear-gradient'; import { BlurView } from 'expo-blur'; import Animated, { useAnimatedStyle, useSharedValue, withSpring, FadeIn, FadeOut, } from 'react-native-reanimated'; import { colors, spacing, radius, typography } from '../../theme'; import type { IntensityLevel } from '@/types'; export interface IntensitySliderProps { value: IntensityLevel; onValueChange: (value: IntensityLevel) => void; disabled?: boolean; /** Partner's intensity level (shows as a ghost indicator) */ partnerValue?: IntensityLevel | null; /** Partner's name for the mismatch message */ partnerName?: string; /** Partner's avatar URL */ partnerAvatar?: string | null; } const INTENSITY_LEVELS: Array<{ level: IntensityLevel; label: string; emoji: string; description: string }> = [ { level: 1, label: 'Gentle', emoji: '💭', description: 'Pure emotional connection & non-sexual bonding' }, { level: 2, label: 'Warm', emoji: '💕', description: 'Romantic atmosphere & affectionate touch' }, { level: 3, label: 'Playful', emoji: '😏', description: 'Light sexual exploration & sensual discovery' }, { level: 4, label: 'Steamy', emoji: '🔥', description: 'Explicit sexual activities & moderate adventure' }, { level: 5, label: 'Intense', emoji: '🌶️', description: 'Advanced/BDSM/Extreme exploration' }, ]; const HEAT_COLORS = [ '#9b59b6', // Purple - gentle '#e94560', // Rose - warm '#ff6b6b', // Coral - playful '#ff4757', // Red - steamy '#ff3333', // Bright red - intense ]; const triggerHaptic = async () => { if (Platform.OS === 'web') return; const Haptics = await import('expo-haptics'); await Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light); }; export function IntensitySlider({ value, onValueChange, disabled = false, partnerValue, partnerName, partnerAvatar, }: IntensitySliderProps) { const current = INTENSITY_LEVELS[value - 1] ?? INTENSITY_LEVELS[1]; const progress = useSharedValue((value - 1) / 4); const [showInfoModal, setShowInfoModal] = useState(false); const hasPartner = partnerValue != null; const partnerLevel = hasPartner ? INTENSITY_LEVELS[partnerValue - 1] : null; const levelsDiffer = hasPartner && value !== partnerValue; const userIsHigher = hasPartner && value > partnerValue; const displayPartnerName = partnerName || 'Your partner'; useEffect(() => { progress.value = withSpring((value - 1) / 4, { damping: 15, stiffness: 150 }); }, [value]); const handleSelect = async (nextValue: IntensityLevel) => { if (disabled || nextValue === value) return; await triggerHaptic(); onValueChange(nextValue); }; const progressStyle = useAnimatedStyle(() => ({ width: `${progress.value * 100}%`, })); const getMismatchMessage = () => { if (!levelsDiffer || !partnerLevel) return null; if (userIsHigher) { return `${displayPartnerName} is at ${partnerLevel.label} — tap for details`; } return `${displayPartnerName} is at ${partnerLevel.label}`; }; return ( {/* Progress track */} {/* Level indicators */} {INTENSITY_LEVELS.map((level) => { const isSelected = value === level.level; const isPassed = value > level.level; const isActive = isSelected || isPassed; const isPartnerLevel = hasPartner && partnerValue === level.level; return ( handleSelect(level.level)} disabled={disabled} > {/* Partner indicator ring */} {isPartnerLevel && !isSelected && ( {partnerAvatar ? ( ) : ( )} )} {isSelected ? ( {level.emoji} ) : ( )} {level.label} ); })} {/* Current level card */} {current.emoji} {current.label} {hasPartner && !levelsDiffer && ( setShowInfoModal(true)} > Matched )} {current.description} {/* Mismatch message */} {levelsDiffer && ( setShowInfoModal(true)} > {partnerAvatar ? ( ) : ( )} {getMismatchMessage()} )} {/* Info Modal */} setShowInfoModal(false)} > setShowInfoModal(false)} > e.stopPropagation()}> {Platform.OS === 'ios' ? ( ) : null} {/* Header */} {levelsDiffer ? ( ) : ( )} {levelsDiffer ? (userIsHigher ? "Different Comfort Zones" : "Room to Explore") : "You're Perfectly Matched" } {/* Comparison visual */} {hasPartner && ( {current.emoji} You {current.label} {partnerAvatar ? ( ) : ( {partnerLevel?.emoji} )} {displayPartnerName} {partnerLevel?.label} )} {/* Explanation */} {!levelsDiffer ? ( <> You and {displayPartnerName} have the same comfort zone setting. You'll both see the same question packs and can match on everything! Perfect alignment means more matches ) : userIsHigher ? ( <> You're both seeing questions up to {partnerLevel?.label} level because that's {displayPartnerName}'s comfort zone. You won't see {current.label} content until {displayPartnerName} raises their level The lower setting between you determines what you both see. ) : ( <> You're both seeing questions up to {current.label} level based on your comfort zone. {displayPartnerName} is at {partnerLevel?.label} — raise yours to unlock more content together )} {/* Close button */} setShowInfoModal(false)} > Got it ); } const styles = StyleSheet.create({ container: { gap: spacing.md, }, containerDisabled: { opacity: 0.6, }, trackContainer: { paddingHorizontal: spacing.lg, }, track: { height: 4, backgroundColor: 'rgba(255, 255, 255, 0.1)', borderRadius: 2, overflow: 'hidden', }, progressFill: { height: '100%', borderRadius: 2, overflow: 'hidden', }, levelsRow: { flexDirection: 'row', justifyContent: 'space-between', paddingHorizontal: spacing.xs, }, levelButton: { alignItems: 'center', flex: 1, }, indicatorWrapper: { position: 'relative', marginBottom: spacing.xs, }, levelIndicator: { width: 36, height: 36, borderRadius: 18, alignItems: 'center', justifyContent: 'center', backgroundColor: 'rgba(255, 255, 255, 0.05)', borderWidth: 2, borderColor: 'rgba(255, 255, 255, 0.1)', }, levelIndicatorActive: { backgroundColor: 'rgba(233, 69, 96, 0.15)', borderColor: 'rgba(233, 69, 96, 0.3)', }, levelIndicatorPartner: { borderColor: colors.secondary, borderStyle: 'dashed', }, partnerRing: { position: 'absolute', top: -6, right: -6, width: 18, height: 18, borderRadius: 9, backgroundColor: colors.secondary, alignItems: 'center', justifyContent: 'center', zIndex: 1, borderWidth: 2, borderColor: colors.backgroundLight, }, partnerAvatarSmall: { width: 14, height: 14, borderRadius: 7, }, levelEmoji: { fontSize: 16, }, levelLabel: { ...typography.caption2, color: colors.textTertiary, textAlign: 'center', }, levelLabelActive: { color: colors.text, fontWeight: '600', }, levelLabelPartner: { color: colors.secondary, }, currentCard: { backgroundColor: 'rgba(255, 255, 255, 0.05)', borderRadius: radius.md, padding: spacing.md, borderWidth: 1, borderColor: 'rgba(255, 255, 255, 0.08)', }, currentCardWarning: { borderColor: 'rgba(243, 156, 18, 0.3)', backgroundColor: 'rgba(243, 156, 18, 0.05)', }, currentHeader: { flexDirection: 'row', alignItems: 'center', gap: spacing.sm, marginBottom: spacing.xs, }, currentEmoji: { fontSize: 20, }, currentLabel: { ...typography.subhead, fontWeight: '600', color: colors.text, }, matchBadge: { flexDirection: 'row', alignItems: 'center', gap: 4, marginLeft: 'auto', backgroundColor: 'rgba(46, 204, 113, 0.15)', paddingHorizontal: spacing.sm, paddingVertical: 2, borderRadius: radius.full, }, matchBadgeText: { ...typography.caption2, color: colors.success, fontWeight: '600', }, currentDescription: { ...typography.caption1, color: colors.textSecondary, lineHeight: 18, }, mismatchRow: { flexDirection: 'row', alignItems: 'center', gap: spacing.sm, marginTop: spacing.sm, paddingTop: spacing.sm, borderTopWidth: 1, borderTopColor: 'rgba(255, 255, 255, 0.08)', }, partnerAvatarTiny: { width: 20, height: 20, borderRadius: 10, }, partnerIconTiny: { width: 20, height: 20, borderRadius: 10, backgroundColor: 'rgba(155, 89, 182, 0.2)', alignItems: 'center', justifyContent: 'center', }, mismatchText: { ...typography.caption1, color: colors.textSecondary, flex: 1, }, mismatchTextWarning: { color: colors.warning, }, // Modal styles modalOverlay: { flex: 1, backgroundColor: 'rgba(0, 0, 0, 0.7)', justifyContent: 'center', alignItems: 'center', padding: spacing.lg, }, modalContent: { width: '100%', maxWidth: 360, borderRadius: radius.xl, overflow: 'hidden', backgroundColor: Platform.OS === 'ios' ? 'transparent' : colors.backgroundLight, borderWidth: 1, borderColor: 'rgba(255, 255, 255, 0.1)', }, modalInner: { padding: spacing.lg, backgroundColor: Platform.OS === 'ios' ? 'rgba(26, 26, 46, 0.85)' : 'transparent', }, modalHeader: { alignItems: 'center', marginBottom: spacing.lg, }, modalIconGradient: { width: 56, height: 56, borderRadius: 28, alignItems: 'center', justifyContent: 'center', marginBottom: spacing.md, }, modalTitle: { ...typography.title3, color: colors.text, textAlign: 'center', }, comparisonContainer: { flexDirection: 'row', alignItems: 'center', justifyContent: 'center', backgroundColor: 'rgba(255, 255, 255, 0.05)', borderRadius: radius.lg, padding: spacing.md, marginBottom: spacing.lg, }, comparisonPerson: { alignItems: 'center', flex: 1, }, comparisonAvatar: { width: 48, height: 48, borderRadius: 24, alignItems: 'center', justifyContent: 'center', marginBottom: spacing.xs, }, comparisonAvatarImage: { width: 48, height: 48, borderRadius: 24, marginBottom: spacing.xs, }, comparisonEmoji: { fontSize: 24, }, comparisonName: { ...typography.caption1, color: colors.text, fontWeight: '600', }, comparisonLevel: { ...typography.caption2, color: colors.textSecondary, }, comparisonDivider: { width: 40, alignItems: 'center', }, modalExplanation: { marginBottom: spacing.lg, }, modalText: { ...typography.subhead, color: colors.textSecondary, textAlign: 'center', lineHeight: 22, marginBottom: spacing.md, }, modalSubtext: { ...typography.caption1, color: colors.textTertiary, textAlign: 'center', marginTop: spacing.sm, }, modalTip: { flexDirection: 'row', alignItems: 'center', justifyContent: 'center', backgroundColor: 'rgba(46, 204, 113, 0.1)', borderRadius: radius.md, padding: spacing.sm, gap: spacing.xs, }, modalTipWarning: { backgroundColor: 'rgba(243, 156, 18, 0.1)', }, modalTipText: { ...typography.caption1, color: colors.success, flex: 1, }, modalTipTextWarning: { color: colors.warning, }, modalCloseButton: { backgroundColor: colors.glass.background, borderRadius: radius.md, paddingVertical: spacing.md, alignItems: 'center', borderWidth: 1, borderColor: colors.glass.border, }, modalCloseText: { ...typography.subhead, color: colors.text, fontWeight: '600', }, }); export default IntensitySlider;