feat: add Solana USDT/USDC support and refine admin payouts UI

This commit is contained in:
mstfyldz
2026-03-13 05:17:04 +03:00
parent 5f0df83686
commit 641498957c
16 changed files with 1335 additions and 120 deletions

View File

@@ -0,0 +1,131 @@
'use client';
import React, { useState, useEffect } from 'react';
import { Wallet, RefreshCw, Zap, TrendingUp, AlertCircle } from 'lucide-react';
export default function PlatformTreasuryWidget() {
const [treasuryData, setTreasuryData] = useState<any>(null);
const [isLoading, setIsLoading] = useState(true);
const [lastUpdated, setLastUpdated] = useState<Date | null>(null);
const fetchTreasury = async () => {
setIsLoading(true);
try {
const res = await fetch('/api/admin/treasury/balances');
const data = await res.json();
if (res.ok) {
setTreasuryData(data.balances);
setLastUpdated(new Date());
}
} catch (e) {
console.error('[Treasury Widget] Error:', e);
} finally {
setIsLoading(false);
}
};
useEffect(() => {
fetchTreasury();
}, []);
const networks = [
{ id: 'SOLANA', color: 'text-emerald-500', bg: 'bg-emerald-50', icon: '🟢' },
{ id: 'POLYGON', color: 'text-purple-500', bg: 'bg-purple-50', icon: '🟣' },
{ id: 'TRON', color: 'text-red-500', bg: 'bg-red-50', icon: '🔴' },
{ id: 'BSC', color: 'text-yellow-500', bg: 'bg-yellow-50', icon: '🟡' },
{ id: 'ETH', color: 'text-blue-500', bg: 'bg-blue-50', icon: '🔵' },
{ id: 'BITCOIN', color: 'text-orange-500', bg: 'bg-orange-50', icon: '🟠' }
];
return (
<div className="bg-white rounded-[40px] border border-gray-100 shadow-sm overflow-hidden">
<div className="p-8 border-b border-gray-50 flex justify-between items-center">
<div className="flex items-center gap-4">
<div className="w-12 h-12 bg-gray-900 rounded-2xl flex items-center justify-center text-white shadow-xl">
<Wallet size={24} />
</div>
<div>
<h2 className="text-xl font-black text-gray-900 leading-none">Platform Hazinesi</h2>
<p className="text-[10px] text-gray-400 font-bold uppercase tracking-widest mt-2 flex items-center gap-1.5">
<Zap size={10} className="text-emerald-500 fill-emerald-500" />
Sistem Genelindeki On-Chain Likidite
</p>
</div>
</div>
<div className="flex items-center gap-4">
{lastUpdated && (
<span className="text-[9px] font-black text-gray-300 uppercase tracking-tighter">
Son Güncelleme: {lastUpdated.toLocaleTimeString('tr-TR')}
</span>
)}
<button
onClick={fetchTreasury}
disabled={isLoading}
className={`p-3 rounded-2xl border border-gray-100 text-gray-400 hover:text-gray-900 hover:border-gray-300 transition-all ${isLoading ? 'animate-spin border-transparent text-blue-600' : ''}`}
>
<RefreshCw size={20} />
</button>
</div>
</div>
<div className="p-8">
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-6 gap-6">
{networks.map((net) => {
const data = treasuryData?.[net.id];
const nativeSymbol = data?.nativeSymbol || net.id;
const balance = data?.native || '0.00';
const tokenList = data?.tokens ? Object.entries(data.tokens) : [];
return (
<div key={net.id} className="group relative">
<div className={`p-6 rounded-[32px] border border-gray-100 shadow-sm transition-all duration-300 hover:shadow-xl hover:-translate-y-1 ${net.bg}/20`}>
<div className="flex items-center justify-between mb-4">
<span className="text-2xl drop-shadow-sm">{net.icon}</span>
<span className={`text-[10px] font-black uppercase tracking-widest px-2 py-0.5 rounded-lg bg-white/80 border ${net.color}`}>
{net.id}
</span>
</div>
<div className="space-y-1">
<p className="text-xs font-bold text-gray-400 uppercase tracking-tighter leading-none">Ana Varlık</p>
<div className="flex items-baseline gap-1.5 overflow-hidden">
<h3 className={`text-xl font-black tabular-nums transition-all ${isLoading ? 'blur-sm' : ''} ${net.color}`}>
{balance}
</h3>
<span className="text-[10px] font-black text-gray-400 uppercase">{nativeSymbol}</span>
</div>
</div>
{tokenList.length > 0 && (
<div className="mt-4 pt-4 border-t border-gray-50 space-y-2">
{tokenList.map(([symbol, bal]) => (
<div key={symbol as string} className="flex justify-between items-center text-[10px] font-bold">
<span className="text-gray-400 uppercase">{symbol as string}</span>
<span className="text-gray-900 tabular-nums">{bal as string}</span>
</div>
))}
</div>
)}
{balance === "Error" && (
<div className="mt-2 text-[8px] font-black text-red-500 uppercase flex items-center gap-1">
<AlertCircle size={10} /> Bağlantı Hatası
</div>
)}
</div>
</div>
);
})}
</div>
<div className="mt-8 p-4 bg-blue-50/50 rounded-2xl border border-blue-100/50 flex items-center gap-3">
<TrendingUp className="text-blue-600" size={18} />
<p className="text-[10px] font-bold text-blue-800 leading-relaxed uppercase tracking-tight">
Yukarıdaki bakiyeler platformun operasyonel cüzdanlarından (Platform Treasury) anlık olarak çekilir. Ödemeler bu likidite üzerinden karşılanmaktadır.
</p>
</div>
</div>
</div>
);
}