Wall ownership ladder: positions 2 and 3 become the member's own at 2 / 5 qualifying buyers

- accounts.wall_offers (JSON, up to 2 offers: label, https link, banner) set from
  Profile > Your wall; upload supported; locks show the buyer threshold.
- /api/wall assembles: position 1 = own line banner; positions 2-3 = own offer
  when unlocked and set, else upline banners (only uplines with a live banner),
  else house ads. Response carries unlocked + buyerCount; wall labels show
  "this wall" / "their line" / "InstantAdPay".
- Chatbot canned answer + facts, follow-up email 7 mention the ladder.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
martbost
2026-09-09 15:31:45 -05:00
parent 8b25361eef
commit 2ac6549171
21 changed files with 192 additions and 69 deletions
+13 -2
View File
@@ -34,7 +34,7 @@ function newCode(taken) {
}
const pub = a => a ? { email: a.email, sponsorRef: a.sponsorRef || '', code: a.code || null,
username: a.username || null, memberId: a.memberId || 0, joinedVia: a.joinedVia || null,
lineBannerUrl: a.lineBannerUrl || null, lineTargetUrl: a.lineTargetUrl || null,
lineBannerUrl: a.lineBannerUrl || null, lineTargetUrl: a.lineTargetUrl || null, wallOffers: a.wallOffers || null,
avatarUrl: a.avatarUrl || null, bio: a.bio || null, socials: a.socials || null,
chatAvailable: a.chatAvailable === false ? false : true, lastSeen: a.lastSeen || 0,
address: a.address || null, created: a.created } : null;
@@ -109,6 +109,12 @@ const J = {
this.save();
return { ok: true, account: pub(acct) };
},
async setWallOffers(e, json) {
const acct = this.db.byEmail[e];
if (!acct) return { error: 'No such account.' };
acct.wallOffers = json || null; this.save();
return { ok: true, account: pub(acct) };
},
async setProfile(e, avatarUrl, bio, socials) {
const acct = this.db.byEmail[e];
if (!acct) return { error: 'No such account.' };
@@ -172,7 +178,7 @@ const J = {
// ---- MySQL mode ----
const rowPub = r => r ? pub({ email: r.email, sponsorRef: r.sponsor_ref, code: r.code,
username: r.username, memberId: r.member_id || 0, joinedVia: r.joined_via || null,
lineBannerUrl: r.line_banner_url, lineTargetUrl: r.line_target_url,
lineBannerUrl: r.line_banner_url, lineTargetUrl: r.line_target_url, wallOffers: r.wall_offers || null,
avatarUrl: r.avatar_url, bio: r.bio, socials: r.socials,
chatAvailable: r.chat_available === 0 ? false : true, lastSeen: Number(r.last_seen || 0),
address: r.address, created: Number(r.created) }) : null;
@@ -224,6 +230,10 @@ const D = {
await db.q('UPDATE accounts SET line_banner_url=?, line_target_url=? WHERE email=?', [bannerUrl || null, targetUrl || null, e]);
return { ok: true, account: await this.byEmail(e) };
},
async setWallOffers(e, json) {
await db.q('UPDATE accounts SET wall_offers=? WHERE email=?', [json || null, e]);
return { ok: true, account: await this.byEmail(e) };
},
async setProfile(e, avatarUrl, bio, socials) {
if (avatarUrl !== undefined) await db.q('UPDATE accounts SET avatar_url=? WHERE email=?', [avatarUrl || null, e]);
if (bio !== undefined) await db.q('UPDATE accounts SET bio=? WHERE email=?', [bio || null, e]);
@@ -375,6 +385,7 @@ async function getChatSettings(email) {
module.exports = { init, signup, login, ensure, byEmail, byAddress, byCode, byUsername, listAll, setSponsorRef,
setUsername, setMemberId, namesForMembers, listByReferrer, downline, linkWallet, count,
setLineBanner: (e, b, t) => impl().setLineBanner(String(e || '').toLowerCase(), b, t),
setWallOffers: (e, j) => impl().setWallOffers(String(e || '').toLowerCase(), j),
setProfile: (e, a, bio, socials) => impl().setProfile(String(e || '').toLowerCase(), a, bio, socials),
touchSeen: e => impl().touchSeen(String(e || '').toLowerCase()),
setChatAvailable: (e, v) => impl().setChatAvailable(String(e || '').toLowerCase(), v),