Sponsor shown on sign-in + new-member onboarding (username, optional profile)
- Sign-in page shows "You're joining the line of @X" when arriving via a sponsor link (/api/sponsor now returns the sponsor name + avatar). - After a new account verifies (or signs up) with no username yet, an onboarding modal prompts for a username and an optional bio (both skippable), before the welcome tour. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+30
-2
@@ -11,6 +11,13 @@
|
||||
}
|
||||
if (c.rehearsal && $('faucetCard')) $('faucetCard').hidden = false;
|
||||
} catch (e) {}
|
||||
// if they arrived through a sponsor's link, show who they're joining under
|
||||
(async () => {
|
||||
try {
|
||||
const sp = await (await fetch('/api/sponsor')).json();
|
||||
if (sp && sp.invited && sp.name && $('sponsorNote')) { $('sponsorNoteName').textContent = sp.name; $('sponsorNote').hidden = false; }
|
||||
} catch (e) {}
|
||||
})();
|
||||
|
||||
async function api(path, body) {
|
||||
const r = await (await fetch(path, { method: 'POST',
|
||||
@@ -1255,16 +1262,37 @@
|
||||
IAP.status('Fresh code sent.', 'ok');
|
||||
}));
|
||||
$('mcVerifyBtn').addEventListener('click', busy($('mcVerifyBtn'), async () => {
|
||||
await api('/api/auth/email/verify', { email: $('mcEmail').value, code: $('mcCode').value });
|
||||
const r = await api('/api/auth/email/verify', { email: $('mcEmail').value, code: $('mcCode').value });
|
||||
IAP.status('You are in.', 'ok');
|
||||
if (r.created && !(r.account && r.account.username)) await showOnboard(); // pick a username first
|
||||
if (!(await showGauntlet())) await showLoginAd(); // welcome tour outranks the login ad
|
||||
await render();
|
||||
}));
|
||||
})();
|
||||
|
||||
// new-member onboarding: choose a username, optionally a bio (both skippable)
|
||||
function showOnboard() {
|
||||
return new Promise(resolve => {
|
||||
const m = $('onboardModal'); if (!m) return resolve();
|
||||
m.hidden = false; $('obErr').hidden = true;
|
||||
const done = () => { m.hidden = true; resolve(); };
|
||||
$('obSkip').onclick = done;
|
||||
$('obSave').onclick = async () => {
|
||||
const u = $('obUsername').value.trim();
|
||||
try {
|
||||
if (u) await api('/api/my/profile', { username: u });
|
||||
const bio = $('obBio').value.trim();
|
||||
if (bio) await api('/api/my/profile-details', { bio });
|
||||
done();
|
||||
} catch (e) { $('obErr').hidden = false; $('obErr').textContent = e.message || 'Could not save that. Try a different username.'; }
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
$('signupBtn').addEventListener('click', busy($('signupBtn'), async () => {
|
||||
await api('/api/signup', { email: $('suEmail').value, password: $('suPass').value });
|
||||
const r = await api('/api/signup', { email: $('suEmail').value, password: $('suPass').value });
|
||||
IAP.status('Welcome aboard. You are in.', 'ok');
|
||||
if (!(r.account && r.account.username)) await showOnboard();
|
||||
await render();
|
||||
}));
|
||||
$('loginBtn').addEventListener('click', busy($('loginBtn'), async () => {
|
||||
|
||||
+23
-1
@@ -17,6 +17,10 @@
|
||||
<p class="lead" id="introLead" style="font-size:16px">Join free with your email. Your wallet only
|
||||
comes out when you buy a package or switch on payouts, and it stays yours the whole time.</p>
|
||||
</section>
|
||||
<div class="card" id="sponsorNote" style="border-color:var(--mint);text-align:center" hidden>
|
||||
<p style="margin:0"><span class="muted small">You're joining the line of</span><br>
|
||||
<b id="sponsorNoteName" style="font-size:19px;color:var(--mint)"></b></p>
|
||||
</div>
|
||||
<div class="card" id="magicCard" hidden>
|
||||
<h3>Sign in or join free</h3>
|
||||
<p class="muted small">Type your email and we send a 6-digit code. No password to invent,
|
||||
@@ -82,6 +86,24 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ── onboarding: new members pick a username (profile optional) ── -->
|
||||
<div id="onboardModal" class="modal-back" hidden>
|
||||
<div class="modal-card">
|
||||
<p class="eyebrow">Welcome to InstantAdPay</p>
|
||||
<h3 style="margin:.2em 0 .5em">Pick your username</h3>
|
||||
<p class="muted small">This is how your team sees you, and it turns your invite link into a clean vanity link.
|
||||
You can change it later in Profile.</p>
|
||||
<p><input id="obUsername" placeholder="Username (3-20 letters, numbers, _)" autocomplete="off" style="width:100%"></p>
|
||||
<p class="muted small" style="margin:12px 0 4px">Optional — a short bio for your public page (you can skip this).</p>
|
||||
<p><textarea id="obBio" rows="2" maxlength="600" placeholder="A short bio (optional)" style="width:100%"></textarea></p>
|
||||
<p id="obErr" class="small" style="color:var(--bad)" hidden></p>
|
||||
<p style="margin-top:14px;display:flex;gap:10px;justify-content:flex-end">
|
||||
<button class="btn sec small" id="obSkip" type="button">Skip for now</button>
|
||||
<button class="btn" id="obSave" type="button">Save & continue</button>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ── sponsor message modal: unmissable on sign-in ── -->
|
||||
<div id="msgModal" class="modal-back" hidden>
|
||||
<div class="modal-card">
|
||||
@@ -644,7 +666,7 @@
|
||||
</div>
|
||||
<script src="/assets/common.js?v=20260907n"></script>
|
||||
<script src="/assets/wallet.js?v=20260907q"></script>
|
||||
<script src="/assets/my.js?v=20260907p"></script>
|
||||
<script src="/assets/my.js?v=20260907r"></script>
|
||||
<script src="/assets/chat.js?v=20260907l"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user