邀請好友,賺 e幣

分享你的邀請碼,你得 500 e幣,朋友得 100 e幣。

① 我的邀請碼

ABCD-23
https://eclawbot.com/invite/ABCD23

② 邀請儀表板

3
累計邀請
1,500
獲得 e幣
12
今日使用
33%
轉換率
62 / 100

過去 30 天使用量

③ 獎勵說明

你獲得+500 e幣
好友獲得+100 e幣
朋友首次儲值獎勵(你)+500 e幣

④ 階級與里程碑

目前階級
青銅邀請者
🥉
青銅(1 位好友)
✓ 解鎖
白銀(5 位好友)
+1000 e幣
黃金(10 位好友)
+3000 e幣

⑤ 兌換邀請碼

🔧 這次 PR 動到的 UI — before / after

為了修 invite 0/8 轉換率,後端加了 /invite/:code redirect(原本 404)+ 前端在 invite.html DOMContentLoaded 加 5 行 JS 把 ?redeem=CODE 自動填入 input。UI 視覺本身完全沒改,只有行為改了。

BEFORE

1. 分享連結行為

https://eclawbot.com/invite/ABCD23
💀
Cannot GET /invite/ABCD23

Express 預設 404 — 零路由,所有分享出去的碼都是死的

2. 兌換框(直接進 portal 的話)

有邀請碼?

↑ 空白,使用者要手動從訊息裡抄

AFTER

1. 分享連結行為

https://eclawbot.com/invite/ABCD23
1. 302 Redirect (+ 寫 click log)
2. /portal/invite.html?redeem=ABCD23
✓ 落地頁正常渲染 + 兌換框已預填

2. 兌換框(從分享連結進來)

有邀請碼?

↑ 自動填入,使用者一按兌換就完成

展開:動到的 code(完整 diff)
+ // index.js (新增路由)
+ app.get('/invite/:code', async (req, res) => {
+     const raw = String(req.params.code || '').toUpperCase();
+     const code = /^[A-Z0-9]{4,12}$/.test(raw) ? raw : null;
+     if (!code) return res.redirect(302, '/portal/invite.html');
+     // best-effort click log (PII-hashed IP, 不擋 redirect)
+     try { await db.logInviteClick({ code, ipHash, userAgent, referer }); } catch {}
+     return res.redirect(302, `/portal/invite.html?redeem=${encodeURIComponent(code)}`);
+ });

  // public/portal/invite.html DOMContentLoaded 裡面加 5 行:
  window.addEventListener('DOMContentLoaded', async () => {
      const _params = new URLSearchParams(window.location.search);
      const _isEmbed = _params.get('embed') === '1' || window.self !== window.top;
      if (_isEmbed) document.body.classList.add('embed-mode');
+     const _redeemParam = (_params.get('redeem') || '').toUpperCase()
+         .replace(/[^A-Z0-9]/g, '').slice(0, 12);
+     if (_redeemParam) {
+         const _input = document.getElementById('redeemInput');
+         if (_input) _input.value = _redeemParam;
+     }
      renderNav('settings');
      ...
  });

  // invite.html 的 HTML (input 本身完全沒動):
  <div class="inv-redeem">
      <input id="redeemInput" placeholder="ABCDEF" maxlength="8">
      <button onclick="redeemCode()">兌換</button>
  </div>

🐞 zh-CN 字典 bug — 簡繁混雜範例(實測頁面看到的)

下面是今天從線上頁面抓下來的真實渲染字串,這不是邀請頁獨有,而是 i18n.zh-CN 全站字典的問題。

繁體直接當簡體用(應該翻成簡體)

key: inv_dashboard儀表板
key: inv_invite_friends邀請好友
key: inv_copy複製
key: inv_qr_gen_cta產生分享圖
key: invite_stats_kpi_conversion轉換率
key: inv_you_get你獲得
key: topup_btn儲值
key: footer_privacy隱私權政策

🚨 單字串內簡繁混寫(最糟)

key: inv_earn_coin赚取 e幣
 (赚=簡,幣=繁)應:賺取 e幣 (繁) / 赚取 e币 (簡)
key: topbar_info资訊
 (资=簡,訊=繁)應:資訊 (繁) / 资讯 (簡)
key: invite_stats_timeline_title过去 30 天
 (过=簡,其他繁)應:過去 30 天 (繁)
key: inv_rewards_title獎勵说明
 (獎勵=繁,说=簡)應:獎勵說明 (繁) / 奖励说明 (簡)
key: inv_tier_title阶級与里程碑
 (阶/与=簡,級=繁)應:階級與里程碑 (繁)
key: faq_title常見問题
 (見=繁,题=簡)應:常見問題 (繁) / 常见问题 (簡)

推測成因:zh-CN 字典是從 zh-TW 字典複製過來後只翻了一部分 key(或機翻工具吃到半個字串就漏字)。影響範圍:全站,不是只有邀請頁。
建議:另開一張 P2 卡做 zh-CN 字典全面清洗(or 直接用 OpenCC zh-TW → zh-CN 自動轉一次當 baseline)。