import React, { useMemo } from 'react'; import { StyleSheet, FlatList, Image } from 'react-native'; import { View, Text, useTheme } from '@bettoredge/styles'; import { Ionicons } from '@expo/vector-icons'; import type { CalcuttaParticipantProps, PublicPlayerProps } from '@bettoredge/types'; import type { CalcuttaPresence } from '../../hooks/useCalcuttaSocket'; import type { CalcuttaLifecycleState } from '../../helpers/lifecycleState'; import { formatCurrency } from '../../helpers/formatting'; import { showResults } from '../../helpers/lifecycleState'; interface SealedBidPlayersTabProps { participants: CalcuttaParticipantProps[]; players: Record; player_id?: string; presence: CalcuttaPresence; market_type: string; lifecycleState: CalcuttaLifecycleState; socketConnected?: boolean; listHeader?: React.ReactNode; } export const SealedBidPlayersTab: React.FC = ({ participants, players, player_id, presence, market_type, lifecycleState, socketConnected, listHeader, }) => { const { theme } = useTheme(); const isResultsPhase = showResults(lifecycleState); const showOnlineStatus = socketConnected && !isResultsPhase; const onlineIds = useMemo( () => new Set(presence.players.map(p => p.player_id)), [presence.players], ); const onlineCount = useMemo( () => participants.filter(p => onlineIds.has(p.player_id)).length, [participants, onlineIds], ); // Sort by rank/winnings in results phase const sortedParticipants = useMemo(() => { if (!isResultsPhase) return participants; return [...participants].sort((a, b) => { if (a.place && b.place) return a.place - b.place; if (a.place) return -1; if (b.place) return 1; return (b.total_winnings || 0) - (a.total_winnings || 0); }); }, [participants, isResultsPhase]); if (participants.length === 0) { return ( <>{listHeader} No players yet ); } return ( p.calcutta_participant_id} contentContainerStyle={styles.list} ListHeaderComponent={ <>{listHeader} {showOnlineStatus ? `${onlineCount} of ${participants.length} player${participants.length !== 1 ? 's' : ''} online` : `${participants.length} player${participants.length !== 1 ? 's' : ''}` } } renderItem={({ item: participant, index }) => { const player = players[participant.player_id]; const isOnline = onlineIds.has(participant.player_id); const isMe = participant.player_id === player_id; const username = player?.username || player?.show_name || `Player ${participant.player_id.slice(0, 6)}`; const profilePic = player?.profile_pic; return ( {/* Rank in results phase */} {isResultsPhase && ( {(participant.place ?? index + 1) <= 3 ? ( ) : ( {participant.place ?? index + 1} )} )} {/* Avatar */} {profilePic ? ( ) : ( {username.charAt(0).toUpperCase()} )} {showOnlineStatus && isOnline && ( )} {/* Name */} {username} {isMe && ( YOU )} {isResultsPhase && ( {participant.items_owned > 0 ? `${participant.items_owned} item${participant.items_owned !== 1 ? 's' : ''} ยท ${formatCurrency(participant.total_spent, market_type)} spent` : 'No items'} )} {/* Winnings in results phase */} {isResultsPhase && participant.total_winnings > 0 && ( Won {formatCurrency(participant.total_winnings, market_type)} )} ); }} /> ); }; const styles = StyleSheet.create({ container: { flex: 1, }, emptyContainer: { flex: 1, alignItems: 'center', justifyContent: 'center', padding: 40, }, headerRow: { paddingHorizontal: 16, paddingVertical: 10, }, list: { paddingBottom: 40, }, rankCol: { width: 28, alignItems: 'center', marginRight: 4, }, playerRow: { flexDirection: 'row', alignItems: 'center', paddingHorizontal: 16, paddingVertical: 10, borderBottomWidth: 1, }, avatarWrap: { marginRight: 12, position: 'relative', }, avatar: { width: 40, height: 40, borderRadius: 20, alignItems: 'center', justifyContent: 'center', overflow: 'hidden', }, onlineDot: { position: 'absolute', bottom: 0, right: 0, width: 12, height: 12, borderRadius: 6, borderWidth: 2, }, youBadge: { paddingHorizontal: 6, paddingVertical: 2, borderRadius: 6, marginLeft: 6, }, });