const token = location.pathname.split('/').pop(); history.replaceState(null, '', '/admin'); const grid = document.querySelector('#review-grid'); const reviewStatus = document.querySelector('#review-status'); const reviewCount = document.querySelector('#review-count'); const selected = new Set(); document.querySelector('#refresh-review').addEventListener('click', loadPending); document.querySelector('#approve-selected').addEventListener('click', () => moderateSelected('approve')); document.querySelector('#delete-selected').addEventListener('click', () => moderateSelected('delete')); grid.addEventListener('change', (event) => { const checkbox = event.target.closest('[data-select-id]'); if (!checkbox) return; if (checkbox.checked) selected.add(checkbox.dataset.selectId); else selected.delete(checkbox.dataset.selectId); }); grid.addEventListener('click', (event) => { const action = event.target.closest('[data-admin-action]'); if (!action) return; moderate([action.dataset.id], action.dataset.adminAction); }); await loadPending(); async function loadPending() { selected.clear(); reviewStatus.textContent = 'FETCHING_PENDING_QUEUE'; const response = await fetch('/api/admin/pending', { headers: adminHeaders() }); const payload = await response.json(); if (!response.ok) { reviewStatus.textContent = 'REVIEW_AUTH_FAILED'; grid.innerHTML = '
ADMIN_TOKEN_INVALID
'; return; } reviewStatus.textContent = 'PENDING_REVIEW'; reviewCount.textContent = `${payload.total} ITEMS`; renderPending(payload.memes); } function renderPending(memes) { if (memes.length === 0) { grid.innerHTML = '
NO_PENDING_MEMES
'; return; } grid.replaceChildren(...memes.map((meme) => { const article = document.createElement('article'); article.className = 'meme-card'; article.innerHTML = `
SCORE ${meme.moderationScore}
Pending meme ${shortId(meme.id)}

${escapeText(meme.moderationReason || 'Queued for review.')}

${formatBytes(meme.byteSize)}
`; return article; })); } async function moderateSelected(action) { if (selected.size === 0) return; await moderate([...selected], action); } async function moderate(ids, action) { const endpoint = action === 'approve' ? '/api/admin/approve' : '/api/admin/delete'; const response = await fetch(endpoint, { method: 'POST', headers: { ...adminHeaders(), 'Content-Type': 'application/json' }, body: JSON.stringify({ ids }) }); if (!response.ok) { reviewStatus.textContent = 'REVIEW_ACTION_FAILED'; return; } await loadPending(); } function adminHeaders() { return { 'X-Admin-Token': token }; } function shortId(id) { return `0x${id.slice(0, 4).toUpperCase()}...${id.slice(-4).toUpperCase()}`; } function formatBytes(value) { if (value >= 1024 * 1024) return `${(value / 1024 / 1024).toFixed(1)}MB`; return `${Math.ceil(value / 1024)}KB`; } function escapeText(value) { const span = document.createElement('span'); span.textContent = value; return span.innerHTML; }