Add dormant public direct-join fallback (/join-now) + post-join redirect

/join-now: public self-enroll page gated behind config.dappFallbackPublic
(default off -> redirects to /start, invisible until needed). Auto-assigns the
current rotation sponsor via /api/public/current-sponsor, registers the user's
own wallet, then redirects to /my/<newId> so new members land on their live
position instead of guessing their ID. HTML lives in private/, served only via
the flagged route. Reuses the proven contract engine. Admin /direct-join now
also shows a 'View position ->' link to /my/<newId> after a successful join.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
martbost
2026-08-18 07:09:57 -05:00
parent 962eacd44c
commit e14c541e5e
5 changed files with 169 additions and 4 deletions
+1
View File
@@ -68,6 +68,7 @@
<div style="font-size:12px;text-transform:uppercase;letter-spacing:.12em;color:var(--ok);font-weight:800">✅ Success — save this</div>
<div id="resultId" style="font-size:46px;font-weight:900;color:var(--gold);margin:6px 0;letter-spacing:-1px">—</div>
<div id="resultSub" style="color:var(--muted);font-size:14px"></div>
<a id="resultLink" class="btn btn-primary btn-sm" href="/my" style="display:none;margin-top:12px">View position →</a>
</div>
<div class="dj-card">
+52
View File
@@ -0,0 +1,52 @@
<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><meta name="robots" content="noindex"><title>Join the Team | RM Circle</title><link rel="stylesheet" href="/styles.css">
<style>
.dj-wrap{width:min(720px,calc(100% - 32px));margin:22px auto 70px}
.dj-card{background:var(--card,#0b1e30);border:1px solid var(--line);border-radius:16px;padding:20px 22px;margin:0 0 16px}
.dj-mono{font-family:ui-monospace,Menlo,Consolas,monospace;font-size:13px;color:var(--gold);word-break:break-all}
.dj-kv{display:flex;justify-content:space-between;gap:12px;padding:8px 0;border-bottom:1px solid var(--line);font-size:14px}
.dj-kv:last-child{border-bottom:0}.dj-kv b{color:var(--text)}
.dj-log{font-size:13px;line-height:1.5;padding:8px 10px;border-left:2px solid var(--line);margin:6px 0;color:var(--muted);background:#08192880}
.dj-log.ok{border-color:var(--ok);color:#cfeede}.dj-log.err{border-color:var(--danger);color:#f3b7ac}
#logWrap{max-height:220px;overflow:auto}
</style></head>
<body>
<header class="wrap nav"><a class="brand" href="/"><div class="brand-mark">RM</div><span><span>RM Circle</span><small>Join the Team</small></span></a><div class="nav-actions"><a class="btn btn-secondary btn-sm hide-mobile" href="/training">Training</a><a class="btn btn-secondary btn-sm" href="/">How it works</a></div></header>
<main class="dj-wrap">
<div class="section-head" style="margin:6px 0 18px"><div class="eyebrow">Direct enrollment</div><h1 style="font-size:clamp(28px,5vw,40px);margin:8px 0 8px">Join the <span class="gold">RM Circle</span> team.</h1><p style="color:var(--muted);font-size:16px;line-height:1.6;margin:0">Connect your wallet and enter your Premium position on the Polygon smart contract — paid straight from your wallet, verifiable on-chain. You’ll be placed under the current team position automatically. New here? Watch the <a href="/training" style="color:var(--teal)">training</a> first.</p></div>
<div class="dj-card"><p id="sponsorLine" style="margin:0;color:var(--muted);font-size:15px">Loading the current team placement…</p></div>
<div class="dj-card">
<h2 style="margin:0 0 10px;font-size:18px">1 · Connect your wallet</h2>
<p style="color:var(--muted);font-size:14px;margin:0 0 14px">Use MetaMask or Trust Wallet on <strong>Polygon</strong>, funded with enough POL for your Premium entry plus a little gas.</p>
<button id="connectBtn" class="btn btn-primary">Connect wallet</button>
<div id="connected" style="display:none">
<div class="dj-kv"><span>Wallet</span><b id="wallet" class="dj-mono">—</b></div>
<div class="dj-kv"><span>Network</span><b>Polygon Mainnet ✓</b></div>
<div class="dj-kv"><span>Balance</span><b id="bal">—</b></div>
</div>
<div id="already" style="display:none;margin-top:12px;color:#f0b4aa;font-size:14px"></div>
</div>
<div id="joinBox" class="dj-card" style="display:none">
<h2 style="margin:0 0 10px;font-size:18px">2 · Join</h2>
<div class="dj-kv"><span>Tier</span><b>Premium (the tier the team builds at)</b></div>
<div class="dj-kv"><span>You will pay</span><b id="joinCost">—</b></div>
<button id="joinBtn" class="btn btn-primary" style="margin-top:14px;width:100%">Join the team →</button>
<p style="color:var(--muted);font-size:12px;margin:10px 0 0">Confirm the amount in your wallet before signing. If anything is off, the contract simply rejects it and you keep your POL.</p>
</div>
<div id="result" class="dj-card" style="display:none;border-color:var(--ok);background:rgba(123,224,161,.08);text-align:center">
<div style="font-size:12px;text-transform:uppercase;letter-spacing:.12em;color:var(--ok);font-weight:800">✅ You’re in — this is your position</div>
<div id="resultId" style="font-size:46px;font-weight:900;color:var(--gold);margin:6px 0;letter-spacing:-1px">—</div>
<div id="resultSub" style="color:var(--muted);font-size:14px;margin-bottom:12px"></div>
<a id="resultLink" class="btn btn-primary" href="/my" style="display:none">View your position →</a>
</div>
<div class="dj-card"><h2 style="margin:0 0 8px;font-size:15px">Activity</h2><div id="logWrap"><div id="log"></div></div></div>
<p class="micro" style="text-align:center">No income is guaranteed. Cryptocurrency and smart-contract participation carry risk. Only use funds you can afford to lose.</p>
</main>
<footer class="wrap disclaimer">All figures are read live from the RM Circle smart contract on Polygon. Not an earnings guarantee or investment advice. Participation carries risk of loss.<div class="footer-links"><a href="/">Home</a><a href="/training">Training</a><a href="/how-pay-works">How You Get Paid</a><a href="/contract">Contract Security</a><a href="/disclaimer">Disclaimers</a></div></footer>
<script src="/join-now.js"></script></body></html>