feat: rebuild trader detail UI with tabs and manual recalculate button

This commit is contained in:
Richard
2026-07-05 19:04:35 +02:00
parent b5dfa6bb1b
commit 3f6f8fc17d
2 changed files with 91 additions and 30 deletions
+58 -28
View File
@@ -211,39 +211,69 @@
<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 class="detail-main">
<!-- 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>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 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>
</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>
<tbody id="td-categoryBody"></tbody>
</table>
<!-- 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">
<table class="data-table">
<thead><tr><th>Time</th><th>Market</th><th>Side</th><th>Price</th><th>Size</th><th>Amount</th></tr></thead>
<tbody id="td-tradesBody"></tbody>
</table>
</div>
</div>
</div>
<div class="card">
<div class="card-header"><h2>Recent Trades</h2></div>
<div class="table-wrap">
<table class="data-table">
<thead><tr><th>Time</th><th>Market</th><th>Side</th><th>Price</th><th>Size</th><th>Amount</th></tr></thead>
<tbody id="td-tradesBody"></tbody>
</table>
<!-- 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>
+33 -2
View File
@@ -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}`);