doxa-maps/library/utils/peopleGroupPoints.js
Doxa Maps c99fe68c38 A country map you can drop on one page, without the dashboard around it
DX-life's country pages render nothing where a map belongs. The map they need
has been in this repo since the regions clone landed — it was just unreachable
without loading the whole regions dashboard, a bundle that fetches the people
group list, builds four stat cards, a region chooser and a table, none of which
a country page wants. So this is not a new map. It is the same component, given
its own element and its own bundle.

  <doxa-country-map profile-config='{"countryCodes":["TCD"],"colorByPrayer":true}'>

RegionCountryMap and useRegionsI18n move to library/ because they now have a
second consumer, which is the only thing that earns a place there. Six import
sites updated in this commit; nothing else moved.

THE CONTRACT arrives through profile-config, the channel every element here
uses, so a generated page and a hand-written host page are configured the same
way: countryCodes, center, zoom, bounds, colorByPrayer, researchUrl,
prayBaseUrl. Two translations happen at the edge rather than by widening the
component — colorByPrayer is a boolean here and colorMode a string inside, and
countryCodes accepts an array OR "TCD,NER,MLI", because an HTML attribute is a
string and JSON-inside-an-attribute is the shape people get wrong.

THE ELEMENT FETCHES ITS OWN PINS, and that is what makes prayBaseUrl part of the
contract rather than decoration. An element handed a country code, a base URL
and no way to fetch would draw a country outline with nothing inside it — the
blank page it exists to fix, in a new disguise. Same endpoint, same fields, same
mapping as the dashboard; it asks for a country instead of the world.

THE FIELD LIST TRAVELS WITH THE MAPPING, in peopleGroupPoints.js. The obvious
version of this commit asks for PEOPLE_GROUP_LIST_FIELDS — the list the stats
need — and every pin still draws, every popup comes up empty, and nothing logs
anything. The popup half is what makes it a map you can read, so the two are
one export and neither can be requested without the other. The dashboard's own
request is unchanged: the concatenation produces the identical string.

countryUrl is additive, not in the confirmed contract. The component's country
link needs a base and DX-life's country pages live under /regions/; a host that
sets nothing gets that documented default.
2026-09-29 01:38:07 +00:00

37 lines
2.1 KiB
JavaScript

/**
* peopleGroupPoints.js — SHARED (@map/utils/peopleGroupPoints.js).
*
* ONE mapping from the prayer API's people-group rows to the pin objects RegionCountryMap draws.
* Extracted when the country-map bundle became the second consumer, rather than copied: the field
* names here are not ours, they are the API's, and a copy that drifts by one key draws a map with
* silently missing popups.
*
* Every field is mapped exactly as DX-life's CountryMap.vue:107-115 maps it, including the
* has_photo GATE on the image, which is theirs: a row can carry an image_url that is a
* placeholder, and they only show it when the flag says there is a real photo.
*
* Rows without finite coordinates are DROPPED, not defaulted — a pin at 0,0 is a people group in
* the Gulf of Guinea, which is worse than an absent pin because it looks like data.
*/
/**
* The fields this mapping needs, as the API spells them. It lives HERE, beside the mapping, because
* the two are one contract: ask for PEOPLE_GROUP_LIST_FIELDS alone — the list the stats need — and
* every pin still draws, every popup comes up empty, and nothing logs a thing. The popup half
* (name, slug, rop1, religion, description, photo) is what makes it a map you can read.
*/
export const PEOPLE_GROUP_POINT_FIELDS = 'name,slug,rop1,religion,imb_people_description,image_url,has_photo'
export function peopleGroupPoints(posts, toNumber) {
return (Array.isArray(posts) ? posts : []).map((p) => ({
name: p.name || '', slug: p.slug || '',
code: p.country_code?.value || '', country: p.country_code?.label || '',
// the wagf_region VALUE (e.g. 'latin_america_&_caribbean'), which is what
// library/colors/wagf-region.js keys its palette on
region: p.wagf_region?.value || '',
lng: parseFloat(p.longitude), lat: parseFloat(p.latitude),
committed: toNumber(p.people_committed), population: toNumber(p.population),
rop1: p.rop1?.label || '', religion: p.religion?.label || '',
description: p.imb_people_description ?? '',
imageUrl: (p.has_photo && p.image_url) ? p.image_url : '',
})).filter((p) => Number.isFinite(p.lng) && Number.isFinite(p.lat))
}