henaiv2 / templates /admin_dashboard.html
joashsam's picture
Update templates/admin_dashboard.html
437f304 verified
Raw
History Blame Contribute Delete
6.5 kB
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>HenAi Admin Dashboard</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
background: #0f0f12;
color: #d4d4e0;
padding: 20px;
}
.container { max-width: 1400px; margin: 0 auto; }
h1 { font-size: 28px; margin-bottom: 20px; color: #eeeef5; }
h2 { font-size: 20px; margin: 24px 0 16px; color: #eeeef5; }
.stats-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 16px;
margin-bottom: 24px;
}
.stat-card {
background: #141418;
border: 1px solid rgba(255,255,255,0.08);
border-radius: 16px;
padding: 20px;
}
.stat-number {
font-size: 36px;
font-weight: 700;
color: #7c6aff;
}
.stat-label {
font-size: 13px;
color: #6b6b80;
margin-top: 8px;
}
table {
width: 100%;
border-collapse: collapse;
background: #141418;
border-radius: 16px;
overflow: hidden;
}
th, td {
padding: 12px 16px;
text-align: left;
border-bottom: 1px solid rgba(255,255,255,0.08);
}
th {
background: #1a1a20;
font-weight: 600;
color: #9191a8;
}
tr:hover { background: rgba(124,106,255,0.05); }
.btn {
padding: 6px 12px;
border-radius: 8px;
border: none;
cursor: pointer;
font-size: 12px;
}
.btn-danger {
background: rgba(248,113,113,0.2);
color: #f87171;
}
.btn-danger:hover { background: rgba(248,113,113,0.4); }
.nav-links {
display: flex;
gap: 16px;
margin-bottom: 20px;
border-bottom: 1px solid rgba(255,255,255,0.08);
padding-bottom: 12px;
}
.nav-link {
color: #9191a8;
text-decoration: none;
font-size: 14px;
padding: 4px 0;
cursor: pointer;
}
.nav-link.active {
color: #7c6aff;
border-bottom: 2px solid #7c6aff;
}
.nav-link:hover { color: #d4d4e0; }
</style>
</head>
<body>
<div class="container">
<h1>HenAi Admin Dashboard</h1>
<div class="nav-links">
<span class="nav-link active" data-tab="overview">Overview</span>
<span class="nav-link" data-tab="users">Users</span>
</div>
<div id="overview-tab">
<div class="stats-grid" id="stats-container">
<div class="stat-card">
<div class="stat-number" id="total-users">-</div>
<div class="stat-label">Total Users</div>
</div>
<div class="stat-card">
<div class="stat-number" id="total-conversations">-</div>
<div class="stat-label">Total Conversations</div>
</div>
</div>
</div>
<div id="users-tab" style="display:none;">
<table id="users-table">
<thead>
<tr><th>User ID</th><th>Username</th><th>Email</th><th>Created</th><th>Last Active</th><th>Actions</th></tr>
</thead>
<tbody id="users-tbody"></tbody>
</table>
</div>
</div>
<script>
async function loadStats() {
const res = await fetch('/admin/api/stats');
const data = await res.json();
if (data.success) {
document.getElementById('total-users').textContent = data.stats.total_users;
document.getElementById('total-conversations').textContent = data.stats.total_conversations;
}
}
async function loadUsers() {
const res = await fetch('/api/users');
const data = await res.json();
if (data.success) {
const tbody = document.getElementById('users-tbody');
tbody.innerHTML = '';
data.users.forEach(user => {
const row = tbody.insertRow();
row.insertCell(0).textContent = user.user_id;
row.insertCell(1).textContent = user.username;
row.insertCell(2).textContent = user.email;
row.insertCell(3).textContent = user.created_at ? new Date(user.created_at).toLocaleDateString() : '-';
row.insertCell(4).textContent = user.last_active ? new Date(user.last_active).toLocaleDateString() : '-';
const actionsCell = row.insertCell(5);
const deleteBtn = document.createElement('button');
deleteBtn.textContent = 'Delete';
deleteBtn.className = 'btn btn-danger';
deleteBtn.onclick = () => {
if (confirm(`Delete user ${user.username}?`)) {
fetch(`/api/users/${user.user_id}`, { method: 'DELETE' })
.then(() => { loadUsers(); loadStats(); });
}
};
actionsCell.appendChild(deleteBtn);
});
}
}
document.querySelectorAll('.nav-link').forEach(link => {
link.addEventListener('click', () => {
document.querySelectorAll('.nav-link').forEach(l => l.classList.remove('active'));
link.classList.add('active');
const tab = link.dataset.tab;
document.getElementById('overview-tab').style.display = tab === 'overview' ? 'block' : 'none';
document.getElementById('users-tab').style.display = tab === 'users' ? 'block' : 'none';
if (tab === 'overview') loadStats();
if (tab === 'users') loadUsers();
});
});
loadStats();
</script>
</body>
</html>