feat: rebuild trader detail UI with tabs and manual recalculate button
This commit is contained in:
@@ -211,32 +211,48 @@
|
||||
<div class="stat-value" id="td-strategy">—</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card" style="margin-top: 16px;">
|
||||
<div class="stat-group">
|
||||
<div class="stat-label" style="display:flex; justify-content:space-between; align-items:center;">
|
||||
AI Analysis
|
||||
<button class="btn-sm" id="btn-ai-analysis" style="padding:4px 8px; font-size:12px; background:var(--bg-input);">Run Analysis</button>
|
||||
</div>
|
||||
<div class="stat-value small" id="td-ai-summary" style="margin-top: 8px; font-weight:normal; line-height:1.4;">Not analyzed yet.</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="detail-main">
|
||||
<div class="metrics-grid">
|
||||
<div class="metric-card"><div class="metric-label">Win Rate</div><div class="metric-value" id="td-winrate">—</div></div>
|
||||
<div class="metric-card"><div class="metric-label">Total PnL</div><div class="metric-value" id="td-pnl">—</div></div>
|
||||
<div class="metric-card"><div class="metric-label">Total Trades</div><div class="metric-value" id="td-trades">—</div></div>
|
||||
<div class="metric-card accent"><div class="metric-label">Score</div><div class="metric-value" id="td-score">—</div></div>
|
||||
<!-- Tabs Navigation -->
|
||||
<div class="tabs-nav" style="display:flex; gap:16px; margin-bottom:16px; border-bottom:1px solid var(--border); padding-bottom:8px;">
|
||||
<button class="btn-tab active" data-tab="td-tab-analytics" onclick="switchTraderTab('td-tab-analytics')" style="background:transparent; border:none; color:var(--text); font-weight:bold; cursor:pointer;">Analytics & AI</button>
|
||||
<button class="btn-tab" data-tab="td-tab-recent" onclick="switchTraderTab('td-tab-recent')" style="background:transparent; border:none; color:var(--text-muted); cursor:pointer;">Recent Trades</button>
|
||||
<button class="btn-tab" data-tab="td-tab-positions" onclick="switchTraderTab('td-tab-positions')" style="background:transparent; border:none; color:var(--text-muted); cursor:pointer;">Positions</button>
|
||||
</div>
|
||||
|
||||
<!-- Tab Content: Analytics -->
|
||||
<div class="tab-content" id="td-tab-analytics" style="display:block;">
|
||||
<div class="metrics-grid">
|
||||
<div class="metric-card"><div class="metric-label">Win Rate</div><div class="metric-value" id="td-winrate">---</div></div>
|
||||
<div class="metric-card"><div class="metric-label">Total PnL</div><div class="metric-value" id="td-pnl">---</div></div>
|
||||
<div class="metric-card"><div class="metric-label">Total Trades</div><div class="metric-value" id="td-trades">---</div></div>
|
||||
<div class="metric-card accent">
|
||||
<div class="metric-label">Score</div>
|
||||
<div class="metric-value" id="td-score">---</div>
|
||||
<button class="btn-sm" id="btn-force-analyze" style="margin-top:8px; padding:4px 8px; width:100%; background:var(--bg-input);">Recalculate</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card" style="margin-bottom: 24px;">
|
||||
<div class="card-header" style="display:flex; justify-content:space-between; align-items:center;">
|
||||
<h2>AI Strategy Analysis</h2>
|
||||
<button class="btn-sm" id="btn-ai-analysis" style="padding:6px 12px; background:var(--primary); color:#000;">Run Deep Analysis</button>
|
||||
</div>
|
||||
<div class="stat-value small" id="td-ai-summary" style="margin-top: 16px; font-weight:normal; line-height:1.6; white-space:pre-wrap; background:var(--bg-input); padding:16px; border-radius:8px; border:1px solid var(--border);">Click 'Run Deep Analysis' to generate a detailed summary of this trader's behavior.</div>
|
||||
</div>
|
||||
|
||||
<div class="card" style="margin-bottom: 24px;">
|
||||
<div class="card-header"><h2>Category Specialization</h2></div>
|
||||
<div class="table-wrap">
|
||||
<table class="data-table">
|
||||
<thead><tr><th>Category</th><th>Win Rate</th><th>PnL</th><th>Volume</th><th>Trades</th></tr></thead>
|
||||
<thead><tr><th>Category</th><th>Subcategory</th><th>Win Rate</th><th>PnL</th><th>Volume</th><th>Trades</th></tr></thead>
|
||||
<tbody id="td-categoryBody"></tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Tab Content: Recent Trades -->
|
||||
<div class="tab-content" id="td-tab-recent" style="display:none;">
|
||||
<div class="card">
|
||||
<div class="card-header"><h2>Recent Trades</h2></div>
|
||||
<div class="table-wrap">
|
||||
@@ -247,6 +263,20 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Tab Content: Positions -->
|
||||
<div class="tab-content" id="td-tab-positions" style="display:none;">
|
||||
<div class="card">
|
||||
<div class="card-header"><h2>Active Positions</h2></div>
|
||||
<div class="table-wrap">
|
||||
<table class="data-table">
|
||||
<thead><tr><th>Market</th><th>Outcome</th><th>Shares</th><th>Avg Price</th><th>Est. PnL</th></tr></thead>
|
||||
<tbody id="td-positionsBody"><tr><td colspan="5" style="text-align:center;">Coming soon</td></tr></tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
@@ -346,6 +346,9 @@ async function viewTrader(id) {
|
||||
const t = await api(`/api/traders/${id}`);
|
||||
if (!t) return;
|
||||
|
||||
// Reset tabs to default (Analytics)
|
||||
switchTraderTab('td-tab-analytics');
|
||||
|
||||
document.getElementById('td-name').textContent = t.displayName;
|
||||
document.getElementById('td-platform').textContent = t.platform;
|
||||
document.getElementById('td-platformId').textContent = t.platformUserId;
|
||||
@@ -360,11 +363,26 @@ async function viewTrader(id) {
|
||||
const refreshBtn = document.getElementById('btn-refresh-trader');
|
||||
refreshBtn.onclick = () => manualUpdateTrader(id);
|
||||
|
||||
const forceBtn = document.getElementById('btn-force-analyze');
|
||||
if(forceBtn) {
|
||||
forceBtn.onclick = async () => {
|
||||
forceBtn.disabled = true;
|
||||
forceBtn.textContent = '...';
|
||||
try {
|
||||
await api(`/api/traders/${id}/force-analyze`, { method: 'POST' });
|
||||
alert('Deep Analysis queued! Please wait a moment and then refresh.');
|
||||
} finally {
|
||||
forceBtn.disabled = false;
|
||||
forceBtn.textContent = 'Recalculate';
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
const aiBtn = document.getElementById('btn-ai-analysis');
|
||||
aiBtn.onclick = () => triggerAiAnalysis(id, true);
|
||||
|
||||
const wlBtn = document.getElementById('btn-toggle-watchlist');
|
||||
wlBtn.textContent = t.isOnWatchlist ? '★ Watchlist (Remove)' : '☆ Watchlist (Add)';
|
||||
wlBtn.textContent = t.isOnWatchlist ? 'Watchlist (Remove)' : 'Watchlist (Add)';
|
||||
wlBtn.onclick = async () => {
|
||||
const method = t.isOnWatchlist ? 'DELETE' : 'POST';
|
||||
await api(`/api/traders/${id}/watchlist`, { method });
|
||||
@@ -385,6 +403,7 @@ async function viewTrader(id) {
|
||||
catBody.innerHTML = t.categoryPerformances.map(c => `
|
||||
<tr>
|
||||
<td>${c.category}</td>
|
||||
<td>${c.subcategory || '-'}</td>
|
||||
<td>${fmt.pct(c.winRate)}</td>
|
||||
<td>${fmt.pnl(c.totalPnL)}</td>
|
||||
<td>${fmt.usd(c.totalVolume)}</td>
|
||||
@@ -392,7 +411,7 @@ async function viewTrader(id) {
|
||||
</tr>
|
||||
`).join('');
|
||||
} else {
|
||||
catBody.innerHTML = '<tr><td colspan="5" style="text-align:center; padding:16px; color:var(--text-muted)">No category data available</td></tr>';
|
||||
catBody.innerHTML = '<tr><td colspan="6" style="text-align:center; padding:16px; color:var(--text-muted)">No category data available</td></tr>';
|
||||
}
|
||||
|
||||
const tbody = document.getElementById('td-tradesBody');
|
||||
@@ -410,6 +429,18 @@ async function viewTrader(id) {
|
||||
`).join('');
|
||||
}
|
||||
|
||||
function switchTraderTab(tabId) {
|
||||
// Hide all tabs
|
||||
document.querySelectorAll('.tab-content').forEach(el => el.style.display = 'none');
|
||||
// Deactivate all buttons
|
||||
document.querySelectorAll('.btn-tab').forEach(el => el.classList.remove('active'));
|
||||
// Show active tab
|
||||
document.getElementById(tabId).style.display = 'block';
|
||||
// Activate clicked button
|
||||
const btn = document.querySelector(`.btn-tab[data-tab="${tabId}"]`);
|
||||
if(btn) btn.classList.add('active');
|
||||
}
|
||||
|
||||
async function viewMarket(id) {
|
||||
navigateTo('market-detail');
|
||||
const m = await api(`/api/markets/${id}`);
|
||||
|
||||
Reference in New Issue
Block a user