Enhance UI, add AI integration, improve logging and database stats
This commit is contained in:
@@ -149,7 +149,12 @@ async function api(endpoint) {
|
||||
// ─── Format Helpers ───
|
||||
const fmt = {
|
||||
usd: v => { if (v === null || v === undefined) return '$0'; const n = Number(v); return n >= 1000000 ? `$${(n/1000000).toFixed(1)}M` : n >= 1000 ? `$${(n/1000).toFixed(1)}K` : `$${n.toFixed(0)}`; },
|
||||
pct: v => { if (v === null || v === undefined) return '0%'; return `${Number(v).toFixed(1)}%`; },
|
||||
pct: v => {
|
||||
if (v === null || v === undefined) return '0%';
|
||||
const n = Number(v);
|
||||
const color = n > 55 ? 'var(--pnl-positive)' : n < 45 ? 'var(--pnl-negative)' : 'var(--text)';
|
||||
return `<span style="color:${color};font-weight:${n>55||n<45?'600':'normal'};">${n.toFixed(1)}%</span>`;
|
||||
},
|
||||
num: v => { if (v === null || v === undefined) return '0'; return Number(v).toLocaleString(); },
|
||||
time: v => { if (!v) return '—'; const d = new Date(v); const now = new Date(); const diff = (now - d) / 1000;
|
||||
if (diff < 60) return `${Math.floor(diff)}s ago`;
|
||||
@@ -207,15 +212,15 @@ async function loadDashboard() {
|
||||
// Top Traders table
|
||||
const tbody = document.getElementById('topTradersBody');
|
||||
tbody.innerHTML = data.topTraders.map((t, i) => `
|
||||
<tr onclick="viewTrader(${t.id})" style="cursor:pointer">
|
||||
<td>${i + 1}</td>
|
||||
<td><strong>${t.displayName}</strong></td>
|
||||
<td>${t.platform}</td>
|
||||
<td><strong>${Number(t.combinedScore).toFixed(1)}</strong></td>
|
||||
<td>${fmt.pct(t.winRate)}</td>
|
||||
<td>${fmt.pnl(t.totalPnl)}</td>
|
||||
<td>${fmt.tier(t.tier)}</td>
|
||||
<td>${fmt.num(t.totalTrades)}</td>
|
||||
<tr>
|
||||
<td onclick="viewTrader(${t.id})" style="cursor:pointer">${i + 1}</td>
|
||||
<td><strong>${t.platform === 'Polymarket' ? `<a href="https://polymarket.com/profile/${t.platformUserId}" target="_blank" style="color:var(--text);text-decoration:underline;">${t.displayName}</a>` : t.displayName}</strong></td>
|
||||
<td onclick="viewTrader(${t.id})" style="cursor:pointer">${t.platform}</td>
|
||||
<td onclick="viewTrader(${t.id})" style="cursor:pointer"><strong>${Number(t.combinedScore).toFixed(1)}</strong></td>
|
||||
<td onclick="viewTrader(${t.id})" style="cursor:pointer">${fmt.pct(t.winRate)}</td>
|
||||
<td onclick="viewTrader(${t.id})" style="cursor:pointer">${fmt.pnl(t.totalPnl)}</td>
|
||||
<td onclick="viewTrader(${t.id})" style="cursor:pointer">${fmt.tier(t.tier)}</td>
|
||||
<td onclick="viewTrader(${t.id})" style="cursor:pointer">${fmt.num(t.totalTrades)}</td>
|
||||
</tr>
|
||||
`).join('');
|
||||
|
||||
@@ -282,7 +287,7 @@ async function loadTraders() {
|
||||
tbody.innerHTML = data.map((t, i) => `
|
||||
<tr>
|
||||
<td>${i + 1}</td>
|
||||
<td><strong>${t.displayName}</strong></td>
|
||||
<td><strong>${t.platform === 'Polymarket' ? `<a href="https://polymarket.com/profile/${t.platformUserId}" target="_blank" style="color:var(--text);text-decoration:underline;">${t.displayName}</a>` : t.displayName}</strong></td>
|
||||
<td>${t.platform}</td>
|
||||
<td><strong>${Number(t.combinedScore).toFixed(1)}</strong></td>
|
||||
<td>${fmt.pct(t.winRate)}</td>
|
||||
@@ -350,10 +355,14 @@ async function viewTrader(id) {
|
||||
document.getElementById('td-pnl').innerHTML = fmt.pnl(t.totalPnl);
|
||||
document.getElementById('td-trades').textContent = fmt.num(t.totalTrades);
|
||||
document.getElementById('td-score').textContent = Number(t.combinedScore).toFixed(1);
|
||||
document.getElementById('td-ai-summary').textContent = t.aiStrategySummary || 'Not analyzed yet.';
|
||||
|
||||
const refreshBtn = document.getElementById('btn-refresh-trader');
|
||||
refreshBtn.onclick = () => manualUpdateTrader(id);
|
||||
|
||||
const aiBtn = document.getElementById('btn-ai-analysis');
|
||||
aiBtn.onclick = () => triggerAiAnalysis(id, true);
|
||||
|
||||
const tbody = document.getElementById('td-tradesBody');
|
||||
tbody.innerHTML = t.recentTrades.map(tr => `
|
||||
<tr>
|
||||
@@ -428,3 +437,24 @@ setInterval(() => {
|
||||
const activePage = document.querySelector('.page.active');
|
||||
if (activePage?.id === 'page-dashboard') loadDashboard();
|
||||
}, 30000);
|
||||
|
||||
async function triggerAiAnalysis(id, manual) {
|
||||
const btn = document.getElementById('btn-ai-analysis');
|
||||
const oldText = btn.textContent;
|
||||
btn.textContent = 'Analyzing...';
|
||||
btn.disabled = true;
|
||||
try {
|
||||
const res = await api(`/api/traders/${id}/ai-analysis?manual=${manual}`, { method: 'POST' });
|
||||
if (res && res.summary) {
|
||||
document.getElementById('td-ai-summary').textContent = res.summary;
|
||||
} else {
|
||||
alert('Analysis failed or returned empty.');
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
alert('Analysis error: ' + e);
|
||||
} finally {
|
||||
btn.textContent = oldText;
|
||||
btn.disabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user