Milestones: celebrate every 100 members, not just the big marks
Marty, 2026-09-22. The ladder was 500 / 1000 / 2500 / 5000 / 10000, so most of the year would pass with nothing to cheer. It is now every 100, with the fuller write-up kept for the half-thousands and thousands and a short cheer in between, so the small ones do not read as a repeated speech. Both are laid out in short lines for a phone, like the daily snapshot. The hundreds already passed are recorded as done on the live volume, so the next post is 600. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
+32
-11
@@ -112,16 +112,37 @@ async function tick() {
|
|||||||
|
|
||||||
async function preview() { const sc = X.siteConfig(); return compose(await gather(), sc.telegramCtaUrl); }
|
async function preview() { const sc = X.siteConfig(); return compose(await gather(), sc.telegramCtaUrl); }
|
||||||
|
|
||||||
// ---- membership milestones (Marty, 2026-09-19): one celebratory post per mark, the moment it is crossed
|
// ---- membership milestones: one celebratory post per mark, the moment it is crossed.
|
||||||
const MILESTONES = [500, 1000, 2500, 5000, 10000];
|
// Every 100 members since 2026-09-22 (Marty), with the fuller write-up saved for the round
|
||||||
|
// thousands and the half-thousands so the small ones stay a quick cheer, not a repeated speech.
|
||||||
|
const STEP = 100;
|
||||||
|
const isBig = m => m % 500 === 0;
|
||||||
|
const marksUpTo = count => { const out = []; for (let m = STEP; m <= count; m += STEP) out.push(m); return out; };
|
||||||
|
const MILESTONES = marksUpTo(10000); // kept for callers that want the ladder
|
||||||
|
|
||||||
function composeMilestone(mark, s, cta) {
|
function composeMilestone(mark, s, cta) {
|
||||||
const L = [];
|
const ledger = '<a href="https://instantadpay.com/ledger">Live ledger</a>' + (cta ? ' \u00b7 <a href="' + cta + '">Join free</a>' : '');
|
||||||
L.push('\u{1F389} <b>' + n(mark) + ' members on InstantAdPay.</b>');
|
const B = [];
|
||||||
L.push(n(mark) + ' people have joined, and here is what that looks like right now: <b>' + n(s.wallets) + '</b> wallets linked, <b>' + n(s.payoutsOn) + '</b> with payouts switched on, <b>' + n(s.lifeBuys) + '</b> purchases, and <b>' + pol(s.lifePaidWei) + ' POL</b> paid to members in the same transactions the purchases came from. Every one of those payments is on the public ledger.');
|
B.push('\u{1F389} <b>' + n(mark) + ' members on InstantAdPay</b>');
|
||||||
L.push('Thank you to every member who brought someone in. That is the whole engine, and it is working.');
|
if (isBig(mark)) {
|
||||||
L.push('The next ' + n(mark) + ' start today.');
|
B.push(n(mark) + ' people have joined. Here is what that looks like right now:');
|
||||||
L.push('<a href="https://instantadpay.com/ledger">Live ledger</a>' + (cta ? ' \u00b7 <a href="' + cta + '">Join free</a>' : ''));
|
B.push('<b>' + n(s.wallets) + '</b> wallets linked\n'
|
||||||
return L.join('\n\n');
|
+ '<b>' + n(s.payoutsOn) + '</b> with payouts switched on\n'
|
||||||
|
+ '<b>' + n(s.lifeBuys) + '</b> purchases\n'
|
||||||
|
+ '<b>' + pol(s.lifePaidWei) + ' POL</b> paid to members\nin the same transactions');
|
||||||
|
B.push('Every one of those payments is on the public ledger.');
|
||||||
|
B.push('Thank you to every member who brought someone in. That is the whole engine, and it is working.');
|
||||||
|
B.push('The next ' + n(mark) + ' start today.');
|
||||||
|
} else {
|
||||||
|
B.push('Another hundred through the door.');
|
||||||
|
B.push('<b>' + n(s.wallets) + '</b> wallets linked\n'
|
||||||
|
+ '<b>' + n(s.payoutsOn) + '</b> with payouts on\n'
|
||||||
|
+ '<b>' + pol(s.lifePaidWei) + ' POL</b> paid to members');
|
||||||
|
B.push('Every payment on the public ledger.');
|
||||||
|
B.push('Next stop: <b>' + n(mark + STEP) + '</b>.');
|
||||||
|
}
|
||||||
|
B.push(ledger);
|
||||||
|
return B.join('\n\n');
|
||||||
}
|
}
|
||||||
async function memberCount() {
|
async function memberCount() {
|
||||||
if (!(X.db && X.db.enabled())) return 0;
|
if (!(X.db && X.db.enabled())) return 0;
|
||||||
@@ -132,7 +153,7 @@ async function milestoneTick() {
|
|||||||
const sc = X.siteConfig(); if (!sc.telegramBotToken) return null;
|
const sc = X.siteConfig(); if (!sc.telegramBotToken) return null;
|
||||||
const st = state(); const done = st.milestones || {};
|
const st = state(); const done = st.milestones || {};
|
||||||
const count = await memberCount();
|
const count = await memberCount();
|
||||||
const due = MILESTONES.filter(m => count >= m && !done[m]);
|
const due = marksUpTo(count).filter(m => !done[m]);
|
||||||
if (!due.length) return null;
|
if (!due.length) return null;
|
||||||
const mark = due[due.length - 1];
|
const mark = due[due.length - 1];
|
||||||
const text = composeMilestone(mark, await gather(), sc.telegramCtaUrl);
|
const text = composeMilestone(mark, await gather(), sc.telegramCtaUrl);
|
||||||
@@ -147,4 +168,4 @@ async function milestoneTick() {
|
|||||||
}
|
}
|
||||||
async function previewMilestone(mark) { const sc = X.siteConfig(); return composeMilestone(Number(mark) || 500, await gather(), sc.telegramCtaUrl); }
|
async function previewMilestone(mark) { const sc = X.siteConfig(); return composeMilestone(Number(mark) || 500, await gather(), sc.telegramCtaUrl); }
|
||||||
|
|
||||||
module.exports = { init, gather, compose, post, tick, preview, milestoneTick, previewMilestone, memberCount, MILESTONES };
|
module.exports = { init, gather, compose, post, tick, preview, milestoneTick, previewMilestone, composeMilestone, memberCount, MILESTONES, STEP };
|
||||||
|
|||||||
Reference in New Issue
Block a user