import React, { useState, useEffect, useRef } from 'react'; import { StyleSheet, TouchableOpacity } from 'react-native'; import { View, Text, useTheme } from '@bettoredge/styles'; import { Ionicons } from '@expo/vector-icons'; import type { CalcuttaCompetitionProps, CalcuttaEscrowProps, CalcuttaBidProps, CalcuttaAuctionItemProps } from '@bettoredge/types'; import type { CalcuttaLifecycleState } from '../../helpers/lifecycleState'; import { formatCurrency } from '../../helpers/formatting'; interface SealedBidStatusBarProps { competition: CalcuttaCompetitionProps; escrow?: CalcuttaEscrowProps; my_bids: CalcuttaBidProps[]; items: CalcuttaAuctionItemProps[]; totalItems: number; market_type: string; player_id?: string; lifecycleState: CalcuttaLifecycleState; auctionExpired?: boolean; isParticipant?: boolean; onEscrowTap: () => void; onLeave?: () => void; leaving?: boolean; } const getTimerColor = (msLeft: number) => { if (msLeft > 3600000) return '#10B981'; if (msLeft > 600000) return '#F59E0B'; return '#EF4444'; }; export const SealedBidStatusBar: React.FC = ({ competition, escrow, my_bids, items, totalItems, market_type, player_id, lifecycleState, auctionExpired, isParticipant, onEscrowTap, onLeave, leaving, }) => { const { theme } = useTheme(); const [timeLeft, setTimeLeft] = useState(''); const [msLeft, setMsLeft] = useState(Infinity); const timerRef = useRef | null>(null); const timerTarget = lifecycleState === 'auctioning' ? competition.auction_end_datetime : lifecycleState === 'scheduled' ? competition.scheduled_datetime : undefined; useEffect(() => { if (!timerTarget) { setTimeLeft(''); setMsLeft(0); return; } const update = () => { const end = new Date(timerTarget).getTime(); const diff = end - Date.now(); setMsLeft(diff); if (diff <= 0) { setTimeLeft(lifecycleState === 'auctioning' ? 'Closed' : 'Starting...'); if (timerRef.current) clearInterval(timerRef.current); return; } const d = Math.floor(diff / 86400000); const h = Math.floor((diff % 86400000) / 3600000); const m = Math.floor((diff % 3600000) / 60000); const s = Math.floor((diff % 60000) / 1000); if (d > 0) setTimeLeft(`${d}d ${h}h`); else if (h > 0) setTimeLeft(`${h}h ${m}m`); else setTimeLeft(`${m}:${s.toString().padStart(2, '0')}`); }; update(); timerRef.current = setInterval(update, 1000); return () => { if (timerRef.current) clearInterval(timerRef.current); }; }, [timerTarget, lifecycleState]); const escrowBalance = Number(escrow?.escrow_balance ?? 0); const committed = Number(escrow?.committed_balance ?? 0); const total = escrowBalance + committed; // All items I purchased (active + eliminated) const myPurchasedItems = items.filter(i => i.winning_player_id === player_id); // ============================================ // PENDING // ============================================ if (lifecycleState === 'pending') { return ( Coming Soon Items: {totalItems} ); } // ============================================ // SCHEDULED // ============================================ if (lifecycleState === 'scheduled') { return ( {timeLeft ? `Starts ${timeLeft}` : 'Scheduled'} {formatCurrency(escrowBalance, market_type)} {items.length > 0 ? `${totalItems} items` : '0'} ); } // ============================================ // AUCTIONING — big KPI-style bar // ============================================ if (lifecycleState === 'auctioning') { const activeBids = my_bids.filter(b => b.bid_status === 'active').length; const timerColor = auctionExpired ? '#F59E0B' : getTimerColor(msLeft); // Safe auction metrics (no bid amount leaks) const totalBidsPlaced = items.reduce((s, i) => s + (i.bid_count ?? 0), 0); const itemsWithBids = items.filter(i => (i.bid_count ?? 0) > 0).length; const minPot = competition.min_bid * totalItems; const myTotalBid = my_bids .filter(b => b.bid_status === 'active') .reduce((s, b) => s + Number(b.bid_amount), 0); return ( {/* Timer row */} {auctionExpired ? 'Closing...' : timeLeft} {/* Auction Activity (safe metrics only) */} Auction Activity {itemsWithBids}/{totalItems} Items Bid {totalBidsPlaced} Total Bids {formatCurrency(minPot, market_type)} Min Pot {/* My Escrow KPIs — only for participants */} {isParticipant && ( Available {formatCurrency(escrowBalance, market_type)} My Bids {formatCurrency(myTotalBid, market_type)} My Items {activeBids}/{totalItems} )} {/* Transfer actions — only for participants */} {isParticipant && Transfer In Transfer Out } {/* Leave button — only when: not expired, no active bids, no escrow balance */} {onLeave && !auctionExpired && activeBids === 0 && escrowBalance === 0 && committed === 0 && ( {leaving ? 'Leaving...' : 'Leave Auction'} )} ); } // ============================================ // TOURNAMENT // ============================================ if (lifecycleState === 'tournament') { const totalPurchased = myPurchasedItems.reduce((s, i) => s + Number(i.winning_bid), 0); const stillAlive = myPurchasedItems.filter(i => i.status !== 'eliminated').length; return ( Status In Progress Purchased {myPurchasedItems.length} ({stillAlive} alive) Spent {formatCurrency(totalPurchased, market_type)} ); } // ============================================ // COMPLETED // ============================================ const totalPurchased = myPurchasedItems.reduce((s, i) => s + Number(i.winning_bid), 0); return ( Status Completed Purchased {myPurchasedItems.length} Spent {formatCurrency(totalPurchased, market_type)} ); }; const styles = StyleSheet.create({ // Compact container for pending/scheduled container: { borderBottomWidth: 1, paddingTop: 8, paddingHorizontal: 12, paddingBottom: 6, }, cells: { flexDirection: 'row', justifyContent: 'space-between', }, cell: { flexDirection: 'row', alignItems: 'center', }, // Full KPI container for auctioning/tournament/completed auctionContainer: { borderBottomWidth: 1, paddingHorizontal: 12, paddingVertical: 10, }, timerRow: { flexDirection: 'row', alignItems: 'center', justifyContent: 'center', marginBottom: 10, }, potTracker: { borderRadius: 12, borderWidth: 1, padding: 12, marginBottom: 10, }, potHeader: { flexDirection: 'row', alignItems: 'center', marginBottom: 10, }, potRow: { flexDirection: 'row', alignItems: 'center', }, potItem: { flex: 1, alignItems: 'center', }, potDivider: { width: 1, height: 32, }, kpiRow: { flexDirection: 'row', gap: 8, }, kpiCard: { flex: 1, borderRadius: 10, borderWidth: 1, paddingVertical: 10, paddingHorizontal: 8, alignItems: 'center', }, transferRow: { flexDirection: 'row', gap: 8, marginTop: 10, }, transferBtn: { flex: 1, flexDirection: 'row', alignItems: 'center', justifyContent: 'center', height: 36, borderRadius: 8, }, leaveBtn: { flexDirection: 'row', alignItems: 'center', justifyContent: 'center', marginTop: 10, paddingVertical: 8, }, });