forked from Txio-labs/txio
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathHeaderBar.tsx
More file actions
107 lines (96 loc) · 4.52 KB
/
Copy pathHeaderBar.tsx
File metadata and controls
107 lines (96 loc) · 4.52 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
import React, { useEffect, useState } from 'react';
import { Play, Zap, Loader2, Server, Terminal, Layers } from 'lucide-react';
import { Select } from '../Select';
import { RequestType, Network, RPCHealthMetric } from '../../types';
import { useAppStore } from '@/lib/store';
import { resolveRpcUrl } from '@/lib/appConfig';
import { getSuiRpcHealth } from '../../services/suiService';
interface HeaderBarProps {
requestType: RequestType;
network: Network;
isLoading: boolean;
activeAddress: string | null;
onTypeChange: (type: RequestType) => void;
onSend: () => void;
onExecute?: () => void;
}
export const HeaderBar: React.FC<HeaderBarProps> = ({
requestType,
network,
isLoading,
activeAddress,
onTypeChange,
onSend,
onExecute
}) => {
const { settings } = useAppStore();
const [rpcHealth, setRpcHealth] = useState<RPCHealthMetric | null>(null);
const endpoint = resolveRpcUrl(network, settings);
useEffect(() => {
let mounted = true;
const getHealth = async () => {
const health = await getSuiRpcHealth(network);
if (mounted) {
setRpcHealth(health);
}
};
getHealth();
return () => {
mounted = false;
};
}, [network, endpoint]);
return (
<div className="p-3 border-b border-white/10 bg-near-black/50 flex flex-wrap gap-3 items-center backdrop-blur-sm">
<div className="w-full sm:w-40 shrink-0">
<Select
value={requestType}
onChange={onTypeChange}
options={[
{ label: 'JSON-RPC', value: RequestType.RPC, icon: <Terminal size={12} className="text-emerald-500" /> },
{ label: 'TX BUILDER', value: RequestType.TRANSACTION, icon: <Layers size={12} className="text-amber-500" /> }
]}
fullWidth
/>
</div>
{/* Enhanced Endpoint Context */}
<div className="flex-1 flex items-center bg-near-black border border-white/10 rounded-lg px-3 py-1.5 h-[38px] min-w-[200px] group focus-within:border-white/20 transition-colors">
<div className="flex items-center gap-2 mr-3 border-r border-white/10 pr-3">
<Server size={12} className="text-slate-500" />
<span className="text-[10px] font-bold text-slate-300 uppercase">{network}</span>
</div>
<div className="flex-1 flex items-center gap-2 overflow-hidden">
<span className="text-xs font-mono text-slate-500 truncate" title={endpoint}>{endpoint}</span>
</div>
{rpcHealth && (
<div className="flex items-center gap-1.5 ml-2 pl-2 border-l border-white/10" title={`Status: ${rpcHealth.status}`}>
<div className={`w-1.5 h-1.5 rounded-full ${rpcHealth.status === 'healthy' ? 'bg-emerald-500 shadow-[0_0_5px_rgba(16,185,129,0.5)]' : rpcHealth.status === 'degraded' ? 'bg-amber-500' : 'bg-red-500'}`}></div>
<span className={`text-[10px] font-mono ${rpcHealth.status === 'healthy' ? 'text-emerald-500' : rpcHealth.status === 'degraded' ? 'text-amber-500' : 'text-red-400'}`}>
{Math.round(rpcHealth.latency[rpcHealth.latency.length-1])}ms
</span>
</div>
)}
</div>
<div className="flex items-center gap-2 w-full sm:w-auto">
<button
onClick={onSend}
disabled={isLoading}
className={`h-[38px] bg-electric-violet hover:bg-electric-violet text-white px-5 rounded-lg font-bold flex items-center justify-center gap-2 transition-all disabled:opacity-30 disabled:grayscale text-[10px] uppercase tracking-widest shadow-lg shadow-sui-900/40 active:scale-95 shrink-0 flex-1 sm:flex-initial`}
>
{isLoading ? <Loader2 size={14} className="animate-spin" /> : <Play size={14} fill="currentColor" />}
{requestType === RequestType.RPC ? 'Send' : 'Simulate'}
</button>
{requestType === RequestType.TRANSACTION && onExecute && (
<button
onClick={onExecute}
disabled={isLoading || !activeAddress}
className="h-[38px] bg-emerald-600 hover:bg-emerald-500 text-white px-3 rounded-lg font-bold flex items-center justify-center transition-all shadow-lg shadow-emerald-900/40 active:scale-95 disabled:opacity-30 disabled:grayscale disabled:cursor-not-allowed"
title={activeAddress ? 'Review wallet-based simulation' : 'Connect Wallet to review simulation'}
aria-label={activeAddress ? 'Review wallet-based simulation' : 'Connect wallet to review simulation'}
>
<Zap size={14} fill="currentColor" />
</button>
)}
</div>
</div>
);
};