/* DubLab reviews dashboard */ const key = new URLSearchParams(location.search).get('key') || ''; let allReviews = []; let filter = 'all'; const $ = (s) => document.querySelector(s); function esc(s) { const d = document.createElement('div'); d.textContent = s == null ? '' : String(s); return d.innerHTML; } function fmtTime(ts) { const d = new Date(ts * 1000); const p = (n) => String(n).padStart(2, '0'); return `${d.getFullYear()}-${p(d.getMonth() + 1)}-${p(d.getDate())} ${p(d.getHours())}:${p(d.getMinutes())}`; } async function load() { try { const r = await fetch('/admin/api/reviews?key=' + encodeURIComponent(key)); if (!r.ok) { $('#list').innerHTML = '

not found

'; return; } const j = await r.json(); allReviews = j.reviews || []; renderStats(j.stats || {}); renderUsage(j.usage || {}); renderList(); } catch (e) { $('#list').innerHTML = '

load failed

'; } } function renderStats(s) { $('#st-total').textContent = s.total ?? 0; $('#st-avg').textContent = s.avg ?? '–'; $('#st-5').textContent = (s.dist && s.dist['5']) ?? 0; const dist = $('#dist'); dist.innerHTML = ''; const max = Math.max(1, ...[1, 2, 3, 4, 5].map((i) => (s.dist && s.dist[String(i)]) || 0)); for (let i = 5; i >= 1; i--) { const c = (s.dist && s.dist[String(i)]) || 0; const row = document.createElement('div'); row.className = 'drow'; row.innerHTML = `⭐${i}
${c}`; dist.appendChild(row); } } function renderUsage(u) { $('#u-jobs').textContent = u.jobs ?? 0; $('#u-users').textContent = u.users ?? 0; $('#u-done').textContent = u.done ?? 0; $('#u-fail').textContent = u.fail ?? 0; $('#u-today').textContent = u.today ?? 0; $('#u-week').textContent = u.week ?? 0; const box = $('#recent'); const evs = u.recent || []; const status = {}; const durs = {}; evs.forEach((e) => { if (!e.job_id) return; if (e.event === 'done' || e.event === 'fail') status[e.job_id] = e.event; if (e.event === 'done' && e.dur) durs[e.job_id] = e.dur; }); const jobs = evs.filter((e) => e.event === 'job').slice(0, 12); if (!jobs.length) { box.innerHTML = '

job မရှိသေးဘူး

'; return; } box.innerHTML = ''; jobs.forEach((e) => { const st = status[e.job_id] || ''; const mark = st === 'done' ? '✅' : st === 'fail' ? '❌' : '⏳'; const dur = durs[e.job_id] ? ' · ' + durs[e.job_id] + 's video' : ''; const el = document.createElement('div'); el.className = 'rev'; el.innerHTML = `
${mark} ${esc(fmtTime(e.ts))} · ${esc(e.ip || '?')} · ${esc(e.kind || '')}${dur}
`; box.appendChild(el); }); } function renderList() { const list = $('#list'); const rows = allReviews.filter((r) => { if (filter === 'all') return true; if (filter === 'msg') return (r.message || '').trim().length > 0; return r.stars === +filter; }); if (!rows.length) { list.innerHTML = '

မရှိသေးဘူး

'; return; } list.innerHTML = ''; rows.forEach((r) => { const el = document.createElement('div'); el.className = 'rev'; const stars = r.stars ? '⭐'.repeat(r.stars) : 'no rating'; el.innerHTML = `
${esc(fmtTime(r.ts))} · ${esc(r.ip || '?')}${r.job_id ? ' · job ' + esc(r.job_id) : ''}` + `
` + `
${stars}
` + `
${esc(r.message || '—')}
`; el.querySelector('.del').addEventListener('click', async () => { if (!confirm('ဒီ review ကို ဖျက်မလား?')) return; try { const dr = await fetch('/admin/api/reviews/' + encodeURIComponent(r.id || '') + '?key=' + encodeURIComponent(key), { method: 'DELETE' }); if (dr.ok) load(); } catch (e) { /* ignore */ } }); list.appendChild(el); }); } $('#filters').querySelectorAll('button').forEach((b) => b.addEventListener('click', () => { $('#filters').querySelectorAll('button').forEach((x) => x.classList.remove('on')); b.classList.add('on'); filter = b.dataset.f; renderList(); })); $('#refresh').addEventListener('click', load); load(); setInterval(() => { if (!document.hidden) load(); }, 30000);