Tentative next-up for bracket matches waiting on live courts; per-court score keeper QR codes

Matches whose opponent comes from a live match now show in the queue and under
courts as 'X vs winner on Court 2 · ready ~time', which is what double
elimination needed. Score keeper access is a QR per court on the desk plus a
printable page; the copy-link button is gone. Release 0.4.1.

Co-Authored-By: Claude Fable 5.1 <[email protected]>
Claude-Session: https://claude.ai/code/session_01MB7nCCAscYsb3zzkT6LHZi
This commit is contained in:
2026-09-04 02:28:04 +00:00
co-authored by Claude Fable 5.1
parent eb58eb9ad9
commit ae44014e22
10 changed files with 69 additions and 15 deletions
+12 -2
View File
@@ -117,9 +117,19 @@ export function buildRouter({ registry, auth, store }) {
send.redirect(res, `/admin/t/${it.t.slug}?msg=${encodeURIComponent('Created. Print the QR code and open registration when ready.')}`);
});
r.get('/admin/t/:slug', (req, res, { slug }) => {
r.get('/admin/t/:slug', async (req, res, { slug }) => {
const who = requireAdmin(req, res); if (!who) return;
send.html(res, adm.adminTournament(item(slug), who, origin(req), q(req).get('msg'), q(req).get('error'), store.events(slug, 40), (t, c) => keeperUrl(req, t.slug, c.number)));
const it = item(slug);
const keeper = { url: c => keeperUrl(req, slug, c.number), qr: {} };
if (it.t.phase === 'live') for (const c of it.engine.courts) keeper.qr[c.number] = await QRCode.toDataURL(keeperUrl(req, slug, c.number), { width: 220, margin: 1 });
send.html(res, adm.adminTournament(it, who, origin(req), q(req).get('msg'), q(req).get('error'), store.events(slug, 40), keeper));
});
r.get('/admin/t/:slug/keeper-qr', async (req, res, { slug }) => {
const who = requireAdmin(req, res); if (!who) return;
const it = item(slug);
const cards = [];
for (const c of it.engine.courts) cards.push({ court: c.number, url: keeperUrl(req, slug, c.number), qr: await QRCode.toDataURL(keeperUrl(req, slug, c.number), { width: 640, margin: 2 }) });
send.html(res, adm.keeperQrPage(it.t, cards, who));
});
r.get('/admin/t/:slug/qr', async (req, res, { slug }) => {
const who = requireAdmin(req, res); if (!who) return;