Branded Voice copy pass, members activity panels, menu update

Site copy regenerated through the bv-tester1 engine; em dashes scrubbed from
all user-visible strings. /api/my/activity serves per-member earnings,
referrals, and purchases from the chain index.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
martbost
2026-09-04 12:51:16 -05:00
parent f053c1befa
commit a87a63d75d
10 changed files with 111 additions and 62 deletions
+15 -1
View File
@@ -30,7 +30,7 @@ function siteConfig() {
try { saved = JSON.parse(fs.readFileSync(SITE_FILE, 'utf8')); } catch (e) {}
return Object.assign({
siteName: 'InstantAdPay',
tagline: 'Advertising that pays the people who build it — instantly, on-chain.',
tagline: 'Advertise and earn. Locked in code, not promises.',
rehearsal: true // shows the testnet banner; flipped off at mainnet launch
}, saved);
}
@@ -172,6 +172,20 @@ const server = http.createServer(async (req, res) => {
return json(res, 200, out);
}
if (p === '/api/my/activity' && req.method === 'GET') {
const s = auth.fromRequest(req);
if (!s) return json(res, 401, { error: 'Sign in first.' });
const id = s.memberId || await auth.refreshMemberId(s);
if (!id) return json(res, 200, { memberId: 0, earnings: [], purchases: [], referrals: [] });
const evs = chain.recentEvents(600);
return json(res, 200, {
memberId: id,
earnings: evs.filter(e => (e.type === 'TierPaid' && e.recipientId === id) || (e.type === 'AwardPaid' && e.toId === id)),
purchases: evs.filter(e => e.type === 'Purchase' && e.buyerId === id),
referrals: evs.filter(e => (e.type === 'MemberActivated' && e.sponsorId === id) || (e.type === 'BuyerCounted' && e.sponsorId === id))
});
}
// -- admin (Bearer ADMIN_PASSWORD)
if (p === '/api/admin/site' && req.method === 'PATCH') {
if (!isAdmin(req)) return json(res, 401, { error: 'auth' });