Files
Pay2Gateway/app/admin/merchants/page.tsx

674 lines
43 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
'use client';
import React, { useState, useEffect } from 'react';
import Link from 'next/link';
import {
Plus, Search, Building2, Copy, Check, Pencil, Trash2,
ExternalLink, Globe, LayoutGrid, List, AlertCircle, X,
DollarSign, Wallet, ArrowRight, ShieldCheck, Loader2,
Coins, History
} from 'lucide-react';
export default function MerchantsPage() {
const [merchants, setMerchants] = useState<any[]>([]);
const [isLoading, setIsLoading] = useState(true);
const [treasuryData, setTreasuryData] = useState<any>(null);
const [isLoadingTreasury, setIsLoadingTreasury] = useState(true);
const [copiedId, setCopiedId] = useState<string | null>(null);
const [showEditModal, setShowEditModal] = useState(false);
const [showPayoutModal, setShowPayoutModal] = useState(false);
const [selectedMerchant, setSelectedMerchant] = useState<any>(null);
const [payoutAmount, setPayoutAmount] = useState<string>('');
const [payoutNetwork, setPayoutNetwork] = useState<string>('POLYGON');
const [payoutCurrency, setPayoutCurrency] = useState<string>('USDT');
const [merchantBalances, setMerchantBalances] = useState<any[]>([]);
const [merchantFeePercent, setMerchantFeePercent] = useState<number>(1);
const [isSubmitting, setIsSubmitting] = useState(false);
const [editForm, setEditForm] = useState({
name: '',
webhook_url: '',
fee_percent: '',
payout_address: '',
payout_addresses: { EVM: '', SOLANA: '', TRON: '', BITCOIN: '' } as Record<string, string>
});
const [isUpdating, setIsUpdating] = useState(false);
useEffect(() => {
fetchMerchants();
fetchTreasury();
}, []);
const fetchTreasury = async () => {
setIsLoadingTreasury(true);
try {
const res = await fetch('/api/admin/treasury/balances');
const data = await res.json();
if (res.ok) setTreasuryData(data.balances);
} catch (e) {
console.error(e);
} finally {
setIsLoadingTreasury(false);
}
};
const fetchMerchants = async () => {
setIsLoading(true);
try {
const response = await fetch('/api/merchants');
const data = await response.json();
if (!response.ok) throw new Error(data.error);
setMerchants(data);
} catch (err) {
console.error('Fetch error:', err);
} finally {
setIsLoading(false);
}
};
const copyToClipboard = (text: string, id: string) => {
navigator.clipboard.writeText(text);
setCopiedId(id);
setTimeout(() => setCopiedId(null), 2000);
};
const handleEditClick = (merchant: any) => {
setSelectedMerchant(merchant);
setEditForm({
name: merchant.name,
webhook_url: merchant.webhook_url || '',
fee_percent: merchant.fee_percent?.toString() || '1.0',
payout_address: merchant.payout_address || '',
payout_addresses: merchant.payout_addresses || { EVM: '', SOLANA: '', TRON: '', BITCOIN: '' }
});
setShowEditModal(true);
};
const handlePayoutClick = async (merchant: any) => {
setSelectedMerchant(merchant);
setPayoutAmount('');
setShowPayoutModal(true);
// Fetch merchant's per-network balances
try {
const res = await fetch(`/api/merchants/${merchant.id}/balances`);
const data = await res.json();
setMerchantBalances(data.balances || []);
setMerchantFeePercent(data.feePercent || 1);
} catch (e) {
setMerchantBalances([]);
}
};
const handleUpdateMerchant = async (e: React.FormEvent) => {
e.preventDefault();
setIsUpdating(true);
try {
const response = await fetch(`/api/merchants/${selectedMerchant.id}`, {
method: 'PATCH',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
name: editForm.name,
webhook_url: editForm.webhook_url,
fee_percent: parseFloat(editForm.fee_percent),
payout_address: editForm.payout_address,
payout_addresses: editForm.payout_addresses
})
});
if (!response.ok) throw new Error('Güncelleme başarısız.');
await fetchMerchants();
setShowEditModal(false);
setSelectedMerchant(null);
} catch (err: any) {
alert(err.message);
} finally {
setIsUpdating(false);
}
};
const handleDeleteMerchant = async (id: string) => {
if (!confirm('Bu firmayı silmek istediğinize emin misiniz? Bu işlem geri alınamaz.')) return;
try {
const response = await fetch(`/api/merchants/${id}`, {
method: 'DELETE'
});
if (!response.ok) throw new Error('Silme işlemi başarısız.');
await fetchMerchants();
} catch (err: any) {
alert(err.message);
}
};
const handleProcessPayout = async (e: React.FormEvent) => {
e.preventDefault();
if (!selectedMerchant || parseFloat(payoutAmount) <= 0) return;
setIsSubmitting(true);
try {
const response = await fetch('/api/admin/payouts', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
merchantId: selectedMerchant.id,
amount: parseFloat(payoutAmount),
network: payoutNetwork,
currency: payoutCurrency
})
});
const data = await response.json();
if (!response.ok) throw new Error(data.error || 'Ödeme işlemi başarısız.');
alert('Ödeme başarıyla gönderildi! TX Hash: ' + data.txHash);
await fetchMerchants();
setShowPayoutModal(false);
setSelectedMerchant(null);
setPayoutAmount('');
} catch (err: any) {
alert(err.message);
} finally {
setIsSubmitting(false);
}
};
return (
<div className="space-y-8 animate-in fade-in slide-in-from-bottom-4 duration-700">
{/* Header */}
<div className="flex flex-col md:flex-row md:items-center justify-between gap-6 bg-white p-8 rounded-[32px] border border-gray-100 shadow-sm">
<div className="flex items-center gap-4">
<div className="w-12 h-12 bg-blue-50 rounded-2xl flex items-center justify-center text-blue-600">
<Building2 size={24} />
</div>
<div>
<h2 className="text-xl font-black text-gray-900">Firmalar (Merchants)</h2>
<p className="text-xs text-gray-400 font-bold uppercase tracking-widest mt-0.5">Ödeme alan tüm işletmeler</p>
</div>
</div>
<Link
href="/admin/merchants/new"
className="flex items-center justify-center gap-2 px-6 py-3 bg-[#2563EB] text-white rounded-2xl text-sm font-bold hover:bg-blue-700 transition shadow-lg shadow-blue-100"
>
<Plus size={18} />
Yeni Firma Ekle
</Link>
</div>
{/* Merchant Cards Grid */}
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-2 gap-6">
{isLoading ? (
<div className="col-span-full flex justify-center py-20">
<div className="animate-spin rounded-full h-8 w-8 border-b-2 border-blue-600"></div>
</div>
) : merchants.map((m) => {
const identifier = m.short_id || m.id;
const paymentLink = `https://p2cgateway.store/checkout?merchant_id=${identifier}&amount=0`;
return (
<div key={m.id} className="bg-white rounded-[40px] border border-gray-100 p-8 shadow-sm hover:shadow-md transition-shadow group">
<div className="flex justify-between items-start mb-6">
<div className="flex items-center gap-4">
<div className="w-14 h-14 bg-gray-50 rounded-2xl flex items-center justify-center text-gray-400 font-black text-xl group-hover:bg-blue-50 group-hover:text-blue-600 transition-colors">
{m.name.substring(0, 1).toUpperCase()}
</div>
<div>
<h3 className="text-lg font-black text-gray-900">{m.name}</h3>
<div className="flex items-center gap-3">
<span className="text-[10px] text-blue-600 font-black uppercase tracking-widest">ID: {identifier}</span>
<div className="flex items-center gap-1.5 px-2 py-0.5 bg-emerald-50 text-emerald-600 text-[9px] font-black rounded-lg border border-emerald-100 uppercase tracking-tight">
Fee: %{m.fee_percent || '1.0'}
</div>
</div>
</div>
</div>
<div className="flex items-center gap-1">
<button
onClick={() => handleEditClick(m)}
className="p-2 text-gray-300 hover:text-blue-600 hover:bg-blue-50 rounded-xl transition-all"
title="Düzenle"
>
<Pencil size={18} />
</button>
<button
onClick={() => handleDeleteMerchant(m.id)}
className="p-2 text-gray-300 hover:text-red-600 hover:bg-red-50 rounded-xl transition-all"
title="Sil"
>
<Trash2 size={18} />
</button>
</div>
</div>
{/* Balance Section */}
<div className="mb-6 p-4 bg-emerald-50/50 rounded-2xl border border-emerald-100 space-y-4">
<div className="flex items-center justify-between">
<div>
<p className="text-[10px] font-black text-emerald-600 uppercase tracking-widest pl-1">İçerideki Bakiye</p>
<p className="text-xl font-black text-emerald-700">
{new Intl.NumberFormat('tr-TR', { style: 'currency', currency: 'TRY' }).format(Number(m.available_balance || 0))}
</p>
</div>
<div className="text-right">
<p className="text-[10px] font-black text-gray-400 uppercase tracking-widest">Toplam Ödenen</p>
<p className="text-xs font-bold text-gray-600">
{new Intl.NumberFormat('tr-TR', { style: 'currency', currency: 'TRY' }).format(Number(m.withdrawn_balance || 0))}
</p>
</div>
</div>
{m.balance_breakdown && m.balance_breakdown.length > 0 && (
<div className="flex flex-wrap gap-2 pt-2 border-t border-emerald-100/50">
{m.balance_breakdown.map((b: any, i: number) => (
<div key={i} className="px-2 py-1 bg-white/60 rounded-lg border border-emerald-100/50 flex items-center gap-1.5 shadow-sm">
<div className={`w-1.5 h-1.5 rounded-full ${b.network === 'SOLANA' ? 'bg-emerald-400' : b.network === 'POLYGON' ? 'bg-purple-400' : b.network === 'TRON' ? 'bg-red-400' : 'bg-orange-400'}`}></div>
<span className="text-[9px] font-black text-emerald-800 uppercase tabular-nums">
{Number(b.amount).toFixed(4)} {b.token}
</span>
</div>
))}
</div>
)}
<button
onClick={() => handlePayoutClick(m)}
disabled={parseFloat(m.available_balance || '0') <= 0}
className="w-full flex items-center justify-center gap-2 py-3 bg-emerald-600 text-white rounded-xl text-[10px] font-black uppercase tracking-widest hover:bg-emerald-700 disabled:opacity-50 disabled:grayscale transition-all shadow-lg shadow-emerald-100"
>
<Wallet size={14} /> Ödeme Gönder (Withdraw)
</button>
</div>
<div className="space-y-4">
{/* API Key Section */}
<div className="p-4 bg-gray-50 rounded-2xl space-y-2 border border-transparent hover:border-gray-100 transition-colors">
<label className="text-[10px] font-black text-gray-400 uppercase tracking-widest pl-1">API Anahtarı (Secret Key)</label>
<div className="flex items-center justify-between gap-3">
<div className="flex-1 bg-white px-4 py-2 rounded-xl text-[11px] font-mono text-gray-400 truncate border border-gray-100/50">
{m.api_key || '••••••••••••••••'}
</div>
<button
onClick={() => copyToClipboard(m.api_key || '', m.id + '-key')}
className="p-2 text-gray-400 hover:text-blue-600 transition-colors"
>
{copiedId === m.id + '-key' ? <Check size={14} /> : <Copy size={14} />}
</button>
</div>
</div>
{/* Webhook Section */}
<div className="p-4 bg-gray-50 rounded-2xl space-y-2 border border-transparent hover:border-gray-100 transition-colors">
<label className="text-[10px] font-black text-gray-400 uppercase tracking-widest pl-1">Webhook URL</label>
<div className="flex items-center gap-2">
<span className="text-xs font-bold text-gray-600 truncate px-1">{m.webhook_url || 'Ayarlanmamış'}</span>
<Globe size={14} className="text-gray-300 shrink-0" />
</div>
</div>
{/* Payment Link Section */}
<div className="p-4 bg-blue-50/30 rounded-2xl border border-blue-50 space-y-2">
<label className="text-[10px] font-black text-blue-600 uppercase tracking-widest pl-1">Ödeme Linki</label>
<div className="flex items-center gap-2">
<div className="flex-1 bg-white px-4 py-3 rounded-xl border border-blue-100/50 flex items-center justify-between group/link hover:border-blue-200 transition-colors">
<a
href={paymentLink}
target="_blank"
rel="noreferrer"
className="text-[11px] font-mono truncate text-gray-500 hover:text-blue-600 transition-colors flex-1 flex items-center gap-1.5"
title="Linki Aç"
>
https://p2cgateway.store/checkout?merchant_id=<span className="text-blue-600 font-bold">{identifier}</span>&amount=<span className="text-emerald-500 font-bold">0</span>
<ExternalLink size={10} className="opacity-0 group-hover/link:opacity-100 transition-opacity" />
</a>
</div>
<button
onClick={() => copyToClipboard(paymentLink, m.id)}
className="p-3 bg-white text-blue-600 rounded-xl border border-blue-100 hover:bg-blue-600 hover:text-white transition shadow-sm shrink-0"
title="Kopyala"
>
{copiedId === m.id ? <Check size={16} /> : <Copy size={16} />}
</button>
</div>
<p className="text-[9px] text-gray-400 font-medium px-1">Yukarıdaki linki müşterinize ileterek manuel ödeme alabilir veya sitenize gömebilirsiniz.</p>
</div>
</div>
<div className="mt-8 pt-6 border-t border-gray-50 flex items-center justify-between">
<div className="flex items-center gap-2">
<div className="w-2 h-2 rounded-full bg-emerald-500 animate-pulse"></div>
<span className="text-[10px] font-black text-gray-400 uppercase tracking-widest">Aktif</span>
</div>
<a
href={`/admin/transactions?merchant_id=${m.id}`}
className="flex items-center gap-2 text-xs font-black text-[#2563EB] hover:underline"
>
Tüm İşlemleri Gör
<ExternalLink size={12} />
</a>
<Link
href={`/merchant/${identifier}`}
className="flex items-center gap-2 text-xs font-black text-emerald-600 hover:underline"
>
Firma Paneli
<ExternalLink size={12} />
</Link>
</div>
</div>
);
})}
{!isLoading && merchants.length === 0 && (
<div className="col-span-full p-20 bg-white rounded-[40px] border border-gray-100 text-center space-y-6">
<div className="w-20 h-20 bg-gray-50 rounded-3xl flex items-center justify-center mx-auto text-gray-200">
<Building2 size={40} />
</div>
<div className="max-w-xs mx-auto">
<p className="text-lg font-black text-gray-900">Henüz firma bulunmuyor</p>
<p className="text-gray-400 text-sm mt-1 font-bold">İlk firmanızı ekleyerek ödeme almaya başlayın.</p>
</div>
<Link
href="/admin/merchants/new"
className="inline-flex items-center gap-2 px-8 py-4 bg-gray-900 text-white rounded-2xl text-sm font-black hover:bg-gray-800 transition shadow-xl shadow-gray-200"
>
<Plus size={20} />
Firma Ekleyerek Başlayın
</Link>
</div>
)}
</div>
{/* Edit Modal */}
{showEditModal && (
<div className="fixed inset-0 z-50 flex items-center justify-center p-6 bg-gray-900/60 backdrop-blur-sm animate-in fade-in duration-300">
<div className="bg-white w-full max-w-lg rounded-[40px] shadow-2xl overflow-hidden animate-in zoom-in-95 duration-300">
<div className="p-10">
<div className="flex justify-between items-center mb-10">
<div>
<h2 className="text-2xl font-black text-gray-900">Firmayı Düzenle</h2>
<p className="text-xs text-gray-400 font-bold uppercase tracking-widest mt-2 px-1">Firma bilgilerini güncelle</p>
</div>
<button
onClick={() => setShowEditModal(false)}
className="p-3 hover:bg-gray-50 rounded-2xl text-gray-400 transition"
>
<X size={24} />
</button>
</div>
<form onSubmit={handleUpdateMerchant} className="space-y-8">
<div className="space-y-6">
<div className="space-y-3">
<label className="text-[10px] font-black text-gray-400 uppercase tracking-[0.2em] ml-1">Firma Adı</label>
<div className="relative">
<Building2 className="absolute left-5 top-1/2 -translate-y-1/2 text-gray-300" size={20} />
<input
type="text"
required
value={editForm.name}
onChange={(e) => setEditForm({ ...editForm, name: e.target.value })}
placeholder="Örn: Ayris Teknoloji"
className="w-full pl-14 pr-6 py-4 bg-gray-50 border-2 border-transparent focus:border-blue-500 focus:bg-white rounded-[24px] outline-none transition-all font-bold text-gray-900 placeholder:text-gray-300"
/>
</div>
</div>
<div className="space-y-3">
<label className="text-[10px] font-black text-gray-400 uppercase tracking-[0.2em] ml-1">Özel Komisyon (%)</label>
<div className="relative">
<div className="absolute right-5 top-1/2 -translate-y-1/2 text-gray-300 font-black text-sm">%</div>
<input
type="number"
step="0.1"
min="0"
max="100"
value={editForm.fee_percent}
onChange={(e) => setEditForm({ ...editForm, fee_percent: e.target.value })}
placeholder="1.0"
className="w-full pl-6 pr-12 py-4 bg-gray-50 border-2 border-transparent focus:border-blue-500 focus:bg-white rounded-[24px] outline-none transition-all font-bold text-gray-900 placeholder:text-gray-300"
/>
</div>
<p className="text-[10px] text-gray-400 font-medium px-1">Kesinti oranı. Boş bırakılırsa sistem varsayılanı kullanılır.</p>
</div>
<div className="space-y-3">
<label className="text-[10px] font-black text-gray-400 uppercase tracking-[0.2em] ml-1">Webhook URL</label>
<div className="relative">
<Globe className="absolute left-5 top-1/2 -translate-y-1/2 text-gray-300" size={20} />
<input
type="url"
value={editForm.webhook_url}
onChange={(e) => setEditForm({ ...editForm, webhook_url: e.target.value })}
placeholder="https://siteniz.com/webhook"
className="w-full pl-14 pr-6 py-4 bg-gray-50 border-2 border-transparent focus:border-blue-500 focus:bg-white rounded-[24px] outline-none transition-all font-bold text-gray-900 placeholder:text-gray-300"
/>
</div>
</div>
<div className="space-y-3">
<label className="text-[10px] font-black text-gray-400 uppercase tracking-[0.2em] ml-1">Ödeme Adresleri ( Bazlı)</label>
<p className="text-[9px] text-gray-400 italic px-1 -mt-1">Her için payout yapılacak cüzdan adresini girin.</p>
{[
{ key: 'EVM', label: 'EVM (Polygon/BSC/ETH)', placeholder: '0x...', icon: '🟣' },
{ key: 'SOLANA', label: 'Solana', placeholder: '5pLH...veya base58 adres', icon: '🟢' },
{ key: 'TRON', label: 'TRON', placeholder: 'T...', icon: '🔴' },
{ key: 'BITCOIN', label: 'Bitcoin', placeholder: 'bc1q...', icon: '🟠' }
].map(net => (
<div key={net.key} className="relative">
<span className="absolute left-4 top-1/2 -translate-y-1/2 text-base">{net.icon}</span>
<input
type="text"
value={editForm.payout_addresses?.[net.key] || ''}
onChange={(e) => setEditForm({
...editForm,
payout_addresses: { ...editForm.payout_addresses, [net.key]: e.target.value }
})}
className="w-full pl-12 pr-6 py-3 bg-gray-50 border-2 border-transparent focus:border-blue-500 focus:bg-white rounded-2xl outline-none transition-all font-mono text-xs text-gray-900 placeholder:text-gray-300"
placeholder={`${net.label}: ${net.placeholder}`}
/>
</div>
))}
</div>
</div>
<div className="flex gap-4 pt-4">
<button
type="button"
onClick={() => setShowEditModal(false)}
className="flex-1 py-4 text-gray-400 font-black text-sm uppercase tracking-widest hover:text-gray-600 transition"
>
İptal
</button>
<button
type="submit"
disabled={isUpdating}
className="flex-[2] py-4 bg-blue-600 text-white rounded-2xl font-black text-sm uppercase tracking-widest hover:bg-blue-700 transition shadow-xl shadow-blue-100 disabled:opacity-50"
>
{isUpdating ? 'Güncelleniyor...' : 'Değişiklikleri Kaydet'}
</button>
</div>
</form>
</div>
</div>
</div>
)}
{/* Payout Modal */}
{showPayoutModal && (
<div className="fixed inset-0 bg-black/40 backdrop-blur-sm z-50 flex items-center justify-center p-4">
<div className="bg-white rounded-[40px] w-full max-w-lg max-h-[90vh] overflow-y-auto shadow-2xl animate-in zoom-in duration-300">
<div className="bg-emerald-600 p-8 text-white relative">
<button onClick={() => setShowPayoutModal(false)} className="absolute top-6 right-6 p-2 hover:bg-white/10 rounded-full transition">
<X size={24} />
</button>
<div className="flex items-center gap-4 mb-4">
<div className="w-16 min-w-[64px] h-16 bg-white/10 rounded-3xl flex items-center justify-center">
<Wallet size={32} />
</div>
<div>
<h3 className="text-2xl font-black">Ödeme Gönder</h3>
<p className="text-xs text-white/60 font-bold uppercase tracking-widest">Treasury'den Merchant Cüzdanına Transfer</p>
</div>
</div>
</div>
<form onSubmit={handleProcessPayout} className="p-8 space-y-6">
{(() => {
const bal = merchantBalances.find(b => b.network === payoutNetwork && b.token === payoutCurrency);
const totalGross = bal ? bal.totalGross : 0;
const totalNet = bal ? bal.balance : 0;
const totalFee = totalGross - totalNet;
const withdrawn = bal ? bal.withdrawn : 0;
const available = totalNet - withdrawn;
return (
<div className="bg-emerald-50 p-6 rounded-3xl border border-emerald-100 space-y-4">
<div className="flex justify-between items-center">
<p className="text-[10px] font-black text-emerald-600 uppercase tracking-widest">Alıcı Firma</p>
<p className="text-sm font-bold text-emerald-700">{selectedMerchant?.name}</p>
</div>
<div className="grid grid-cols-2 gap-4 pt-2 border-t border-emerald-200/30">
<div>
<p className="text-[9px] font-black text-emerald-600/60 uppercase tracking-tight">Top. Brüt (Hazine)</p>
<p className="text-xs font-black text-emerald-800 tabular-nums">{totalGross.toFixed(4)} {payoutCurrency}</p>
</div>
<div className="text-right">
<p className="text-[9px] font-black text-emerald-600/60 uppercase tracking-tight">Platform Fee (%{merchantFeePercent})</p>
<p className="text-xs font-black text-orange-600 tabular-nums">-{totalFee.toFixed(4)} {payoutCurrency}</p>
</div>
</div>
<div className="pt-2 border-t border-emerald-200/50">
<p className="text-[10px] font-black text-emerald-600 uppercase tracking-widest mb-1">Net Hak Ediş (Çekilebilir)</p>
<div className="flex items-baseline gap-2">
<p className="text-3xl font-black text-emerald-900 tabular-nums">{available.toFixed(6)}</p>
<p className="text-sm font-black text-emerald-700">{payoutCurrency}</p>
</div>
{withdrawn > 0 && (
<p className="text-[9px] text-emerald-600/60 font-bold mt-1">Daha önce {withdrawn.toFixed(4)} {payoutCurrency} çekildi.</p>
)}
</div>
{merchantBalances.length > 0 && (
<div className="flex flex-wrap gap-1.5 pt-2 border-t border-emerald-200/30">
{merchantBalances.filter(b => b.available > 0).map((b, i) => (
<span key={i} className={`px-2 py-0.5 rounded-lg text-[8px] font-bold uppercase tabular-nums border cursor-pointer transition-all ${b.network === payoutNetwork && b.token === payoutCurrency ? 'bg-emerald-600 text-white border-emerald-600 shadow-md' : 'bg-white text-emerald-700 border-emerald-100 hover:border-emerald-300'}`}
onClick={() => { setPayoutNetwork(b.network); setPayoutCurrency(b.token); }}
>
{b.network}/{b.token}: {b.available.toFixed(4)}
</span>
))}
</div>
)}
</div>
);
})()}
<div className="space-y-4">
{/* Simplified Selection Indicator */}
<div className="p-4 bg-gray-50 rounded-2xl border border-gray-100 mb-4">
<p className="text-[10px] font-black text-gray-400 uppercase tracking-widest leading-none mb-2">Seçili Ödeme Hattı</p>
<div className="flex items-center justify-between">
<div className="flex items-center gap-3">
<div className="w-10 h-10 bg-white rounded-xl flex items-center justify-center text-lg shadow-sm border border-gray-100">
{payoutNetwork === 'SOLANA' ? '🟢' : payoutNetwork === 'TRON' ? '🔴' : payoutNetwork === 'BITCOIN' ? '🟠' : '🟣'}
</div>
<div>
<p className="text-sm font-black text-gray-900">{payoutNetwork}</p>
<p className="text-[10px] font-bold text-blue-600 uppercase tracking-tight">{payoutCurrency}</p>
</div>
</div>
<span className="text-[9px] font-black text-gray-300 uppercase italic">Yukarıdaki chiplerden seçin</span>
</div>
</div>
<div>
<label className="block text-[10px] font-black text-gray-400 uppercase tracking-widest mb-2 pl-1">
Gönderilecek {payoutCurrency} Miktarı
</label>
{(() => {
const bal = merchantBalances.find(b => b.network === payoutNetwork && b.token === payoutCurrency);
const maxAvailable = bal ? bal.available : 0;
const isOverspend = parseFloat(payoutAmount || '0') > maxAvailable;
return (
<>
<div className="relative">
<input
type="number"
step="0.00000001"
value={payoutAmount}
onChange={(e) => setPayoutAmount(e.target.value)}
className={`w-full pl-5 pr-24 py-4 bg-gray-50 border rounded-2xl focus:ring-2 focus:ring-emerald-500 transition outline-none font-black text-lg ${isOverspend ? 'border-red-400 bg-red-50' : 'border-gray-100'}`}
placeholder="0.00"
required
/>
<div className="absolute right-3 top-1/2 -translate-y-1/2 flex items-center gap-2">
{maxAvailable > 0 && (
<button
type="button"
onClick={() => setPayoutAmount(maxAvailable.toString())}
className="px-2 py-1 bg-emerald-100 text-emerald-700 rounded-lg text-[9px] font-black uppercase hover:bg-emerald-200 transition"
>
MAX
</button>
)}
<span className="font-black text-gray-300 uppercase text-sm">{payoutCurrency}</span>
</div>
</div>
{isOverspend && (
<p className="text-[9px] text-red-500 font-black mt-1 px-1">⚠️ Girilen miktar firma bakiyesini ({maxAvailable.toFixed(6)} {payoutCurrency}) aşıyor!</p>
)}
</>
);
})()}
<p className="text-[9px] text-gray-400 mt-1 italic px-1">Treasury cüzdanından düşülüp merchant adresine kripto olarak iletilecek.</p>
</div>
<div className="p-4 bg-blue-50 rounded-2xl border border-blue-100 flex gap-3">
<ShieldCheck className="text-blue-600 shrink-0" size={20} />
<p className="text-[10px] text-blue-700 font-bold leading-relaxed">
Bu işlem kalıcıdır. Payout adresi ({payoutNetwork}):
<span className="font-mono text-[10px] block mt-1 break-all">
{(() => {
const netKey = ['POLYGON', 'BSC', 'ETH'].includes(payoutNetwork) ? 'EVM' : payoutNetwork;
const addr = selectedMerchant?.payout_addresses?.[netKey];
return addr || <span className="text-red-500 font-black">ADRES EKSİK! Lütfen firma ayarlarından {netKey} adresini girin.</span>;
})()}
</span>
</p>
</div>
</div>
<button
type="submit"
disabled={isSubmitting || (() => {
const bal = merchantBalances.find(b => b.network === payoutNetwork && b.token === payoutCurrency);
const maxAvailable = bal ? bal.available : 0;
return parseFloat(payoutAmount || '0') > maxAvailable || parseFloat(payoutAmount || '0') <= 0;
})() || !(() => {
const netKey = ['POLYGON', 'BSC', 'ETH'].includes(payoutNetwork) ? 'EVM' : payoutNetwork;
return selectedMerchant?.payout_addresses?.[netKey];
})()}
className="w-full py-5 bg-gray-900 text-white rounded-2xl text-xs font-black uppercase tracking-[0.2em] hover:bg-black transition shadow-xl disabled:opacity-50 flex items-center justify-center gap-3"
>
{isSubmitting ? (
<>
<Loader2 className="animate-spin" size={18} />
İşleniyor...
</>
) : (
<>
Ödemeyi Onayla & Gönder
<ArrowRight size={18} />
</>
)}
</button>
</form>
</div>
</div>
)}
</div>
);
}