/** * Build a standalone page that renders the REAL dispatch map with mock stops. * * ── Why this exists ───────────────────────────────────────────────────────── * * A leaflet map cannot be checked by anything else in this repo. The pure tests * never mount it, `renderToString` never runs the effect that builds it, and * the jsdom tests can only COUNT what it produced — none of them can tell you * whether the thing looks right. The map shipped twice on that basis and came * back wrong twice: once invisible behind a crash, once with its routes buried * under 966 pins. * * So this bundles the actual `GroupMap` — not a copy of it, not a sketch — * against invented stops, and writes one HTML file to open. What you see is * what the console draws. * * ── Why the mock data lives here and not in `src` ─────────────────────────── * * `npm run verify:live` asserts there is no `src/demo`, and it is right to: * a fixture layer inside the app is how a screen ends up quietly rendering * invented numbers in production. This is a build tool. It imports from `src` * and nothing in `src` imports it, so the app has no path to this data. * * node scripts/mapPreview.mjs → writes scripts/.preview/map.html */ import { build } from 'esbuild'; import { mkdirSync, writeFileSync } from 'node:fs'; import { dirname, join } from 'node:path'; import { fileURLToPath } from 'node:url'; const here = dirname(fileURLToPath(import.meta.url)); const out = join(here, '.preview'); /* ── The mock day ───────────────────────────────────────────────────────── Shaped like the real thing rather than like a neat demo: one shop, two riders working outward in a loop, three orders stacked on one address, and one rider whose last reported position is nowhere near their last drop. Each of those is something the live data does and each has broken this map once. */ const SHOP = { lat: 11.0168, lng: 76.9558 }; const ROUND_A = [ [11.0245, 76.9601], [11.0298, 76.9662], [11.0331, 76.9754], [11.0288, 76.9823], [11.0201, 76.9788], // Three orders at one address — the repeat customer that stacked 379 pins. [11.0154, 76.9702], [11.0154, 76.9702], [11.0154, 76.9702], ]; const ROUND_B = [ [11.0102, 76.9481], [11.0044, 76.9412], [10.9981, 76.9377], [10.9932, 76.9455], [11.0011, 76.9521], ]; function stopsFor(rider, userid, points, from) { return points.map((point, index) => ({ kind: 'delivery', row: { deliveryid: userid * 100 + index, orderid: `916-${userid}${String(index + 1).padStart(2, '0')}`, userid, ridername: rider, // A couple left open, so the status colours are visible on the pins. orderstatus: index === points.length - 1 ? 'active' : 'delivered', assigntime: '2026-08-25 09:00:00', deliverytime: `2026-08-25 ${String(from + Math.floor(index / 2)).padStart(2, '0')}:${String((index * 17) % 60).padStart(2, '0')}:00`, pickuplat: String(SHOP.lat), pickuplon: String(SHOP.lng), droplat: String(point[0]), droplon: String(point[1]), // Only the last stop carries a rider fix, which is the shape the live // rows have — a position arrives when a job moves, not per stop. ...(index === points.length - 1 ? { riderslat: String(point[0] + 0.004), riderslon: String(point[1] - 0.003) } : {}), deliveryamt: 30 + index * 5, deliverycustomer: `${rider}'s customer ${index + 1}`, deliveryaddress: `Stop ${index + 1}`, }, })); } const STOPS = [ ...stopsFor('Varun', 897, ROUND_A, 10), ...stopsFor('Murali', 1111, ROUND_B, 11), ]; const entry = join(out, 'entry.jsx'); mkdirSync(out, { recursive: true }); writeFileSync( entry, `import { createRoot } from 'react-dom/client'; import { GroupMap } from '../../src/features/store-admin/GroupMap'; const STOPS = ${JSON.stringify(STOPS)}; createRoot(document.getElementById('root')).render(
Two riders, one shop, ${STOPS.length} stops. Three of Varun's orders are at one address. This is the real GroupMap component with invented stops.