Files
ProdDash/tools/pco-band-mock.js
Waters ChurchandClaude Fable 5.1 5fb90190ae Band Lineup 1.11.0: into the catalog, and to the guide's rules
The module arrived in the previous commit exactly as it runs in North
Attleboro. This brings it to the interface rules every module follows and
puts it where the admin page can offer it.

The three hide-toggles — names, mic labels, parallax — sat in a folded
"Show / hide" group. Rule 8 puts four or fewer at the top of the gear with
no group at all, so they are ungrouped and first; the Birthday group keeps
its switch. The test-mode select loses its help line (rule 5). Everything
else in the gear was already within the rules, and every title-bar control
was already an icon with a tooltip.

The Planning Center mock moves out of the module folder to tools/, beside
the other upstream mocks, so an install does not download a development
tool with the module; README and CLAUDE.md say how to run it. The version
goes to 1.11.0 so the copy already installed on NA is offered the update
from the repo, and the module joins the README's list.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-22 09:19:34 -04:00

50 lines
3.6 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// Minimal Planning Center mock for the Band Lineup module: service types, one
// plan today, its team_members (with person+team includes), People birthdates,
// and avatar bytes. Enough to exercise the whole board build.
const http = require('http');
const PORT = Number(process.argv[2] || 24710);
const JPEG = Buffer.from('/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAP//////////////////////////////////////////////////////////////////////////////////////wAALCAABAAEBAREA/8QAFAABAAAAAAAAAAAAAAAAAAAAAP/EABQQAQAAAAAAAAAAAAAAAAAAAAD/2gAIAQEAAD8AfwD/2Q==', 'base64');
const TODAY = new Date();
const iso = (d) => d.toISOString();
// One person's birthday lands in this Wed–Tue week (today is a Wed in the test).
const inWeek = new Date(TODAY.getFullYear(), TODAY.getMonth(), TODAY.getDate() + 2);
const bdayInWeek = `1994-${String(inWeek.getMonth()+1).padStart(2,'0')}-${String(inWeek.getDate()).padStart(2,'0')}`;
const PEOPLE = {
p1: { name: 'Lemuel Maldonado', pos: 'Vox 1', team: 'Vocals', bd: '1990-03-04' },
p2: { name: 'Wes Carter', pos: 'Vox 2', team: 'Vocals', bd: null },
p3: { name: 'Jessica Proulx', pos: 'Vox 3', team: 'Vocals', bd: '1992-11-01' },
p4: { name: 'Jeremy Cruz', pos: 'Guitar / Lead', team: 'Band', bd: null },
p5: { name: 'Alex Gaitan', pos: 'Drums', team: 'Band', bd: bdayInWeek }, // celebrating
p6: { name: 'Rosaliz Gomez', pos: 'Piano', team: 'Band', bd: null },
p7: { name: 'George Acosta', pos: 'MC', team: 'Production', bd: null },
p8: { name: 'Not Shown', pos: 'Camera 2', team: 'Video', bd: null }, // team not allowed → filtered out
};
const TEAMS = { Vocals: 't1', Band: 't2', Production: 't3', Video: 't4' };
function send(res, obj) { res.writeHead(200, { 'Content-Type': 'application/json' }); res.end(JSON.stringify(obj)); }
const server = http.createServer((req, res) => {
const u = new URL(req.url, 'http://x'); const p = u.pathname;
if (p.startsWith('/avatar/')) { res.writeHead(200, { 'Content-Type': 'image/jpeg' }); return res.end(JPEG); }
if (p === '/services/v2/folders') return send(res, { data: [] });
if (p === '/services/v2/service_types') return send(res, { data: [{ id: '1', type: 'ServiceType', attributes: { name: 'Sunday Service' }, relationships: { parent: { data: null } } }] });
if (/^\/services\/v2\/service_types\/1\/plans$/.test(p)) {
if (u.searchParams.get('filter') === 'past') return send(res, { data: [] });
return send(res, { data: [{ id: '100', type: 'Plan', attributes: { sort_date: iso(TODAY), title: 'Taking Thoughts Captive - Part 4', dates: 'September 20, 2026' } }] });
}
if (/^\/services\/v2\/service_types\/1\/plans\/100\/team_members$/.test(p)) {
const data = []; const included = [];
for (const [id, v] of Object.entries(PEOPLE)) {
data.push({ id: `tm-${id}`, type: 'PlanPerson', attributes: { status: 'C', team_position_name: v.pos }, relationships: { person: { data: { type: 'Person', id } }, team: { data: { type: 'Team', id: TEAMS[v.team] } } } });
included.push({ id, type: 'Person', attributes: { full_name: v.name, photo_url: `http://127.0.0.1:${PORT}/avatar/${id}` } });
}
for (const [name, id] of Object.entries(TEAMS)) included.push({ id, type: 'Team', attributes: { name } });
return send(res, { data, included, links: {} });
}
const person = p.match(/^\/people\/v2\/people\/([^/]+)$/);
if (person) { const v = PEOPLE[person[1]]; return send(res, { data: { id: person[1], type: 'Person', attributes: { birthdate: v ? v.bd : null } } }); }
res.writeHead(404); res.end('{}');
});
server.listen(PORT, '127.0.0.1', () => console.log(`[pco-band-mock] on http://127.0.0.1:${PORT}`));