75 lines
2.8 KiB
JavaScript
75 lines
2.8 KiB
JavaScript
/**
|
|
* usePrayedLocally.js — the "my dot glows" encouragement loop.
|
|
*
|
|
* WHEN someone clicks "Pray for them", their dot turns glowing FOR THEM,
|
|
* immediately, in this browser (localStorage) — the emotional reward that
|
|
* closes the loop. It is deliberately TEMPORARY (TTL below): the LONG-LASTING
|
|
* glow comes only from actually signing up on the prayer site, which registers
|
|
* server-side and flips `peoplePraying` in the API for everyone. So the local
|
|
* glow is the bridge of encouragement until the real signup shows up in the
|
|
* data — and if they never complete signup, the glow quietly fades.
|
|
*
|
|
* Mechanism: pins color purely from the feature property `peoplePraying`
|
|
* (see colors/prayer-progress.js + useMapLayers HAS_PRAYER). We patch that ONE
|
|
* property (null/0 → 1) for locally-prayed slugs at data-build time — every
|
|
* expression (color, ring, glow) lights up with zero style changes.
|
|
*
|
|
* Storage is sandbox-safe (try/catch — origin-isolated iframes throw).
|
|
*/
|
|
|
|
const KEY = 'doxa-prayed-local'
|
|
// The encouragement window: long enough to still glow when they come back
|
|
// tomorrow, short enough that an unconfirmed click doesn't masquerade as
|
|
// real coverage forever. Real signups persist via the API itself.
|
|
const TTL_MS = 7 * 24 * 60 * 60 * 1000
|
|
|
|
function readAll() {
|
|
try {
|
|
const raw = localStorage.getItem(KEY)
|
|
if (!raw) return {}
|
|
const obj = JSON.parse(raw)
|
|
return (obj && typeof obj === 'object') ? obj : {}
|
|
} catch (_) { return {} }
|
|
}
|
|
|
|
function writeAll(obj) {
|
|
try { localStorage.setItem(KEY, JSON.stringify(obj)) } catch (_) { /* sandboxed */ }
|
|
}
|
|
|
|
/** Slugs prayed-for in this browser, expired entries pruned. */
|
|
export function prayedSlugs() {
|
|
const now = Date.now()
|
|
const all = readAll()
|
|
let dirty = false
|
|
for (const [slug, ts] of Object.entries(all)) {
|
|
if (typeof ts !== 'number' || now - ts > TTL_MS) { delete all[slug]; dirty = true }
|
|
}
|
|
if (dirty) writeAll(all)
|
|
return new Set(Object.keys(all))
|
|
}
|
|
|
|
/** Record a pray-click for a slug + announce it so live maps can re-glow. */
|
|
export function markPrayedLocally(slug) {
|
|
if (!slug) return
|
|
const all = readAll()
|
|
all[slug] = Date.now()
|
|
writeAll(all)
|
|
try {
|
|
window.dispatchEvent(new CustomEvent('doxa:prayed-locally', { detail: { slug } }))
|
|
} catch (_) {}
|
|
}
|
|
|
|
/**
|
|
* Patch a people-groups array: locally-prayed slugs with no real coverage get
|
|
* peoplePraying=1 so they render as "Has Prayer". Real API values (>0) are
|
|
* never touched — the server's truth always wins.
|
|
*/
|
|
export function applyLocalPrayer(list) {
|
|
const set = prayedSlugs()
|
|
if (!set.size || !Array.isArray(list)) return list
|
|
return list.map((pg) => {
|
|
const real = Number(pg && pg.peoplePraying) || 0
|
|
if (real > 0 || !pg || !set.has(pg.slug)) return pg
|
|
return { ...pg, peoplePraying: 1 }
|
|
})
|
|
}
|