fix data flow issues
This commit is contained in:
@@ -7,6 +7,7 @@ import Button from '@/components/ui/Button';
|
||||
import Card from '@/components/ui/Card';
|
||||
import { useEffectiveDriverId } from '@/hooks/useEffectiveDriverId';
|
||||
import { useServices } from '@/lib/services/ServiceProvider';
|
||||
import { LeagueStewardingViewModel } from '@/lib/view-models/LeagueStewardingViewModel';
|
||||
import { LeagueRoleUtility } from '@/lib/utilities/LeagueRoleUtility';
|
||||
import {
|
||||
AlertCircle,
|
||||
@@ -27,32 +28,13 @@ import { useEffect, useMemo, useState } from 'react';
|
||||
// Local type definitions to replace core imports
|
||||
type PenaltyType = 'time_penalty' | 'grid_penalty' | 'points_deduction' | 'disqualification' | 'warning' | 'license_points';
|
||||
|
||||
type DriverDTO = {
|
||||
id: string;
|
||||
name: string;
|
||||
avatarUrl?: string;
|
||||
iracingId?: string;
|
||||
rating?: number;
|
||||
};
|
||||
|
||||
interface RaceWithProtests {
|
||||
race: any;
|
||||
pendingProtests: any[];
|
||||
resolvedProtests: any[];
|
||||
penalties: any[];
|
||||
}
|
||||
|
||||
export default function LeagueStewardingPage() {
|
||||
const params = useParams();
|
||||
const leagueId = params.id as string;
|
||||
const currentDriverId = useEffectiveDriverId();
|
||||
const { raceService, protestService, driverService, leagueMembershipService, penaltyService } = useServices();
|
||||
const { leagueStewardingService, leagueMembershipService } = useServices();
|
||||
|
||||
const [races, setRaces] = useState<any[]>([]);
|
||||
const [protestsByRace, setProtestsByRace] = useState<Record<string, any[]>>({});
|
||||
const [penaltiesByRace, setPenaltiesByRace] = useState<Record<string, any[]>>({});
|
||||
const [driversById, setDriversById] = useState<Record<string, DriverDTO>>({});
|
||||
const [allDrivers, setAllDrivers] = useState<DriverDTO[]>([]);
|
||||
const [stewardingData, setStewardingData] = useState<LeagueStewardingViewModel | null>(null);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [isAdmin, setIsAdmin] = useState(false);
|
||||
const [activeTab, setActiveTab] = useState<'pending' | 'history'>('pending');
|
||||
@@ -72,52 +54,13 @@ export default function LeagueStewardingPage() {
|
||||
async function loadData() {
|
||||
setLoading(true);
|
||||
try {
|
||||
// Get all races for this league
|
||||
const leagueRaces = await raceService.findByLeagueId(leagueId);
|
||||
setRaces(leagueRaces);
|
||||
|
||||
// Get protests and penalties for each race
|
||||
const protestsMap: Record<string, any[]> = {};
|
||||
const penaltiesMap: Record<string, any[]> = {};
|
||||
const driverIds = new Set<string>();
|
||||
|
||||
for (const race of leagueRaces) {
|
||||
const raceProtests = await protestService.findByRaceId(race.id);
|
||||
const racePenalties = await penaltyService.findByRaceId(race.id);
|
||||
|
||||
protestsMap[race.id] = raceProtests;
|
||||
penaltiesMap[race.id] = racePenalties;
|
||||
|
||||
// Collect driver IDs
|
||||
raceProtests.forEach((p: any) => {
|
||||
driverIds.add(p.protestingDriverId);
|
||||
driverIds.add(p.accusedDriverId);
|
||||
});
|
||||
racePenalties.forEach((p: any) => {
|
||||
driverIds.add(p.driverId);
|
||||
});
|
||||
}
|
||||
|
||||
setProtestsByRace(protestsMap);
|
||||
setPenaltiesByRace(penaltiesMap);
|
||||
|
||||
// Load driver info
|
||||
const driverEntities = await driverService.findByIds(Array.from(driverIds));
|
||||
const byId: Record<string, any> = {};
|
||||
driverEntities.forEach((driver) => {
|
||||
if (driver) {
|
||||
byId[driver.id] = driver;
|
||||
}
|
||||
});
|
||||
setDriversById(byId);
|
||||
setAllDrivers(Object.values(byId));
|
||||
const data = await leagueStewardingService.getLeagueStewardingData(leagueId);
|
||||
setStewardingData(data);
|
||||
|
||||
// Auto-expand races with pending protests
|
||||
const racesWithPending = new Set<string>();
|
||||
Object.entries(protestsMap).forEach(([raceId, protests]) => {
|
||||
if (protests.some((p: any) => p.status === 'pending' || p.status === 'under_review')) {
|
||||
racesWithPending.add(raceId);
|
||||
}
|
||||
data.pendingRaces.forEach(race => {
|
||||
racesWithPending.add(race.race.id);
|
||||
});
|
||||
setExpandedRaces(racesWithPending);
|
||||
} catch (err) {
|
||||
@@ -130,34 +73,12 @@ export default function LeagueStewardingPage() {
|
||||
if (isAdmin) {
|
||||
loadData();
|
||||
}
|
||||
}, [leagueId, isAdmin, raceService, protestService, driverService, penaltyService]);
|
||||
|
||||
// Compute race data with protest/penalty info
|
||||
const racesWithData = useMemo((): RaceWithProtests[] => {
|
||||
return races.map(race => {
|
||||
const protests = protestsByRace[race.id] || [];
|
||||
const penalties = penaltiesByRace[race.id] || [];
|
||||
return {
|
||||
race,
|
||||
pendingProtests: protests.filter(p => p.status === 'pending' || p.status === 'under_review'),
|
||||
resolvedProtests: protests.filter(p => p.status === 'upheld' || p.status === 'dismissed' || p.status === 'withdrawn'),
|
||||
penalties
|
||||
};
|
||||
}).sort((a, b) => b.race.scheduledAt.getTime() - a.race.scheduledAt.getTime());
|
||||
}, [races, protestsByRace, penaltiesByRace]);
|
||||
}, [leagueId, isAdmin, leagueStewardingService]);
|
||||
|
||||
// Filter races based on active tab
|
||||
const filteredRaces = useMemo(() => {
|
||||
if (activeTab === 'pending') {
|
||||
return racesWithData.filter(r => r.pendingProtests.length > 0);
|
||||
}
|
||||
return racesWithData.filter(r => r.resolvedProtests.length > 0 || r.penalties.length > 0);
|
||||
}, [racesWithData, activeTab]);
|
||||
|
||||
// Stats
|
||||
const totalPending = racesWithData.reduce((sum, r) => sum + r.pendingProtests.length, 0);
|
||||
const totalResolved = racesWithData.reduce((sum, r) => sum + r.resolvedProtests.length, 0);
|
||||
const totalPenalties = racesWithData.reduce((sum, r) => sum + r.penalties.length, 0);
|
||||
return activeTab === 'pending' ? stewardingData?.pendingRaces ?? [] : stewardingData?.historyRaces ?? [];
|
||||
}, [stewardingData, activeTab]);
|
||||
|
||||
const handleAcceptProtest = async (
|
||||
protestId: string,
|
||||
@@ -165,22 +86,23 @@ export default function LeagueStewardingPage() {
|
||||
penaltyValue: number,
|
||||
stewardNotes: string
|
||||
) => {
|
||||
await protestService.reviewProtest({
|
||||
await leagueStewardingService.reviewProtest({
|
||||
protestId,
|
||||
stewardId: currentDriverId,
|
||||
decision: 'uphold',
|
||||
decisionNotes: stewardNotes,
|
||||
});
|
||||
|
||||
// Find the protest
|
||||
// Find the protest to get details for penalty
|
||||
let foundProtest: any | undefined;
|
||||
Object.values(protestsByRace).forEach(protests => {
|
||||
const p = protests.find(pr => pr.id === protestId);
|
||||
if (p) foundProtest = p;
|
||||
stewardingData?.racesWithData.forEach(raceData => {
|
||||
const p = raceData.pendingProtests.find(pr => pr.id === protestId) ||
|
||||
raceData.resolvedProtests.find(pr => pr.id === protestId);
|
||||
if (p) foundProtest = { ...p, raceId: raceData.race.id };
|
||||
});
|
||||
|
||||
if (foundProtest) {
|
||||
await penaltyService.applyPenalty({
|
||||
await leagueStewardingService.applyPenalty({
|
||||
raceId: foundProtest.raceId,
|
||||
driverId: foundProtest.accusedDriverId,
|
||||
stewardId: currentDriverId,
|
||||
@@ -194,7 +116,7 @@ export default function LeagueStewardingPage() {
|
||||
};
|
||||
|
||||
const handleRejectProtest = async (protestId: string, stewardNotes: string) => {
|
||||
await protestService.reviewProtest({
|
||||
await leagueStewardingService.reviewProtest({
|
||||
protestId,
|
||||
stewardId: currentDriverId,
|
||||
decision: 'dismiss',
|
||||
@@ -260,28 +182,28 @@ export default function LeagueStewardingPage() {
|
||||
</div>
|
||||
|
||||
{/* Stats summary */}
|
||||
{!loading && (
|
||||
{!loading && stewardingData && (
|
||||
<div className="grid grid-cols-3 gap-4 mb-6">
|
||||
<div className="rounded-lg bg-iron-gray/50 border border-charcoal-outline p-4">
|
||||
<div className="flex items-center gap-2 text-warning-amber mb-1">
|
||||
<Clock className="w-4 h-4" />
|
||||
<span className="text-xs font-medium uppercase">Pending Review</span>
|
||||
</div>
|
||||
<div className="text-2xl font-bold text-white">{totalPending}</div>
|
||||
<div className="text-2xl font-bold text-white">{stewardingData.totalPending}</div>
|
||||
</div>
|
||||
<div className="rounded-lg bg-iron-gray/50 border border-charcoal-outline p-4">
|
||||
<div className="flex items-center gap-2 text-performance-green mb-1">
|
||||
<CheckCircle className="w-4 h-4" />
|
||||
<span className="text-xs font-medium uppercase">Resolved</span>
|
||||
</div>
|
||||
<div className="text-2xl font-bold text-white">{totalResolved}</div>
|
||||
<div className="text-2xl font-bold text-white">{stewardingData.totalResolved}</div>
|
||||
</div>
|
||||
<div className="rounded-lg bg-iron-gray/50 border border-charcoal-outline p-4">
|
||||
<div className="flex items-center gap-2 text-red-400 mb-1">
|
||||
<Gavel className="w-4 h-4" />
|
||||
<span className="text-xs font-medium uppercase">Penalties</span>
|
||||
</div>
|
||||
<div className="text-2xl font-bold text-white">{totalPenalties}</div>
|
||||
<div className="text-2xl font-bold text-white">{stewardingData.totalPenalties}</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
@@ -298,9 +220,9 @@ export default function LeagueStewardingPage() {
|
||||
}`}
|
||||
>
|
||||
Pending Protests
|
||||
{totalPending > 0 && (
|
||||
{stewardingData && stewardingData.totalPending > 0 && (
|
||||
<span className="ml-2 px-2 py-0.5 text-xs bg-warning-amber/20 text-warning-amber rounded-full">
|
||||
{totalPending}
|
||||
{stewardingData.totalPending}
|
||||
</span>
|
||||
)}
|
||||
</button>
|
||||
@@ -380,8 +302,8 @@ export default function LeagueStewardingPage() {
|
||||
) : (
|
||||
<>
|
||||
{displayProtests.map((protest) => {
|
||||
const protester = driversById[protest.protestingDriverId];
|
||||
const accused = driversById[protest.accusedDriverId];
|
||||
const protester = stewardingData!.driverMap[protest.protestingDriverId];
|
||||
const accused = stewardingData!.driverMap[protest.accusedDriverId];
|
||||
const daysSinceFiled = Math.floor((Date.now() - new Date(protest.filedAt).getTime()) / (1000 * 60 * 60 * 24));
|
||||
const isUrgent = daysSinceFiled > 2 && (protest.status === 'pending' || protest.status === 'under_review');
|
||||
|
||||
@@ -443,7 +365,7 @@ export default function LeagueStewardingPage() {
|
||||
})}
|
||||
|
||||
{activeTab === 'history' && penalties.map((penalty) => {
|
||||
const driver = driversById[penalty.driverId];
|
||||
const driver = stewardingData!.driverMap[penalty.driverId];
|
||||
return (
|
||||
<div
|
||||
key={penalty.id}
|
||||
@@ -500,12 +422,12 @@ export default function LeagueStewardingPage() {
|
||||
/>
|
||||
)}
|
||||
|
||||
{showQuickPenaltyModal && (
|
||||
{showQuickPenaltyModal && stewardingData && (
|
||||
<QuickPenaltyModal
|
||||
drivers={allDrivers}
|
||||
drivers={stewardingData.allDrivers}
|
||||
onClose={() => setShowQuickPenaltyModal(false)}
|
||||
adminId={currentDriverId}
|
||||
races={races.map(r => ({ id: r.id, track: r.track, scheduledAt: r.scheduledAt }))}
|
||||
races={stewardingData.racesWithData.map(r => ({ id: r.race.id, track: r.race.track, scheduledAt: r.race.scheduledAt }))}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -4,11 +4,13 @@ import { useState, useEffect } from 'react';
|
||||
import { useParams } from 'next/navigation';
|
||||
import Card from '@/components/ui/Card';
|
||||
import Button from '@/components/ui/Button';
|
||||
import {
|
||||
Wallet,
|
||||
DollarSign,
|
||||
ArrowUpRight,
|
||||
ArrowDownLeft,
|
||||
import { useServices } from '@/lib/services/ServiceProvider';
|
||||
import { LeagueWalletViewModel } from '@/lib/view-models/LeagueWalletViewModel';
|
||||
import {
|
||||
Wallet,
|
||||
DollarSign,
|
||||
ArrowUpRight,
|
||||
ArrowDownLeft,
|
||||
Clock,
|
||||
AlertTriangle,
|
||||
CheckCircle,
|
||||
@@ -19,102 +21,9 @@ import {
|
||||
Calendar
|
||||
} from 'lucide-react';
|
||||
|
||||
interface Transaction {
|
||||
id: string;
|
||||
type: 'sponsorship' | 'membership' | 'withdrawal' | 'prize';
|
||||
description: string;
|
||||
amount: number;
|
||||
fee: number;
|
||||
netAmount: number;
|
||||
date: Date;
|
||||
status: 'completed' | 'pending' | 'failed';
|
||||
reference?: string;
|
||||
}
|
||||
|
||||
interface WalletData {
|
||||
balance: number;
|
||||
currency: string;
|
||||
totalRevenue: number;
|
||||
totalFees: number;
|
||||
totalWithdrawals: number;
|
||||
pendingPayouts: number;
|
||||
transactions: Transaction[];
|
||||
canWithdraw: boolean;
|
||||
withdrawalBlockReason?: string;
|
||||
}
|
||||
|
||||
// Mock data for demonstration
|
||||
const MOCK_WALLET: WalletData = {
|
||||
balance: 2450.00,
|
||||
currency: 'USD',
|
||||
totalRevenue: 3200.00,
|
||||
totalFees: 320.00,
|
||||
totalWithdrawals: 430.00,
|
||||
pendingPayouts: 150.00,
|
||||
canWithdraw: false,
|
||||
withdrawalBlockReason: 'Season 2 is still active. Withdrawals are available after season completion.',
|
||||
transactions: [
|
||||
{
|
||||
id: 'txn-1',
|
||||
type: 'sponsorship',
|
||||
description: 'Main Sponsor - TechCorp',
|
||||
amount: 1200.00,
|
||||
fee: 120.00,
|
||||
netAmount: 1080.00,
|
||||
date: new Date('2025-12-01'),
|
||||
status: 'completed',
|
||||
reference: 'SP-2025-001',
|
||||
},
|
||||
{
|
||||
id: 'txn-2',
|
||||
type: 'sponsorship',
|
||||
description: 'Secondary Sponsor - RaceFuel',
|
||||
amount: 400.00,
|
||||
fee: 40.00,
|
||||
netAmount: 360.00,
|
||||
date: new Date('2025-12-01'),
|
||||
status: 'completed',
|
||||
reference: 'SP-2025-002',
|
||||
},
|
||||
{
|
||||
id: 'txn-3',
|
||||
type: 'membership',
|
||||
description: 'Season Fee - 32 drivers',
|
||||
amount: 1600.00,
|
||||
fee: 160.00,
|
||||
netAmount: 1440.00,
|
||||
date: new Date('2025-11-15'),
|
||||
status: 'completed',
|
||||
reference: 'MF-2025-032',
|
||||
},
|
||||
{
|
||||
id: 'txn-4',
|
||||
type: 'withdrawal',
|
||||
description: 'Bank Transfer - Season 1 Payout',
|
||||
amount: -430.00,
|
||||
fee: 0,
|
||||
netAmount: -430.00,
|
||||
date: new Date('2025-10-30'),
|
||||
status: 'completed',
|
||||
reference: 'WD-2025-001',
|
||||
},
|
||||
{
|
||||
id: 'txn-5',
|
||||
type: 'prize',
|
||||
description: 'Championship Prize Pool (reserved)',
|
||||
amount: -150.00,
|
||||
fee: 0,
|
||||
netAmount: -150.00,
|
||||
date: new Date('2025-12-05'),
|
||||
status: 'pending',
|
||||
reference: 'PZ-2025-001',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
function TransactionRow({ transaction }: { transaction: Transaction }) {
|
||||
function TransactionRow({ transaction }: { transaction: any }) {
|
||||
const isIncoming = transaction.amount > 0;
|
||||
|
||||
|
||||
const typeIcons = {
|
||||
sponsorship: DollarSign,
|
||||
membership: CreditCard,
|
||||
@@ -158,13 +67,13 @@ function TransactionRow({ transaction }: { transaction: Transaction }) {
|
||||
</>
|
||||
)}
|
||||
<span>•</span>
|
||||
<span>{transaction.date.toLocaleDateString()}</span>
|
||||
<span>{transaction.formattedDate}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="text-right">
|
||||
<div className={`font-semibold ${isIncoming ? 'text-performance-green' : 'text-white'}`}>
|
||||
{isIncoming ? '+' : ''}{transaction.amount < 0 ? '-' : ''}${Math.abs(transaction.amount).toFixed(2)}
|
||||
{transaction.formattedAmount}
|
||||
</div>
|
||||
{transaction.fee > 0 && (
|
||||
<div className="text-xs text-gray-500">
|
||||
@@ -178,36 +87,48 @@ function TransactionRow({ transaction }: { transaction: Transaction }) {
|
||||
|
||||
export default function LeagueWalletPage() {
|
||||
const params = useParams();
|
||||
const [wallet, setWallet] = useState<WalletData>(MOCK_WALLET);
|
||||
const { leagueWalletService } = useServices();
|
||||
const [wallet, setWallet] = useState<LeagueWalletViewModel | null>(null);
|
||||
const [withdrawAmount, setWithdrawAmount] = useState('');
|
||||
const [showWithdrawModal, setShowWithdrawModal] = useState(false);
|
||||
const [processing, setProcessing] = useState(false);
|
||||
const [filterType, setFilterType] = useState<'all' | 'sponsorship' | 'membership' | 'withdrawal' | 'prize'>('all');
|
||||
|
||||
const filteredTransactions = wallet.transactions.filter(
|
||||
t => filterType === 'all' || t.type === filterType
|
||||
);
|
||||
useEffect(() => {
|
||||
const loadWallet = async () => {
|
||||
if (params.id) {
|
||||
try {
|
||||
const walletData = await leagueWalletService.getWalletForLeague(params.id as string);
|
||||
setWallet(walletData);
|
||||
} catch (error) {
|
||||
console.error('Failed to load wallet:', error);
|
||||
}
|
||||
}
|
||||
};
|
||||
loadWallet();
|
||||
}, [params.id, leagueWalletService]);
|
||||
|
||||
if (!wallet) {
|
||||
return <div>Loading...</div>;
|
||||
}
|
||||
|
||||
const filteredTransactions = wallet.getFilteredTransactions(filterType);
|
||||
|
||||
const handleWithdraw = async () => {
|
||||
if (!withdrawAmount || parseFloat(withdrawAmount) <= 0) return;
|
||||
|
||||
|
||||
setProcessing(true);
|
||||
try {
|
||||
const response = await fetch(`/api/wallets/${params.id}/withdraw`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
amount: parseFloat(withdrawAmount),
|
||||
currency: wallet.currency,
|
||||
seasonId: 'season-2', // Current active season
|
||||
destinationAccount: 'bank-account-***1234',
|
||||
}),
|
||||
});
|
||||
const result = await leagueWalletService.withdraw(
|
||||
params.id as string,
|
||||
parseFloat(withdrawAmount),
|
||||
wallet.currency,
|
||||
'season-2', // Current active season
|
||||
'bank-account-***1234'
|
||||
);
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (!response.ok) {
|
||||
alert(result.reason || result.error || 'Withdrawal failed');
|
||||
if (!result.success) {
|
||||
alert(result.message || 'Withdrawal failed');
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -215,6 +136,8 @@ export default function LeagueWalletPage() {
|
||||
setShowWithdrawModal(false);
|
||||
setWithdrawAmount('');
|
||||
// Refresh wallet data
|
||||
const updatedWallet = await leagueWalletService.getWalletForLeague(params.id as string);
|
||||
setWallet(updatedWallet);
|
||||
} catch (err) {
|
||||
console.error('Withdrawal error:', err);
|
||||
alert('Failed to process withdrawal');
|
||||
@@ -236,7 +159,7 @@ export default function LeagueWalletPage() {
|
||||
<Download className="w-4 h-4 mr-2" />
|
||||
Export
|
||||
</Button>
|
||||
<Button
|
||||
<Button
|
||||
variant="primary"
|
||||
onClick={() => setShowWithdrawModal(true)}
|
||||
disabled={!wallet.canWithdraw}
|
||||
@@ -268,7 +191,7 @@ export default function LeagueWalletPage() {
|
||||
<Wallet className="w-6 h-6 text-performance-green" />
|
||||
</div>
|
||||
<div>
|
||||
<div className="text-2xl font-bold text-white">${wallet.balance.toFixed(2)}</div>
|
||||
<div className="text-2xl font-bold text-white">{wallet.formattedBalance}</div>
|
||||
<div className="text-sm text-gray-400">Available Balance</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -280,7 +203,7 @@ export default function LeagueWalletPage() {
|
||||
<TrendingUp className="w-6 h-6 text-primary-blue" />
|
||||
</div>
|
||||
<div>
|
||||
<div className="text-2xl font-bold text-white">${wallet.totalRevenue.toFixed(2)}</div>
|
||||
<div className="text-2xl font-bold text-white">{wallet.formattedTotalRevenue}</div>
|
||||
<div className="text-sm text-gray-400">Total Revenue</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -292,7 +215,7 @@ export default function LeagueWalletPage() {
|
||||
<DollarSign className="w-6 h-6 text-warning-amber" />
|
||||
</div>
|
||||
<div>
|
||||
<div className="text-2xl font-bold text-white">${wallet.totalFees.toFixed(2)}</div>
|
||||
<div className="text-2xl font-bold text-white">{wallet.formattedTotalFees}</div>
|
||||
<div className="text-sm text-gray-400">Platform Fees (10%)</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -304,7 +227,7 @@ export default function LeagueWalletPage() {
|
||||
<Clock className="w-6 h-6 text-purple-400" />
|
||||
</div>
|
||||
<div>
|
||||
<div className="text-2xl font-bold text-white">${wallet.pendingPayouts.toFixed(2)}</div>
|
||||
<div className="text-2xl font-bold text-white">{wallet.formattedPendingPayouts}</div>
|
||||
<div className="text-sm text-gray-400">Pending Payouts</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -396,7 +319,7 @@ export default function LeagueWalletPage() {
|
||||
<div className="p-3 rounded-lg bg-iron-gray/50 border border-charcoal-outline">
|
||||
<div className="flex items-center justify-between mb-1">
|
||||
<span className="text-sm font-medium text-white">Available for Withdrawal</span>
|
||||
<span className="text-sm font-medium text-performance-green">${wallet.balance.toFixed(2)}</span>
|
||||
<span className="text-sm font-medium text-performance-green">{wallet.formattedBalance}</span>
|
||||
</div>
|
||||
<p className="text-xs text-gray-500">
|
||||
Available after Season 2 ends (estimated: Jan 15, 2026)
|
||||
@@ -434,7 +357,7 @@ export default function LeagueWalletPage() {
|
||||
/>
|
||||
</div>
|
||||
<p className="text-xs text-gray-500 mt-1">
|
||||
Available: ${wallet.balance.toFixed(2)}
|
||||
Available: {wallet.formattedBalance}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user