feat: show generated crypto wallets with block explorer links on admin transactions page

This commit is contained in:
mstfyldz
2026-03-14 00:52:54 +03:00
parent a90b1707bb
commit 6f13e27a80
2 changed files with 73 additions and 0 deletions

View File

@@ -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">

View 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>
);
}