Founding week: /launch leader checklist (8 live-read items incl. the level-3 leader play), dashboard launch-ready mark, launchAt setting
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
+39
-1
@@ -167,5 +167,43 @@ window.IAP = (function () {
|
||||
throw new Error('Could not verify. Refresh the page and try again.');
|
||||
}
|
||||
const esc = s => String(s == null ? '' : s).replace(/[&<>"]/g, c => ({ '&': '&', '<': '<', '>': '>', '"': '"' }[c]));
|
||||
return { getConfig, fmtPol, fmtUsd, status, renderNav, refreshNavWallet, describeEvent, feedRow, adSlot, reportAd, requestCode, $ };
|
||||
// ── founding-week checklist, read from the live account. Shared by /launch and
|
||||
// the dashboard mark. Two items are the member's own call and persist locally.
|
||||
const LAUNCH_KEY = 'iap.launch.manual';
|
||||
const manualSet = () => { try { return new Set(JSON.parse(localStorage.getItem(LAUNCH_KEY) || '[]')); } catch (e) { return new Set(); } };
|
||||
function launchToggle(key) { const s = manualSet(); if (s.has(key)) s.delete(key); else s.add(key); try { localStorage.setItem(LAUNCH_KEY, JSON.stringify([...s])); } catch (e) {} }
|
||||
function launchChecks(me) {
|
||||
const m = me || {}, man = manualSet();
|
||||
const bc = Number(m.buyerCount || 0), refs = (m.referrals || []).length;
|
||||
return [
|
||||
{ key: 'username', title: 'Pick your username', done: !!m.username, href: '/my#profile', cta: 'Profile',
|
||||
how: 'Profile tab. It becomes your invite link and your public page, and it is permanent.',
|
||||
why: 'Every link, banner and video you hand out this week carries it. Change it later and the links you already sent die.' },
|
||||
{ key: 'wallet', title: 'Link your wallet', done: !!m.address, href: '/my#wallet', cta: 'Wallet',
|
||||
how: 'Wallet tab, Connect, sign the free message. MetaMask recommended. Never held crypto? The wallet guide in Training walks through buying POL with a card.',
|
||||
why: 'Payouts go to this address. No wallet, nowhere to pay you.' },
|
||||
{ key: 'payouts', title: 'Switch on payouts', done: !!m.memberId, href: '/my#wallet', cta: 'Wallet',
|
||||
how: 'Wallet tab, one small transaction. It registers your address with the contract.',
|
||||
why: 'The contract binds each buyer to their sponsor at their first purchase. If payouts are off when your first person buys, that commission is not yours.' },
|
||||
{ key: 'level2', title: 'Qualify: open level 2', done: bc >= 2, href: '/my#buy', cta: 'Buy packages',
|
||||
how: 'Two of your people buy a $20 or more package. Or use Qualified Start: add two positions from extra wallets in your own MetaMask and buy a $20 package from each (about $23 of POL in each wallet).',
|
||||
why: 'Until you have two qualifying buyers, every level 2 payment from your team climbs past you.',
|
||||
note: 'Qualifying buyers so far: <b>' + bc + '</b> of 2.' },
|
||||
{ key: 'level3', title: 'The leader play: open all three levels', done: bc >= 5, href: '/my#buy', cta: 'Qualified Start',
|
||||
how: 'Five qualifying buyers, real or Qualified Start, up to five linked positions. Once qualified, buy from your main wallet so your sponsor is paid in full.',
|
||||
why: 'A leader whose team goes three deep this week collects level 3 from day one instead of watching those 10% payments pass upward. Optional for members, the play for leaders.',
|
||||
note: 'Qualifying buyers so far: <b>' + bc + '</b> of 5.' },
|
||||
{ key: 'banner', title: 'Upload your line banner', done: !!m.lineBannerUrl, href: '/my#profile', cta: 'Profile',
|
||||
how: 'Profile tab, line banner. It shows on the welcome tour to everyone in your next three levels.',
|
||||
why: 'Your first advertising to your own team, free, and it is live the moment they join.' },
|
||||
{ key: 'links', title: 'Copy your links and pick a play', done: man.has('links'), manual: true,
|
||||
how: 'Promo tools, Your links: the invite link and the five angle links, plus the matching hook videos. Then read the plays page and choose one.',
|
||||
why: 'On launch day you send links, not explanations. Having them ready is the whole difference between a launch and a scramble.' },
|
||||
{ key: 'two', title: 'Place your first two', done: refs >= 2, href: '/my#line', cta: 'My line',
|
||||
how: 'Two people you have actually talked to, joined through your link, walked through items 1 to 3 on their own accounts.',
|
||||
why: 'Your first two are the shape of your whole line. Choose them, do not wait for them.',
|
||||
note: 'Joined through you so far: <b>' + refs + '</b>.' }
|
||||
];
|
||||
}
|
||||
return { getConfig, fmtPol, fmtUsd, status, renderNav, refreshNavWallet, describeEvent, feedRow, adSlot, reportAd, requestCode, launchChecks, launchToggle, $ };
|
||||
})();
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
// Founding week checklist: members only; every item reads from the live account
|
||||
// (IAP.launchChecks in common.js is shared with the dashboard's "launch ready" mark).
|
||||
(async function () {
|
||||
const $ = id => document.getElementById(id);
|
||||
try { await IAP.renderNav('training'); } catch (e) {}
|
||||
let me = null, cfg = {};
|
||||
try { me = await (await fetch('/api/me')).json(); } catch (e) {}
|
||||
try { cfg = await IAP.getConfig(); } catch (e) {}
|
||||
const signedIn = !!(me && me.signedIn && me.email);
|
||||
$('gate').style.display = signedIn ? 'none' : 'block';
|
||||
$('body').style.display = signedIn ? 'block' : 'none';
|
||||
if (!signedIn) return;
|
||||
const pb = $('printBtn'); if (pb) pb.addEventListener('click', () => window.print());
|
||||
const tok = me.username || me.refCode || me.memberId;
|
||||
if (tok) document.querySelectorAll('[data-link]').forEach(el => { el.textContent = location.origin + '/join/' + tok; });
|
||||
|
||||
// launch moment (admin: Settings > launchAt, ISO 8601 with offset)
|
||||
const at = cfg.launchAt ? new Date(cfg.launchAt) : null;
|
||||
if (at && !isNaN(at)) {
|
||||
$('lwWhen').hidden = false;
|
||||
$('lwWhenAt').textContent = at.toLocaleString([], { weekday: 'short', month: 'short', day: 'numeric', hour: 'numeric', minute: '2-digit' });
|
||||
const tick = () => { const ms = at - Date.now(); if (ms <= 0) { $('lwWhenIn').textContent = 'doors are open'; return; }
|
||||
const d = Math.floor(ms / 86400000), h = Math.floor(ms % 86400000 / 3600000), m = Math.floor(ms % 3600000 / 60000);
|
||||
$('lwWhenIn').textContent = (d ? d + 'd ' : '') + h + 'h ' + m + 'm to go'; };
|
||||
tick(); setInterval(tick, 30000);
|
||||
}
|
||||
|
||||
function render() {
|
||||
const items = IAP.launchChecks(me);
|
||||
const done = items.filter(i => i.done).length;
|
||||
$('lwDone').textContent = done; $('lwBar').style.width = Math.round(done / items.length * 100) + '%';
|
||||
$('chk').innerHTML = items.map((i, n) => '<li class="' + (i.done ? 'done' : '') + '"><div class="box">' + (i.done ? '✓' : (n + 1)) + '</div>'
|
||||
+ '<div><h3>' + i.title + '</h3><p>' + i.how + '</p><div class="why">' + i.why + '</div>' + (i.note ? '<p class="small" style="margin-top:4px">' + i.note + '</p>' : '') + '</div>'
|
||||
+ '<div class="act">' + (i.manual ? '<button class="btn small ' + (i.done ? 'sec' : '') + '" type="button" data-manual="' + i.key + '">' + (i.done ? 'Undo' : 'Mark done') + '</button>' : '<a class="btn small sec" href="' + i.href + '">' + i.cta + '</a>') + '</div></li>').join('');
|
||||
$('chk').querySelectorAll('[data-manual]').forEach(b => b.addEventListener('click', () => { IAP.launchToggle(b.dataset.manual); render(); }));
|
||||
}
|
||||
render();
|
||||
})();
|
||||
@@ -421,6 +421,14 @@
|
||||
// ready-to-send share message + promo tools, personalized
|
||||
const link = location.origin + '/join/' + (d.username || d.refCode || d.memberId || '');
|
||||
fillPromo(link, d);
|
||||
// founding-week readiness: shown until every item is done (or the launch moment is a week past)
|
||||
try {
|
||||
const cfg = await IAP.getConfig(); const items = IAP.launchChecks(d); const done = items.filter(i => i.done).length;
|
||||
const at = cfg.launchAt ? new Date(cfg.launchAt).getTime() : 0;
|
||||
const show = done < items.length && !(at && Date.now() > at + 7 * 86400000);
|
||||
const lm = $('launchMark');
|
||||
if (lm) { lm.hidden = !show; lm.innerHTML = show ? '<b>Launch ready: ' + done + ' of ' + items.length + '.</b> ' + (at && Date.now() < at ? 'Doors open ' + new Date(at).toLocaleString([], { weekday: 'short', hour: 'numeric', minute: '2-digit' }) + '. ' : '') + '<a href="/launch">Open the founding-week checklist</a>' : ''; }
|
||||
} catch (e) {}
|
||||
if (d.username) { // wall link rides the username
|
||||
const wl = location.origin + '/wall/' + d.username;
|
||||
$('wallLine').textContent = wl;
|
||||
|
||||
Reference in New Issue
Block a user