Email notifications (welcome + payout + passed-up) and net->network label
- Welcome email on new account: onboarding steps + who their sponsor is. - On-chain event emails: a payout received (TierPaid/AwardPaid) and a payout that passed you by unqualified (PassedUp), wired into the chain event stream. - Campaign stats: "+N net" relabeled to "+N network" (clearer than "net"). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -121,7 +121,7 @@ async function frameCheck(url) {
|
||||
}
|
||||
async function boot() {
|
||||
await db.init({ dataDir: DATA_DIR }); // no-op without DATABASE_URL (JSON mode)
|
||||
chain.init({ onEvent: ev => attachNames([ev]).then(a => pushFeed(a[0])).catch(() => pushFeed(ev)) });
|
||||
chain.init({ onEvent: ev => { attachNames([ev]).then(a => pushFeed(a[0])).catch(() => pushFeed(ev)); emailOnEvent(ev).catch(() => {}); } });
|
||||
auth.init({ dataDir: DATA_DIR, chain, isProd: IS_PROD, site: 'instantadpay.com' });
|
||||
accounts.init({ dataDir: DATA_DIR });
|
||||
ads.init({ dataDir: DATA_DIR, chain });
|
||||
@@ -245,6 +245,35 @@ async function nudgeReferrer(ref) {
|
||||
+ 'https://instantadpay.com/my\n\nInstantAdPay').catch(e => console.error('nudge failed', e.message));
|
||||
} catch (e) {}
|
||||
}
|
||||
// welcome email on a new account: onboarding steps + who their sponsor is
|
||||
async function sendWelcome(email, ref) {
|
||||
try {
|
||||
if (!mailer.hasKey()) return;
|
||||
const spon = await accounts.sponsorOf(email);
|
||||
const who = spon ? (spon.username ? '@' + spon.username : 'member #' + (spon.memberId || 0)) : '';
|
||||
const sponsorLine = who ? ('You joined through ' + who + ', your sponsor. They are there to help you get started, and you can message them anytime from your dashboard.\n\n') : '';
|
||||
mailer.send(email, 'Welcome to InstantAdPay',
|
||||
'Your free InstantAdPay account is ready.\n\n' + sponsorLine
|
||||
+ 'Getting started:\n'
|
||||
+ '1. Pick your username and fill out your profile.\n'
|
||||
+ '2. Grab your invite link and start sharing to build your line.\n'
|
||||
+ '3. Explore the ad packages when you are ready. Every payout settles on-chain, straight to your wallet.\n\n'
|
||||
+ 'Sign in anytime: https://instantadpay.com/my\n\nInstantAdPay').catch(() => {});
|
||||
} catch (e) {}
|
||||
}
|
||||
// on-chain event emails: a payout received, or a payout that passed you by
|
||||
const weiToPol = w => { try { return (Number(BigInt(w) / (10n ** 14n)) / 10000).toString(); } catch (e) { return '?'; } };
|
||||
async function emailOnEvent(ev) {
|
||||
if (!mailer.hasKey() || !ev) return;
|
||||
const notify = async (memberId, subject, body) => {
|
||||
if (!memberId) return;
|
||||
const a = await accounts.byMemberId(memberId);
|
||||
if (a && a.email) mailer.send(a.email, subject, body + '\n\nSee it on the live ledger: https://instantadpay.com/ledger\n\nInstantAdPay').catch(() => {});
|
||||
};
|
||||
if (ev.type === 'TierPaid') await notify(ev.recipientId, 'You just got paid on InstantAdPay', 'A level-' + ev.tier + ' payout of ' + weiToPol(ev.amountWei) + ' POL just landed in your wallet.');
|
||||
else if (ev.type === 'AwardPaid') await notify(ev.toId, 'You just got paid on InstantAdPay', weiToPol(ev.amountWei) + ' POL just landed in your wallet.');
|
||||
else if (ev.type === 'PassedUp') await notify(ev.skippedId, 'A payout passed you by on InstantAdPay', 'A level-' + ev.tier + ' payout passed you by because you were not qualified yet. Get qualified so you catch the next one.');
|
||||
}
|
||||
|
||||
// ---- live feed (SSE) ----
|
||||
const feedClients = new Set();
|
||||
@@ -389,7 +418,7 @@ const server = http.createServer(async (req, res) => {
|
||||
const ref = parseCookies(req)['iap.sponsor'] || '';
|
||||
const r = await accounts.ensure(e, ref); // first touch wins; existing accounts unchanged
|
||||
if (r.error) return json(res, 400, r);
|
||||
if (r.created) nudgeReferrer(ref).catch(() => {});
|
||||
if (r.created) { nudgeReferrer(ref).catch(() => {}); sendWelcome(e, ref).catch(() => {}); }
|
||||
let memberId = 0;
|
||||
if (r.account.address) { try { memberId = await chain.memberIdByAccount(r.account.address); } catch (err) {} }
|
||||
const token = await auth.mintSession({ email: r.account.email, address: r.account.address, memberId });
|
||||
|
||||
Reference in New Issue
Block a user