feat: merchant specific fees, TRON & BTC support, coin logos, and bug fixes
This commit is contained in:
@@ -20,6 +20,7 @@ export default function NewMerchantPage() {
|
||||
const [name, setName] = useState('');
|
||||
const [webhookUrl, setWebhookUrl] = useState('');
|
||||
const [paymentProvider, setPaymentProvider] = useState('stripe');
|
||||
const [feePercent, setFeePercent] = useState('1.0');
|
||||
const [success, setSuccess] = useState(false);
|
||||
|
||||
const handleSubmit = async (e: React.FormEvent) => {
|
||||
@@ -33,7 +34,8 @@ export default function NewMerchantPage() {
|
||||
body: JSON.stringify({
|
||||
name,
|
||||
webhook_url: webhookUrl,
|
||||
payment_provider: paymentProvider
|
||||
payment_provider: paymentProvider,
|
||||
fee_percent: parseFloat(feePercent || '1.0')
|
||||
}),
|
||||
});
|
||||
|
||||
@@ -141,6 +143,27 @@ export default function NewMerchantPage() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Fee Percentage Input */}
|
||||
<div className="space-y-3">
|
||||
<label className="text-[11px] font-black text-gray-400 uppercase tracking-widest ml-1">Özel Komisyon Oranı (%)</label>
|
||||
<div className="relative group max-w-[240px]">
|
||||
<div className="absolute right-6 top-1/2 -translate-y-1/2 text-gray-400 font-black">%</div>
|
||||
<input
|
||||
type="number"
|
||||
step="0.1"
|
||||
min="0"
|
||||
max="100"
|
||||
value={feePercent}
|
||||
onChange={(e) => setFeePercent(e.target.value)}
|
||||
placeholder="1.0"
|
||||
className="w-full pl-8 pr-12 py-5 bg-gray-50 border-2 border-transparent focus:border-blue-100 focus:bg-white rounded-3xl text-lg font-black text-gray-900 outline-none transition-all placeholder:text-gray-300"
|
||||
/>
|
||||
</div>
|
||||
<p className="text-[11px] text-gray-400 font-medium px-1">
|
||||
Bu firmadan her işlemde kesilecek platform payı. (Varsayılan: %1.0)
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Webhook Input */}
|
||||
<div className="space-y-3">
|
||||
<label className="text-[11px] font-black text-gray-400 uppercase tracking-widest ml-1">Geri Dönüş (Webhook) URL</label>
|
||||
|
||||
@@ -63,7 +63,8 @@ export default function MerchantsPage() {
|
||||
name: editingMerchant.name,
|
||||
webhook_url: editingMerchant.webhook_url,
|
||||
payment_provider: editingMerchant.payment_provider,
|
||||
provider_config: editingMerchant.provider_config
|
||||
provider_config: editingMerchant.provider_config,
|
||||
fee_percent: editingMerchant.fee_percent
|
||||
})
|
||||
});
|
||||
if (!response.ok) throw new Error('Güncelleme başarısız.');
|
||||
@@ -136,9 +137,11 @@ export default function MerchantsPage() {
|
||||
</div>
|
||||
<div>
|
||||
<h3 className="text-lg font-black text-gray-900">{m.name}</h3>
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="flex items-center gap-3">
|
||||
<span className="text-[10px] text-blue-600 font-black uppercase tracking-widest">ID: {identifier}</span>
|
||||
{m.short_id && <span className="px-1.5 py-0.5 bg-blue-50 text-blue-600 text-[8px] font-black rounded border border-blue-100 uppercase tracking-tighter transition-all group-hover:bg-blue-600 group-hover:text-white group-hover:border-blue-700">Short Link Active</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>
|
||||
@@ -307,6 +310,24 @@ export default function MerchantsPage() {
|
||||
</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={editingMerchant?.fee_percent || '1.0'}
|
||||
onChange={(e) => setEditingMerchant({ ...editingMerchant, 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">Bu firmaya özel 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 (Geri Dönüş)</label>
|
||||
<div className="relative">
|
||||
|
||||
@@ -16,7 +16,8 @@ import {
|
||||
export default function AdminSettingsPage() {
|
||||
const [settings, setSettings] = useState({
|
||||
sol_platform_address: '',
|
||||
evm_platform_address: ''
|
||||
evm_platform_address: '',
|
||||
default_fee_percent: '1.0'
|
||||
});
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const [isSaving, setIsSaving] = useState(false);
|
||||
@@ -34,7 +35,8 @@ export default function AdminSettingsPage() {
|
||||
if (data.error) throw new Error(data.error);
|
||||
setSettings({
|
||||
sol_platform_address: data.sol_platform_address || '',
|
||||
evm_platform_address: data.evm_platform_address || ''
|
||||
evm_platform_address: data.evm_platform_address || '',
|
||||
default_fee_percent: data.default_fee_percent || '1.0'
|
||||
});
|
||||
} catch (err: any) {
|
||||
setMessage({ type: 'error', text: 'Ayarlar yüklenemedi: ' + err.message });
|
||||
@@ -65,7 +67,7 @@ export default function AdminSettingsPage() {
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="max-w-4xl mx-auto space-y-10 animate-in fade-in slide-in-from-bottom-4 duration-700">
|
||||
<div className="max-w-4xl mx-auto space-y-10 animate-in fade-in slide-in-from-bottom-4 duration-700 pb-20">
|
||||
{/* Header */}
|
||||
<div className="flex flex-col md:flex-row md:items-center justify-between gap-6">
|
||||
<div>
|
||||
@@ -80,6 +82,37 @@ export default function AdminSettingsPage() {
|
||||
|
||||
{/* Main Form */}
|
||||
<form onSubmit={handleSave} className="space-y-8">
|
||||
{/* Fee Setting Card */}
|
||||
<div className="bg-white p-10 rounded-[48px] border border-gray-100 shadow-sm space-y-10">
|
||||
<div className="flex items-center gap-4">
|
||||
<div className="w-12 h-12 bg-emerald-50 rounded-2xl flex items-center justify-center text-emerald-600">
|
||||
<Zap size={24} />
|
||||
</div>
|
||||
<div>
|
||||
<h3 className="text-xl font-black text-gray-900">Komisyon (Fee) Ayarları</h3>
|
||||
<p className="text-xs text-gray-400 font-bold uppercase tracking-widest mt-1">Sistem geneli varsayılan işlem kesintisi</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="max-w-xs space-y-3">
|
||||
<label className="text-[10px] font-black text-gray-400 uppercase tracking-[0.2em] ml-1">Yüzdelik Kesinti (%)</label>
|
||||
<div className="relative">
|
||||
<div className="absolute right-6 top-1/2 -translate-y-1/2 text-gray-400 font-black">%</div>
|
||||
<input
|
||||
type="number"
|
||||
step="0.1"
|
||||
min="0"
|
||||
max="100"
|
||||
required
|
||||
value={settings.default_fee_percent}
|
||||
onChange={(e) => setSettings({ ...settings, default_fee_percent: e.target.value })}
|
||||
className="w-full pl-8 pr-12 py-5 bg-gray-50 border-2 border-transparent focus:border-emerald-500 focus:bg-white rounded-[24px] outline-none transition-all font-black text-gray-900 text-lg"
|
||||
/>
|
||||
</div>
|
||||
<p className="text-[10px] text-gray-400 font-medium px-1">Örn: 1.0 (Yüzde bir), 2.5 (Yüzde iki buçuk)</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Platform Addresses Card */}
|
||||
<div className="bg-white p-10 rounded-[48px] border border-gray-100 shadow-sm space-y-10">
|
||||
<div className="flex items-center gap-4">
|
||||
|
||||
Reference in New Issue
Block a user