89 lines
3.5 KiB
HTML
89 lines
3.5 KiB
HTML
@include(snippets/header)
|
|
|
|
<div class="container" style="padding-top: 20px;">
|
|
<h2>Invite Tokens</h2>
|
|
|
|
<div style="margin-bottom: 20px; text-align: right;">
|
|
<button id="generate-token" class="btn-upload" style="width: auto; padding: 10px 20px;">Generate New
|
|
Token</button>
|
|
</div>
|
|
|
|
<div class="upload-form" style="overflow-x: auto;">
|
|
<table style="width: 100%; border-collapse: collapse; color: var(--white);">
|
|
<thead>
|
|
<tr style="border-bottom: 1px solid var(--nav-border-color); text-align: left;">
|
|
<th style="padding: 10px;">Token</th>
|
|
<th style="padding: 10px;">Status</th>
|
|
<th style="padding: 10px;">Used By</th>
|
|
<th style="padding: 10px;">Created</th>
|
|
<th style="padding: 10px;">Actions</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody id="token-list">
|
|
<!-- Populated by JS -->
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
const loadTokens = async () => {
|
|
try {
|
|
console.log('Loading tokens...');
|
|
const res = await fetch('/api/v2/admin/tokens');
|
|
const data = await res.json();
|
|
console.log('Tokens data:', data);
|
|
if (data.success) {
|
|
const tbody = document.getElementById('token-list');
|
|
tbody.innerHTML = data.tokens.map(t =>
|
|
'<tr style="border-bottom: 1px solid rgba(255,255,255,0.05);">' +
|
|
'<td style="padding: 10px; font-family: monospace; font-size: 1.1em; color: var(--accent);">' + t.token + '</td>' +
|
|
'<td style="padding: 10px;">' +
|
|
(t.is_used ? '<span style="color: #ff6b6b">Used</span>' : '<span style="color: #51cf66">Available</span>') +
|
|
'</td>' +
|
|
'<td style="padding: 10px;">' + (t.used_by_name || '-') + '</td>' +
|
|
'<td style="padding: 10px;">' + new Date(parseInt(t.created_at) * 1000).toLocaleString() + '</td>' +
|
|
'<td style="padding: 10px;">' +
|
|
(!t.is_used ? '<button onclick="deleteToken(' + t.id + ')" class="btn-remove" style="padding: 5px 10px; font-size: 0.8em;">Delete</button>' : '') +
|
|
'</td>' +
|
|
'</tr>'
|
|
).join('');
|
|
}
|
|
} catch (e) { console.error(e); }
|
|
};
|
|
|
|
const generateToken = async () => {
|
|
console.log('Generating...');
|
|
try {
|
|
const res = await fetch('/api/v2/admin/tokens/create', { method: 'POST' });
|
|
const data = await res.json();
|
|
console.log('Gen result:', data);
|
|
if (data.success) {
|
|
loadTokens();
|
|
} else {
|
|
alert('Failed: ' + data.msg);
|
|
}
|
|
} catch (e) {
|
|
console.error(e);
|
|
alert('Error: ' + e.message);
|
|
}
|
|
};
|
|
|
|
const deleteToken = async (id) => {
|
|
if (!confirm('Delete this token?')) return;
|
|
const res = await fetch('/api/v2/admin/tokens/delete', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({ id })
|
|
});
|
|
const data = await res.json();
|
|
if (data.success) {
|
|
loadTokens();
|
|
}
|
|
};
|
|
|
|
document.getElementById('generate-token').addEventListener('click', generateToken);
|
|
loadTokens();
|
|
</script>
|
|
|
|
@include(snippets/footer) |