import React, { useMemo, useState } from 'react'; import { StyleSheet, TouchableOpacity, FlatList, Image } from 'react-native'; import { View, Text, useTheme } from '@bettoredge/styles'; import { Ionicons } from '@expo/vector-icons'; import type { CalcuttaAuctionItemProps, CalcuttaBidProps, CalcuttaEscrowProps, CalcuttaItemResultProps, CalcuttaRoundProps } from '@bettoredge/types'; import type { ItemImageMap } from '../../hooks/useCalcuttaItemImages'; import type { CalcuttaLifecycleState } from '../../helpers/lifecycleState'; import { formatCurrency, getBidStatusColor, getStatusLabel } from '../../helpers/formatting'; interface SealedBidMyBidsTabProps { items: CalcuttaAuctionItemProps[]; my_bids: CalcuttaBidProps[]; escrow?: CalcuttaEscrowProps; market_type: string; player_id?: string; lifecycleState: CalcuttaLifecycleState; itemImages?: ItemImageMap; item_results?: CalcuttaItemResultProps[]; rounds?: CalcuttaRoundProps[]; onCancelBid: (calcutta_bid_id: string) => void; onUpdateBid: (calcutta_auction_item_id: string) => void; cancelLoading: boolean; auctionExpired?: boolean; listHeader?: React.ReactNode; } interface BidRow { bid: CalcuttaBidProps; item?: CalcuttaAuctionItemProps; } export const SealedBidMyBidsTab: React.FC = ({ items, my_bids, escrow, market_type, player_id, lifecycleState, itemImages, item_results = [], rounds = [], onCancelBid, onUpdateBid, cancelLoading, auctionExpired, listHeader, }) => { const { theme } = useTheme(); const [expandedItemId, setExpandedItemId] = useState(null); const isPostAuction = lifecycleState === 'tournament' || lifecycleState === 'completed'; const isPreAuction = lifecycleState === 'pending' || lifecycleState === 'scheduled'; // All items I won at auction — includes sold (active) AND eliminated const myItems = useMemo( () => items.filter(i => i.winning_player_id === player_id), [items, player_id], ); // For backward compat / badge counts — only active (non-eliminated) items const wonItems = useMemo( () => myItems.filter(i => i.status === 'sold'), [myItems], ); const totalSpent = useMemo( () => myItems.reduce((s, i) => s + Number(i.winning_bid), 0), [myItems], ); const activeBids = useMemo( () => my_bids.filter(b => b.bid_status === 'active'), [my_bids], ); const rows: BidRow[] = useMemo( () => activeBids.map(bid => ({ bid, item: items.find(i => i.calcutta_auction_item_id === bid.calcutta_auction_item_id), })), [activeBids, items], ); const totalCommitted = useMemo( () => activeBids.reduce((sum, b) => sum + Number(b.bid_amount), 0), [activeBids], ); const budgetRemaining = escrow ? Number(escrow.escrow_balance) : 0; // Build per-item result map for tournament/completed const itemResultMap = useMemo(() => { const map: Record = {}; for (const r of item_results) { const key = r.calcutta_auction_item_id; if (!map[key]) map[key] = []; map[key].push(r); } return map; }, [item_results]); // Round name lookup const roundNameMap = useMemo(() => { const map: Record = {}; for (const r of rounds) map[r.round_number] = r.round_name; return map; }, [rounds]); // ============================================ // PENDING / SCHEDULED — Empty state // ============================================ if (isPreAuction) { return ( <>{listHeader} Bidding hasn't started yet You'll be able to place bids once the auction begins ); } // ============================================ // TOURNAMENT / COMPLETED — "My Items" ownership view with round results // ============================================ if (isPostAuction) { if (myItems.length === 0) { return ( <>{listHeader} No items won You didn't win any items in this auction ); } const totalEarned = myItems.reduce((s, i) => { const results = itemResultMap[i.calcutta_auction_item_id] || []; return s + results.reduce((rs, r) => rs + Number(r.payout_earned || 0), 0); }, 0); const totalROI = totalEarned - totalSpent; return ( i.calcutta_auction_item_id} contentContainerStyle={styles.list} ListHeaderComponent={ <>{listHeader} = 0 ? theme.colors.status.successSubtle : theme.colors.status.error + '08', borderColor: totalROI >= 0 ? theme.colors.status.success + '40' : theme.colors.status.error + '30', }]}> Items {myItems.length} Spent {formatCurrency(totalSpent, market_type)} Earned {formatCurrency(totalEarned, market_type)} {/* ROI banner */} = 0 ? theme.colors.status.successSubtle : theme.colors.status.error + '10', }]}> = 0 ? theme.colors.status.success : theme.colors.status.error }}> ROI: {totalROI >= 0 ? '+' : ''}{formatCurrency(totalROI, market_type)} Your Items } renderItem={({ item }) => { const results = itemResultMap[item.calcutta_auction_item_id] || []; const totalPayout = results.reduce((s, r) => s + Number(r.payout_earned || 0), 0); const itemROI = totalPayout - Number(item.winning_bid); const isEliminated = item.status === 'eliminated'; const isExpanded = expandedItemId === item.calcutta_auction_item_id; return ( setExpandedItemId(isExpanded ? null : item.calcutta_auction_item_id)} style={[styles.ownedCard, { backgroundColor: theme.colors.surface.elevated, borderColor: isEliminated ? theme.colors.status.error + '30' : itemROI > 0 ? theme.colors.status.success + '40' : theme.colors.border.subtle, opacity: isEliminated ? 0.8 : 1, }]} > {(itemImages?.[item.item_id]?.url || item.item_image?.url) ? ( ) : isEliminated ? ( ) : ( )} {item.item_name} {isEliminated && ( ELIMINATED )} {item.seed != null && ( Seed #{item.seed} )} ROI 0 ? theme.colors.status.success : itemROI < 0 ? theme.colors.status.error : theme.colors.text.primary, }}> {itemROI >= 0 ? '+' : ''}{formatCurrency(itemROI, market_type)} {/* Expanded: cost + earnings + round progression */} {isExpanded && ( Paid at auction {formatCurrency(item.winning_bid, market_type)} {results .sort((a, b) => (a.round_number ?? 0) - (b.round_number ?? 0)) .map(r => { const isAdvanced = r.result === 'advanced' || r.result === 'won'; const rn = r.round_number ?? 0; const roundName = roundNameMap[rn] || `Round ${rn}`; return ( {roundName} {getStatusLabel(r.result)} {Number(r.payout_earned) > 0 && ( +{formatCurrency(r.payout_earned, market_type)} )} ); })} {results.length === 0 && ( No round results yet )} )} ); }} /> ); } // ============================================ // AUCTIONING — "My Bids" bidding view // ============================================ if (rows.length === 0) { return ( <>{listHeader} No bids yet Browse the Items tab to start bidding ); } return ( r.bid.calcutta_bid_id} contentContainerStyle={styles.list} ListHeaderComponent={ <>{listHeader} Total Bids {activeBids.length} Committed {formatCurrency(totalCommitted, market_type)} Remaining {formatCurrency(budgetRemaining, market_type)} } renderItem={({ item: row }) => ( {row.item?.item_name ?? 'Unknown Item'} {getStatusLabel(row.bid.bid_status)} {formatCurrency(row.bid.bid_amount, market_type)} {/* Actions — only when auctioning AND timer hasn't expired */} {!auctionExpired ? ( onUpdateBid(row.bid.calcutta_auction_item_id)} activeOpacity={0.7} > Update onCancelBid(row.bid.calcutta_bid_id)} disabled={cancelLoading} activeOpacity={0.7} > Cancel ) : ( Auction ended — resolving results... )} )} /> ); }; const styles = StyleSheet.create({ container: { flex: 1, }, emptyContainer: { flex: 1, alignItems: 'center', justifyContent: 'center', padding: 40, }, summary: { flexDirection: 'row', margin: 12, borderRadius: 10, borderWidth: 1, overflow: 'hidden', }, summaryItem: { flex: 1, alignItems: 'center', paddingVertical: 12, }, roiBanner: { marginHorizontal: 12, marginTop: 8, paddingVertical: 8, borderRadius: 8, alignItems: 'center', }, sectionLabel: { paddingHorizontal: 16, paddingBottom: 8, }, list: { paddingHorizontal: 12, paddingBottom: 40, }, ownedCard: { borderWidth: 1, borderRadius: 10, marginBottom: 8, overflow: 'hidden', }, ownedRow: { flexDirection: 'row', alignItems: 'center', padding: 12, }, ownedIcon: { width: 40, height: 40, borderRadius: 20, alignItems: 'center', justifyContent: 'center', marginRight: 12, }, ownedItemImage: { width: 40, height: 40, borderRadius: 20, }, resultsExpanded: { borderTopWidth: 1, paddingHorizontal: 12, paddingVertical: 6, }, resultRow: { flexDirection: 'row', alignItems: 'center', paddingVertical: 4, }, bidCard: { borderWidth: 1, borderRadius: 10, padding: 12, marginBottom: 8, }, bidRow: { flexDirection: 'row', alignItems: 'center', }, actions: { flexDirection: 'row', marginTop: 10, }, actionBtn: { flexDirection: 'row', alignItems: 'center', paddingHorizontal: 12, paddingVertical: 6, borderRadius: 6, borderWidth: 1, }, expiredNotice: { flexDirection: 'row', alignItems: 'center', marginTop: 10, paddingHorizontal: 10, paddingVertical: 8, borderRadius: 6, }, });