Member pages: send readers to the proof, not back to the same video
Marty spotted that a member's page played the angle video and then its button sent readers to /join/<id>?v=<angle> — which is a SQUEEZE step that shows that same video again before anything else. His instinct was to jump straight to /join-now. That fixes the replay but skips the proof layer: the live payout feed, the 2-4-8-16 explainer, the toolkit line and the sponsor card all live on the full invite page. Going from a personal story directly to "connect your wallet and send POL" is a big jump for somebody who arrived cold from a Traffic Desk banner. So the button now drops the ?v= and lands on the full invite page. The existing design already gives exactly the wanted behaviour — the squeeze step is skipped, the proof is kept, and no new parameter was needed. The QR deliberately keeps the angle: a scanned code often reaches someone who never saw the page, off a printout, and the hook video is what they need. Also: payout alerts now name what an upgrade unlocked, on upgrade pass-ups only. Marty noticed the toolkit was never mentioned — the unlock line was wired to `upgraded` events, which are rare next to payouts. On a pass-up the buyer below just climbed, so saying what they unlocked makes the reason for the payment concrete. Entry rewards stay silent: nobody changed level. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1500,7 +1500,16 @@ chain.startIndexer(evt=>{
|
||||
let text;
|
||||
if(evt.type==='registered')text=`📈 TEAM BUILD: new position!\n#${evt.id} registered under #${evt.referrerId} (${evt.tierName}).`;
|
||||
else if(evt.type==='upgraded'){const tl=suiteTools.unlockText(evt.level,evt.levelName,getConfig());text=`🚀 TEAM BUILD: #${evt.id} upgraded to ${evt.levelName}.${tl?`\n🧰 Unlocked: ${tl}.`:''}`;}
|
||||
else text=`💸 TEAM BUILD: #${evt.toId} just got PAID ${evt.pol.toFixed(2)} POL${evt.kind==='upline'?` (${evt.gen?`Gen ${evt.gen} `:''}upgrade pass-up from #${evt.fromId})`:` (referral reward from #${evt.fromId})`}.${contact(evt.toId)}`;
|
||||
else {
|
||||
// On an upgrade pass-up, say what the BUYER unlocked. This is the exact
|
||||
// moment "your level is your reach" is provable — someone below climbed,
|
||||
// and that is why this payment landed here. Upgrades are rare next to
|
||||
// payouts, so without this the toolkit is almost never mentioned.
|
||||
// Entry rewards get no tool line: nobody changed level.
|
||||
const upTools = evt.kind==='upline' ? suiteTools.unlockText(0,evt.levelName,getConfig()) : '';
|
||||
text=`💸 TEAM BUILD: #${evt.toId} just got PAID ${evt.pol.toFixed(2)} POL${evt.kind==='upline'?` (${evt.gen?`Gen ${evt.gen} `:''}upgrade pass-up from #${evt.fromId})`:` (referral reward from #${evt.fromId})`}.${contact(evt.toId)}`;
|
||||
if(upTools) text+=`\n🧰 #${evt.fromId} reached ${evt.levelName} and unlocked ${upTools}.`;
|
||||
}
|
||||
if(evt.tx)text+=`\nhttps://polygonscan.com/tx/${evt.tx}`;
|
||||
sendTelegram(text);
|
||||
// recruiting-framed copy of the SAME event to the new-members topic
|
||||
|
||||
+46
-2
@@ -47,6 +47,36 @@ function list(id) {
|
||||
return out;
|
||||
}
|
||||
|
||||
// How many pages a position may HOLD at once, by level (index = level - 1).
|
||||
// This is a different thing from the monthly BUILD quota in suite-meter: builds
|
||||
// are how often you may run the writer, this is how many pages you may keep.
|
||||
// They used to contradict each other — an Ascensus member was allowed 3 builds
|
||||
// a month but every build overwrote the same page, so they could never have
|
||||
// more than one. Anyone who can build a page can now keep several, because the
|
||||
// moment somebody thinks about two different audiences they want two pages.
|
||||
const PAGE_LIMIT = [0, 2, 3, 5, 8, 15, 25, 50];
|
||||
function pageLimit(level) {
|
||||
const lv = Math.max(1, Math.min(8, Number(level) || 1));
|
||||
return PAGE_LIMIT[lv - 1] || 0;
|
||||
}
|
||||
|
||||
// Slug from the headline the writer produced, so the address describes the page
|
||||
// without asking the member to invent one. Falls back to the angle, then to a
|
||||
// short random suffix, and always de-duplicates against what they already hold.
|
||||
function slugFromTitle(id, title, angle) {
|
||||
let base = slugify(title || '');
|
||||
if (base.length < 3) base = slugify(angle || 'page');
|
||||
if (!base) base = 'page';
|
||||
const taken = {};
|
||||
list(id).forEach(function (p) { if (p.slug) taken[p.slug] = 1; });
|
||||
if (!taken[base]) return base;
|
||||
for (let i = 2; i < 40; i++) {
|
||||
const c = slugify(base.slice(0, 20) + '-' + i);
|
||||
if (!taken[c]) return c;
|
||||
}
|
||||
return slugify(base.slice(0, 16) + '-' + Math.floor(Date.now() / 1000).toString(36));
|
||||
}
|
||||
|
||||
// Angles reuse the team's existing hook videos + their landing variant.
|
||||
const ANGLES = {
|
||||
pocket: { label: 'Pocket change', video: '/v/rmc-pocket-change-b403fb2f75.mp4', poster: '/v/rmc-pocket-change-poster.jpg' },
|
||||
@@ -119,6 +149,20 @@ function esc(s) {
|
||||
|
||||
function render(rec) {
|
||||
const a = ANGLES[rec.angle] || ANGLES.overview;
|
||||
// The button and the QR go to DIFFERENT places on purpose.
|
||||
//
|
||||
// `?v=<angle>` is not a normal landing page — it is a SQUEEZE step that hides
|
||||
// everything except the hook video and one button. A reader of this page has
|
||||
// just watched that exact video, so sending them there replayed it before
|
||||
// they could act. Dropping the `?v=` lands them on the full invite page
|
||||
// instead: payout feed, proof, sponsor card, join button. That is the proof
|
||||
// layer, and skipping straight past it to the payment screen would be too big
|
||||
// a jump for someone who arrived cold from an ad.
|
||||
//
|
||||
// The QR keeps the angle, because a scanned code often reaches somebody who
|
||||
// never saw this page — off a printout or a screenshot — and the hook video
|
||||
// is exactly what they need first.
|
||||
const joinLink = 'https://rmcircle.team/join/' + rec.id;
|
||||
const link = 'https://rmcircle.team/join/' + rec.id + (rec.angle && rec.angle !== 'overview' ? '?v=' + rec.angle : '');
|
||||
const who = esc(rec.name || ('Member #' + rec.id));
|
||||
const c = rec.copy || {};
|
||||
@@ -156,7 +200,7 @@ function render(rec) {
|
||||
story +
|
||||
(bullets ? '<ul>' + bullets + '</ul>' : '') +
|
||||
'<div class="cta"><p>' + esc(c.closing || 'Take a look and see what you think.') + '</p>' +
|
||||
'<a class="btn btn-primary" href="' + esc(link) + '">See how it works →</a>' +
|
||||
'<a class="btn btn-primary" href="' + esc(joinLink) + '">Join ' + who + ' →</a>' +
|
||||
'<div class="qr" id="ppQr" data-link="' + esc(link) + '"></div><div class="micro" style="color:var(--muted)">or scan · ' + esc(link.replace(/^https:\/\//, '')) + '</div></div>' +
|
||||
'<div class="foot">Independent team resource shared by an individual member. Participation takes real effort and involves cryptocurrency risk, including risk of total loss. No income is guaranteed. ' +
|
||||
'<a href="/disclaimer" style="color:var(--teal)">Disclaimers</a> · <a href="/contract" style="color:var(--teal)">How the contract works</a></div>' +
|
||||
@@ -166,4 +210,4 @@ function render(rec) {
|
||||
'</body></html>';
|
||||
}
|
||||
|
||||
module.exports = { init, load, save, remove, list, slugify, generate, render, ANGLES, parseSections };
|
||||
module.exports = { init, load, save, remove, list, slugify, slugFromTitle, pageLimit, PAGE_LIMIT, generate, render, ANGLES, parseSections };
|
||||
|
||||
@@ -101,7 +101,13 @@ async function notifyEvent(evt) {
|
||||
const chat = memberChat(evt.toId);
|
||||
if (!chat) return;
|
||||
const kind = evt.kind === 'upline' ? `${evt.gen ? `Gen ${evt.gen} ` : ''}upgrade pass-up from #${evt.fromId}` : `referral reward from #${evt.fromId}'s entry`;
|
||||
await dm(chat, `💰 You just caught ${evt.pol.toFixed(2)} POL — ${kind}.\nVerify: https://polygonscan.com/tx/${evt.tx}\n\nYour pipeline: https://rmcircle.team/my/${evt.toId}`);
|
||||
// Upgrade pass-up: tell the catcher what the person below just unlocked.
|
||||
// It makes the reason for the payment concrete, and it is a natural nudge
|
||||
// toward their own next rung without asking for anything.
|
||||
const upTools = evt.kind === 'upline' ? suiteTools.unlockText(0, evt.levelName, getConfig()) : '';
|
||||
await dm(chat, `💰 You just caught ${evt.pol.toFixed(2)} POL — ${kind}.` +
|
||||
(upTools ? `\n\n#${evt.fromId} reached ${evt.levelName}, which unlocked ${upTools} for them — and their climb is what put this on you.` : '') +
|
||||
`\nVerify: https://polygonscan.com/tx/${evt.tx}\n\nYour pipeline: https://rmcircle.team/my/${evt.toId}`);
|
||||
} else if (evt.type === 'upgraded') {
|
||||
// Congratulate the member who upgraded, and tell them what it opened up.
|
||||
const chat = memberChat(evt.id);
|
||||
|
||||
Reference in New Issue
Block a user