feat: show generated crypto wallets with block explorer links on admin transactions page
This commit is contained in:
@@ -12,6 +12,7 @@ import { tr } from 'date-fns/locale';
|
||||
import TransactionSearch from '@/components/admin/TransactionSearch';
|
||||
import TransactionStatusFilter from '@/components/admin/TransactionStatusFilter';
|
||||
import SyncPaymentsButton from '@/components/admin/SyncPaymentsButton';
|
||||
import TransactionWallets from '@/components/admin/TransactionWallets';
|
||||
|
||||
async function getTransactions(filters: { merchant_id?: string; q?: string; status?: string }) {
|
||||
let sql = `
|
||||
@@ -118,6 +119,8 @@ export default async function TransactionsPage(props: {
|
||||
) : (
|
||||
<span className="text-[10px] text-gray-400 font-bold truncate max-w-[200px] mt-1">{t.callback_url || 'Geri dönüş yok'}</span>
|
||||
)}
|
||||
{/* Render generated crypto wallets below the info */}
|
||||
<TransactionWallets metadata={t.metadata} />
|
||||
</div>
|
||||
</td>
|
||||
<td className="px-10 py-8">
|
||||
|
||||
70
components/admin/TransactionWallets.tsx
Normal file
70
components/admin/TransactionWallets.tsx
Normal file
@@ -0,0 +1,70 @@
|
||||
'use client';
|
||||
|
||||
import React from 'react';
|
||||
import { ExternalLink, Copy, Check } from 'lucide-react';
|
||||
|
||||
interface TransactionWalletsProps {
|
||||
metadata: any;
|
||||
}
|
||||
|
||||
export default function TransactionWallets({ metadata }: TransactionWalletsProps) {
|
||||
const [copied, setCopied] = React.useState<string | null>(null);
|
||||
|
||||
if (!metadata || !metadata.wallets) return null;
|
||||
|
||||
const wallets = metadata.wallets;
|
||||
const networks = Object.keys(wallets);
|
||||
|
||||
if (networks.length === 0) return null;
|
||||
|
||||
const handleCopy = (e: React.MouseEvent, text: string) => {
|
||||
e.stopPropagation();
|
||||
navigator.clipboard.writeText(text);
|
||||
setCopied(text);
|
||||
setTimeout(() => setCopied(null), 2000);
|
||||
};
|
||||
|
||||
const getExplorerUrl = (network: string, address: string) => {
|
||||
if (network === 'SOLANA') return `https://explorer.solana.com/address/${address}?cluster=devnet`;
|
||||
if (network === 'POLYGON') return `https://polygonscan.com/address/${address}`;
|
||||
if (network === 'TRON') return `https://tronscan.org/#/address/${address}`;
|
||||
if (network === 'EVM') return `https://etherscan.io/address/${address}`;
|
||||
return '#';
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="mt-3 flex flex-wrap gap-2">
|
||||
{networks.map(network => {
|
||||
const walletData = wallets[network];
|
||||
const address = typeof walletData === 'string' ? walletData : walletData?.address;
|
||||
|
||||
if (!address) return null;
|
||||
|
||||
const shortAddress = `${address.substring(0, 5)}...${address.substring(address.length - 4)}`;
|
||||
|
||||
return (
|
||||
<div key={network} className="flex items-center gap-1.5 bg-gray-50 border border-gray-100 px-2 py-1 rounded-md">
|
||||
<span className="text-[9px] font-black text-gray-500 uppercase">{network}:</span>
|
||||
<a
|
||||
href={getExplorerUrl(network, address)}
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
className="text-[10px] font-mono text-blue-600 hover:text-blue-800 transition flex items-center gap-1"
|
||||
title="Ağda Görüntüle"
|
||||
>
|
||||
{shortAddress}
|
||||
<ExternalLink size={10} />
|
||||
</a>
|
||||
<button
|
||||
onClick={(e) => handleCopy(e, address)}
|
||||
className="text-gray-400 hover:text-gray-700 transition ml-1"
|
||||
title="Adresi Kopyala"
|
||||
>
|
||||
{copied === address ? <Check size={12} className="text-emerald-500" /> : <Copy size={10} />}
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user