import React from 'react'; import { StyleSheet, FlatList, Image } from 'react-native'; import { View, Text, useTheme } from '@bettoredge/styles'; import { Ionicons } from '@expo/vector-icons'; import type { CalcuttaPayoutRuleProps, CalcuttaRoundProps } from '@bettoredge/types'; import { formatCurrency } from '../helpers/formatting'; export interface CalcuttaPayoutPreviewProps { payout_rules: CalcuttaPayoutRuleProps[]; total_pot: number; market_type: string; unclaimed_pot?: number; min_spend_pct?: number; auction_type?: string; rounds?: CalcuttaRoundProps[]; } export const CalcuttaPayoutPreview: React.FC = ({ payout_rules, total_pot, market_type, unclaimed_pot, min_spend_pct, auction_type, rounds, }) => { const { theme } = useTheme(); const isSweepstakes = auction_type === 'sweepstakes'; // Sweepstakes: render prize list per round instead of percentages if (isSweepstakes && rounds) { const prizeRounds = rounds.filter(r => r.prize_description); if (prizeRounds.length === 0) { return ( No prizes defined ); } return ( Prizes {prizeRounds.length} round{prizeRounds.length !== 1 ? 's' : ''} {prizeRounds.map(round => ( {round.prize_image?.url && ( )} {round.round_name} {round.prize_description} ))} ); } const roundRules = payout_rules .filter(r => r.payout_type === 'round') .sort((a, b) => (a.round_number ?? 0) - (b.round_number ?? 0)); const placementRules = payout_rules .filter(r => r.payout_type === 'placement') .sort((a, b) => (a.placement ?? 0) - (b.placement ?? 0)); const totalPct = payout_rules.reduce((sum, r) => sum + r.payout_pct, 0); const renderRule = (rule: CalcuttaPayoutRuleProps) => { const amount = (rule.payout_pct / 100) * total_pot; return ( {rule.description ?? `${rule.payout_type === 'round' ? `Round ${rule.round_number}` : `${rule.placement}${getOrdinal(rule.placement ?? 0)} Place`}`} {rule.payout_type === 'round' ? 'Round Payout' : 'Placement Payout'} {formatCurrency(amount, market_type)} {rule.payout_pct.toFixed(1)}% ); }; return ( {/* Total pot summary */} Total Pot {formatCurrency(total_pot, market_type)} Allocated {totalPct.toFixed(1)}% {/* Min spend rule note */} {min_spend_pct != null && Number(min_spend_pct) > 0 && ( Min spend rule active: {Number(min_spend_pct)}%. If you deposit $300 but only bid $200, the ${((Number(min_spend_pct) / 100) * 300 - 200).toFixed(0)} shortfall is added to the pot. )} {/* Unclaimed rollover notice */} {(unclaimed_pot ?? 0) > 0 && ( {formatCurrency(unclaimed_pot ?? 0, market_type)} rolling forward From unbid teams that advanced. This amount is added to the next round's pool. After the final round, any remaining amount is split among all players based on how much they spent. )} {/* Round-based payouts */} {roundRules.length > 0 && ( <> Round Payouts {roundRules.map(renderRule)} )} {/* Placement-based payouts */} {placementRules.length > 0 && ( <> Placement Payouts {placementRules.map(renderRule)} )} {payout_rules.length === 0 && ( No payout rules defined )} ); }; const getOrdinal = (n: number): string => { const suffixes = ['th', 'st', 'nd', 'rd']; const v = n % 100; return (suffixes[(v - 20) % 10] || suffixes[v] || suffixes[0]); }; const styles = StyleSheet.create({ container: { flex: 1, }, potSummary: { flexDirection: 'row', alignItems: 'center', padding: 14, borderBottomWidth: 1, }, potInfo: { marginLeft: 16, }, sectionHeader: { paddingHorizontal: 12, paddingVertical: 8, }, ruleRow: { flexDirection: 'row', alignItems: 'center', paddingVertical: 10, paddingHorizontal: 12, borderBottomWidth: 1, }, ruleInfo: { flex: 1, }, ruleAmounts: { alignItems: 'flex-end', marginLeft: 10, }, emptyText: { textAlign: 'center', padding: 20, }, rolloverBanner: { flexDirection: 'row', alignItems: 'flex-start', padding: 12, borderBottomWidth: 1, }, });