fix data flow issues

This commit is contained in:
2025-12-19 21:58:03 +01:00
parent 94fc538f44
commit ec177a75ce
37 changed files with 1336 additions and 534 deletions

View File

@@ -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>