Files
smom-dbis-138/frontend-dapp/src/components/admin/chain-management/ChainManagementDashboard.tsx
2026-03-02 12:14:09 -08:00

169 lines
7.2 KiB
TypeScript

/**
* Chain Management Dashboard
* Admin UI for managing all supported chains, adapters, and deployments
*/
import { useState, useEffect } from 'react';
import { useAccount } from 'wagmi';
import { ethers } from 'ethers';
import toast from 'react-hot-toast';
interface ChainMetadata {
chainId: number;
chainIdentifier: string;
chainType: string;
adapter: string;
isActive: boolean;
explorerUrl: string;
minConfirmations: number;
avgBlockTime: number;
}
export default function ChainManagementDashboard() {
const { address, isConnected } = useAccount();
const [chains, setChains] = useState<ChainMetadata[]>([]);
const [loading, setLoading] = useState(true);
const [selectedChain, setSelectedChain] = useState<string>('');
useEffect(() => {
if (isConnected) {
loadChains();
}
}, [isConnected, address]);
const loadChains = async () => {
try {
setLoading(true);
// TODO: Connect to ChainRegistry contract
// const provider = new ethers.JsonRpcProvider(process.env.NEXT_PUBLIC_RPC_URL);
// const registry = new ethers.Contract(REGISTRY_ADDRESS, REGISTRY_ABI, provider);
// const [evmChainIds, evmChains] = await registry.getAllEVMChains();
// const [nonEvmIds, nonEvmChains] = await registry.getAllNonEVMChains();
// Mock data for now
setChains([
{
chainId: 138,
chainIdentifier: 'EVM-138',
chainType: 'EVM',
adapter: '0x...',
isActive: true,
explorerUrl: 'https://explorer.d-bis.org',
minConfirmations: 12,
avgBlockTime: 2
},
{
chainId: 50,
chainIdentifier: 'EVM-50',
chainType: 'XDC',
adapter: '0x...',
isActive: true,
explorerUrl: 'https://explorer.xdc.network',
minConfirmations: 12,
avgBlockTime: 2
}
]);
} catch (error: any) {
toast.error(`Failed to load chains: ${error.message}`);
} finally {
setLoading(false);
}
};
const toggleChain = async (chainId: number, chainIdentifier: string, currentStatus: boolean) => {
try {
// TODO: Call ChainRegistry.setChainActive()
toast.success(`Chain ${currentStatus ? 'disabled' : 'enabled'}`);
loadChains();
} catch (error: any) {
toast.error(`Failed to toggle chain: ${error.message}`);
}
};
if (!isConnected) {
return (
<div className="p-6 bg-white/10 rounded-xl">
<p className="text-white/70">Please connect your wallet to manage chains.</p>
</div>
);
}
return (
<div className="space-y-6">
<div className="bg-black/20 rounded-xl p-6 border border-white/10">
<h2 className="text-xl font-bold text-white mb-4">Chain Management</h2>
{loading ? (
<div className="text-white/70">Loading chains...</div>
) : (
<div className="space-y-4">
{chains.map((chain) => (
<div
key={chain.chainId || chain.chainIdentifier}
className="bg-white/5 rounded-lg p-4 flex items-center justify-between"
>
<div>
<h3 className="text-white font-semibold">
{chain.chainIdentifier} ({chain.chainType})
</h3>
<p className="text-white/70 text-sm">
Adapter: {chain.adapter.slice(0, 10)}...
</p>
<p className="text-white/70 text-sm">
Explorer: <a href={chain.explorerUrl} target="_blank" rel="noopener noreferrer" className="text-blue-400 hover:underline">{chain.explorerUrl}</a>
</p>
</div>
<div className="flex items-center gap-4">
<span className={`px-3 py-1 rounded-full text-sm ${
chain.isActive
? 'bg-green-500/20 text-green-200'
: 'bg-red-500/20 text-red-200'
}`}>
{chain.isActive ? 'Active' : 'Inactive'}
</span>
<button
onClick={() => toggleChain(chain.chainId, chain.chainIdentifier, chain.isActive)}
className={`px-4 py-2 rounded-lg font-semibold transition-colors ${
chain.isActive
? 'bg-red-600 hover:bg-red-700 text-white'
: 'bg-green-600 hover:bg-green-700 text-white'
}`}
>
{chain.isActive ? 'Disable' : 'Enable'}
</button>
</div>
</div>
))}
</div>
)}
</div>
<div className="bg-black/20 rounded-xl p-6 border border-white/10">
<h3 className="text-lg font-bold text-white mb-4">Add New Chain</h3>
<div className="space-y-4">
<select
value={selectedChain}
onChange={(e) => setSelectedChain(e.target.value)}
className="w-full px-4 py-2 bg-white/10 border border-white/20 rounded-lg text-white"
>
<option value="">Select chain to add...</option>
<option value="polygon">Polygon</option>
<option value="arbitrum">Arbitrum</option>
<option value="optimism">Optimism</option>
<option value="base">Base</option>
<option value="avalanche">Avalanche</option>
<option value="bsc">BSC</option>
<option value="ethereum">Ethereum Mainnet</option>
</select>
<button
onClick={() => toast.info('Deployment feature coming soon')}
className="w-full px-4 py-2 bg-blue-600 hover:bg-blue-700 text-white rounded-lg font-semibold"
>
Deploy Chain Adapter
</button>
</div>
</div>
</div>
);
}