feat: add Solana USDT/USDC support and refine admin payouts UI
This commit is contained in:
131
components/admin/PlatformTreasuryWidget.tsx
Normal file
131
components/admin/PlatformTreasuryWidget.tsx
Normal 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>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user