// 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}`));