Members can change their username and email: in-place profile card replaces the separate alert-email opt-in for signed-in owners

The first-time gate cannot be dismissed; editing later can. The 'Email me my alerts' card becomes
'Your member profile' for a signed-in owner, showing the username and confirmed email with Change
buttons, so the verified address is the one source of truth for both messaging and payout alerts.
Visitors and non-owners keep the original opt-in form unchanged.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
martbost
2026-09-16 17:28:26 -05:00
parent 1ea8f8df48
commit 2c5fff20f5
3 changed files with 52 additions and 5 deletions
+28 -3
View File
@@ -9,7 +9,7 @@
// Usage: await window.RMCProfile.require(); // resolves once the profile is complete
(function () {
'use strict';
var back = null, resolveDone = null, state = null;
var back = null, resolveDone = null, state = null, editable = false;
var GOLD = '#d4af37', TEAL = '#4ed6cb';
function el(tag, css, html) {
@@ -35,13 +35,24 @@
'background:#0a1119;border:1px solid rgba(212,175,55,.55);box-shadow:0 24px 70px rgba(0,0,0,.7);' +
'font-family:system-ui,Segoe UI,Arial,sans-serif;color:#e8eef6;padding:22px 22px 20px;');
card.id = 'pgCard';
if (editable) { // editing an existing profile can be abandoned; the first-time gate can not
var x = el('button', 'position:absolute;top:10px;right:12px;z-index:2;width:34px;height:34px;border-radius:50%;border:none;' +
'cursor:pointer;background:rgba(255,255,255,.08);color:#fff;font-size:20px;line-height:1;font-weight:700;', '&times;');
x.setAttribute('aria-label', 'Close');
x.addEventListener('click', close);
card.appendChild(x);
back.addEventListener('click', function (e) { if (e.target === back) close(); });
}
back.appendChild(card);
document.body.appendChild(back);
return card;
}
function head(card, step) {
var keep = card.querySelector('button[aria-label="Close"]');
card.innerHTML = '';
if (keep) card.appendChild(keep);
if (editable) return card;
card.appendChild(el('div', 'text-align:center;letter-spacing:2px;text-transform:uppercase;font-size:11px;font-weight:700;color:' + GOLD + ';margin-bottom:8px;',
'Position #' + esc(state.id) + ' · step ' + step + ' of 2'));
return card;
@@ -79,6 +90,7 @@
try {
var r = await api('/api/public/profile/username', { username: i.value });
state.profile = r.profile;
if (editable) { close(); return; }
next();
} catch (e) {
err.textContent = e.message; err.style.display = 'block'; b.disabled = false; b.textContent = 'Save and continue';
@@ -130,6 +142,7 @@
try {
var r = await api('/api/public/profile/email-verify', { code: ci.value });
state.profile = r.profile;
if (editable) { close(); return; }
done();
} catch (e) {
err.textContent = e.message; err.style.display = 'block'; cb.disabled = false; cb.textContent = 'Confirm and finish';
@@ -154,7 +167,7 @@
function close() {
if (back && back.parentNode) back.parentNode.removeChild(back);
back = null;
if (resolveDone) { var r = resolveDone; resolveDone = null; r(state && state.profile); }
if (resolveDone) { var r = resolveDone; resolveDone = null; r((state && state.profile) || null); }
}
function next() {
if (!state.profile || !state.profile.username) return stepUsername();
@@ -179,6 +192,18 @@
return new Promise(function (res) { resolveDone = res; next(); });
}
async function status() { try { return await api('/api/public/profile'); } catch (e) { return null; } }
// Change an existing username or email. Dismissable, unlike the first-time gate.
// Resolves with the profile when saved, or null if the member closed it.
async function edit(kind) {
if (back) return null;
try { state = await api('/api/public/profile'); } catch (e) { return null; }
if (!state || state.signedIn === false) return null;
editable = true;
shell();
var p = new Promise(function (res) { resolveDone = res; });
if (kind === 'email') stepEmail(); else stepUsername();
var out = await p; editable = false; return out;
}
window.RMCProfile = { require: require_, status: status };
window.RMCProfile = { require: require_, status: status, edit: edit };
})();