import React, { useEffect, useRef, useState } from 'react'; import { StyleSheet, Animated, Image } from 'react-native'; import { View, Text, useTheme } from '@bettoredge/styles'; import { Ionicons } from '@expo/vector-icons'; import type { CalcuttaAuctionItemProps } from '@bettoredge/types'; import { formatCurrency } from '../helpers/formatting'; import { CalcuttaCountdown } from './CalcuttaCountdown'; export interface ItemSoldCelebrationProps { visible: boolean; item?: CalcuttaAuctionItemProps; winnerName?: string; winnerProfilePic?: string; winningBid?: number; isMe?: boolean; marketType?: string; /** Next item coming up (shown at bottom of modal) */ nextItem?: CalcuttaAuctionItemProps; nextItemDeadline?: string; /** Auto-dismiss after this many ms (default 5000) */ autoDismissMs?: number; onDismiss: () => void; itemImage?: string; } export const ItemSoldCelebration: React.FC = ({ visible, item, winnerName, winnerProfilePic, winningBid, isMe, marketType = 'FOR_MONEY', nextItem, nextItemDeadline, autoDismissMs = 5000, onDismiss, itemImage, }) => { const { theme } = useTheme(); const opacityAnim = useRef(new Animated.Value(0)).current; const scaleAnim = useRef(new Animated.Value(0.8)).current; const trophyBounce = useRef(new Animated.Value(0)).current; const confettiAnim = useRef(new Animated.Value(0)).current; useEffect(() => { if (!visible) { Animated.timing(opacityAnim, { toValue: 0, duration: 300, useNativeDriver: true }).start(); return; } // Entrance opacityAnim.setValue(0); scaleAnim.setValue(0.8); trophyBounce.setValue(0); confettiAnim.setValue(0); Animated.parallel([ Animated.timing(opacityAnim, { toValue: 1, duration: 300, useNativeDriver: true }), Animated.spring(scaleAnim, { toValue: 1, friction: 4, tension: 80, useNativeDriver: true }), ]).start(() => { // Trophy bounce Animated.sequence([ Animated.timing(trophyBounce, { toValue: -20, duration: 200, useNativeDriver: true }), Animated.spring(trophyBounce, { toValue: 0, friction: 3, tension: 120, useNativeDriver: true }), ]).start(); // Confetti burst Animated.timing(confettiAnim, { toValue: 1, duration: 600, useNativeDriver: true }).start(); }); // Auto-dismiss const timer = setTimeout(() => { Animated.timing(opacityAnim, { toValue: 0, duration: 400, useNativeDriver: true }).start(() => onDismiss()); }, autoDismissMs); return () => clearTimeout(timer); }, [visible]); if (!visible || !item) return null; const accentColor = isMe ? '#10B981' : '#F59E0B'; return ( {/* Confetti dots */} {[...Array(12)].map((_, i) => { const angle = (i / 12) * Math.PI * 2; const colors = ['#F59E0B', '#10B981', '#3B82F6', '#EF4444', '#8B5CF6', '#EC4899']; return ( ); })} {/* Trophy */} {/* SOLD label */} SOLD! {/* Item info */} {itemImage ? ( ) : ( )} {item.item_name} {item.seed != null && Seed #{item.seed}} {/* Winner + bid */} {winnerProfilePic ? ( ) : ( {(winnerName || '?').charAt(0).toUpperCase()} )} {isMe ? 'You won!' : winnerName || 'Winner'} {formatCurrency(winningBid ?? 0, marketType)} {isMe && } {/* Next item teaser */} {nextItem && ( Next up {nextItem.item_name} {nextItemDeadline && ( )} )} ); }; const styles = StyleSheet.create({ overlay: { ...StyleSheet.absoluteFillObject, zIndex: 998, alignItems: 'center', justifyContent: 'center', }, backdrop: { ...StyleSheet.absoluteFillObject, backgroundColor: 'rgba(0,0,0,0.75)', }, card: { backgroundColor: '#1a1a2e', borderRadius: 24, padding: 28, alignItems: 'center', width: '85%', maxWidth: 360, overflow: 'visible', }, trophyCircle: { width: 80, height: 80, borderRadius: 40, alignItems: 'center', justifyContent: 'center', }, soldLabel: { fontSize: 28, lineHeight: 37, fontWeight: '900', letterSpacing: 4, marginBottom: 20, }, itemRow: { flexDirection: 'row', alignItems: 'center', width: '100%', marginBottom: 16, }, itemImage: { width: 48, height: 48, borderRadius: 10, }, itemName: { color: '#FFFFFF', fontSize: 18, lineHeight: 24, fontWeight: '700', }, itemSeed: { color: 'rgba(255,255,255,0.5)', fontSize: 13, lineHeight: 17, marginTop: 2, }, winnerRow: { flexDirection: 'row', alignItems: 'center', width: '100%', padding: 14, borderRadius: 14, borderWidth: 1, }, winnerAvatar: { width: 36, height: 36, borderRadius: 18, overflow: 'hidden', }, winnerName: { fontSize: 15, lineHeight: 20, fontWeight: '700', }, bidAmount: { color: '#FFFFFF', fontSize: 18, lineHeight: 24, fontWeight: '800', marginTop: 2, }, nextSection: { width: '100%', alignItems: 'center', marginTop: 16, }, divider: { width: 40, height: 2, backgroundColor: 'rgba(255,255,255,0.15)', borderRadius: 1, marginBottom: 12, }, nextLabel: { color: 'rgba(255,255,255,0.4)', fontSize: 12, lineHeight: 16, textTransform: 'uppercase', letterSpacing: 1, }, nextItemName: { color: '#FFFFFF', fontSize: 16, lineHeight: 21, fontWeight: '600', marginTop: 4, }, });