Upgrade promo overlay: flyer shown once per session on the dashboard and Mini App (announce.js promo mode, admin-configurable promo* keys)
This commit is contained in:
@@ -423,7 +423,17 @@ const ANNOUNCE_DEFAULTS = {
|
||||
announceTimes: '7:00 PM CST | USA / Canada\n8:00 PM EST |\n8:00 PM AST | Caribbean\n1:00 AM | UK',
|
||||
announceExpiresUTC: '2026-09-09T02:30:00Z',
|
||||
announceStartUTC: '',
|
||||
announceDurationMin: 60
|
||||
announceDurationMin: 60,
|
||||
// Promo overlay (announce.js, second mode): a flyer shown ONCE PER SESSION to members, with one button.
|
||||
// Unlike the event pop-up (once per browser, with times + meet link) this is a plain nudge (Marty, 2026-09-16).
|
||||
promoEnabled: true,
|
||||
promoId: 'upgrade-2026-09-16',
|
||||
promoImg: '/upgrade-flyer.jpg',
|
||||
promoEyebrow: 'Your upgrade unlocks your reward',
|
||||
promoCtaText: 'See my next step →',
|
||||
promoCtaUrl: '/my',
|
||||
promoPages: 'my,app',
|
||||
promoExpiresUTC: ''
|
||||
};
|
||||
function seedAnnounceDefaults() {
|
||||
try { const c = readJson(CONFIG_FILE) || {}; let ch = false;
|
||||
@@ -586,7 +596,8 @@ async function handleApi(req,res,pathname){
|
||||
id: c.announceId||'', img: c.announceImg||'', meetUrl: c.announceMeetUrl||'',
|
||||
eyebrow: c.announceEyebrow||'', dateLabel: c.announceDateLabel||'',
|
||||
times: c.announceTimes||'', expiresUTC: c.announceExpiresUTC||'',
|
||||
startUTC: c.announceStartUTC||'', durationMin: Number(c.announceDurationMin)||60
|
||||
startUTC: c.announceStartUTC||'', durationMin: Number(c.announceDurationMin)||60,
|
||||
promo: { enabled: !!c.promoEnabled, id: c.promoId||'', img: c.promoImg||'', eyebrow: c.promoEyebrow||'', ctaText: c.promoCtaText||'', ctaUrl: c.promoCtaUrl||'/my', pages: c.promoPages||'my,app', expiresUTC: c.promoExpiresUTC||'' }
|
||||
});
|
||||
}
|
||||
// calendar file for the event pop-up (Apple Calendar / Outlook); Google uses a render URL built client-side
|
||||
@@ -1601,7 +1612,7 @@ async function handleApi(req,res,pathname){
|
||||
const maxOrder=sponsors.reduce((m,s)=>Math.max(m,s.sortOrder||0),0);sponsors.push({id:String(id).trim(),name:String(name).trim(),parentId:String(parentId||'').trim(),directs:0,level,status:sponsors.some(s=>s.status==='active')?'waiting':'active',sortOrder:maxOrder+10,clicks:0,notes:String(notes||'').trim(),email:String(email||'').trim().slice(0,120)});sponsors=normalizeStatuses(sponsors);saveSponsors(sponsors);return json(res,201,{sponsors});
|
||||
}
|
||||
if(req.method==='PATCH'&&pathname==='/api/admin/config'){
|
||||
const b=await bodyJson(req),cur=getConfig(),next={...cur};for(const k of ['siteName','programName','bridgeHeadline','bridgeSubheadline','premiumEntryPol','dappReferralBaseUrl','telegramUrl','supportLabel','showSponsorName','showQueueProgress','bemobPostbackUrl','telegramBotToken','companionBotToken','miniAppShortName','telegramChatId','telegramTopicId','telegramRecruitTopicId','telegramProofChatId','telegramProofTopicId','telegramProofEvents','telegramProofCtaUrl','telegramEchoChatId','telegramEchoTopicId','telegramEchoEvents','telegramTeamEvents','teamRootId','emailFrom','teamAlertEmail','ownerIds','ownerAlertEmail','orgRootId','ctbOfferPostbackUrl','ctbOfferSecret','recruitCtaUrl','walletNotice','tweetEnabled','tweetCtaUrl','tweetHashtags','blotatoTwitterId','dappFallbackPublic','moonpayPublicKey','moonpaySecretKey','publicRotationMode','publicRotationRootId','rotationExcludeIds','suiteAllowlist','suiteToolsInAlerts','suiteLevelOverride','directDefaultIds','announceEnabled','announceId','announceImg','announceMeetUrl','announceEyebrow','announceDateLabel','announceTimes','announceExpiresUTC','announceStartUTC','announceDurationMin'])if(Object.prototype.hasOwnProperty.call(b,k))next[k]=b[k];if('announceDurationMin' in next)next.announceDurationMin=Math.max(15,Number(next.announceDurationMin)||60);next.premiumEntryPol=Number(next.premiumEntryPol)||362;if('announceEnabled' in next)next.announceEnabled=!!next.announceEnabled;next.updatedAt=new Date().toISOString();writeJson(CONFIG_FILE,next);return json(res,200,{config:next});
|
||||
const b=await bodyJson(req),cur=getConfig(),next={...cur};for(const k of ['siteName','programName','bridgeHeadline','bridgeSubheadline','premiumEntryPol','dappReferralBaseUrl','telegramUrl','supportLabel','showSponsorName','showQueueProgress','bemobPostbackUrl','telegramBotToken','companionBotToken','miniAppShortName','telegramChatId','telegramTopicId','telegramRecruitTopicId','telegramProofChatId','telegramProofTopicId','telegramProofEvents','telegramProofCtaUrl','telegramEchoChatId','telegramEchoTopicId','telegramEchoEvents','telegramTeamEvents','teamRootId','emailFrom','teamAlertEmail','ownerIds','ownerAlertEmail','orgRootId','ctbOfferPostbackUrl','ctbOfferSecret','recruitCtaUrl','walletNotice','tweetEnabled','tweetCtaUrl','tweetHashtags','blotatoTwitterId','dappFallbackPublic','moonpayPublicKey','moonpaySecretKey','publicRotationMode','publicRotationRootId','rotationExcludeIds','suiteAllowlist','suiteToolsInAlerts','suiteLevelOverride','directDefaultIds','announceEnabled','announceId','announceImg','announceMeetUrl','announceEyebrow','announceDateLabel','announceTimes','announceExpiresUTC','announceStartUTC','announceDurationMin','promoEnabled','promoId','promoImg','promoEyebrow','promoCtaText','promoCtaUrl','promoPages','promoExpiresUTC'])if(Object.prototype.hasOwnProperty.call(b,k))next[k]=b[k];if('announceDurationMin' in next)next.announceDurationMin=Math.max(15,Number(next.announceDurationMin)||60);next.premiumEntryPol=Number(next.premiumEntryPol)||362;if('announceEnabled' in next)next.announceEnabled=!!next.announceEnabled;next.updatedAt=new Date().toISOString();writeJson(CONFIG_FILE,next);return json(res,200,{config:next});
|
||||
}
|
||||
const m=pathname.match(/^\/api\/admin\/sponsors\/([^/]+)(?:\/(increment|activate|qualify|reset|move))?$/);
|
||||
if(m){const id=decodeURIComponent(m[1]),action=m[2]||null;let sponsors=getSponsors(),idx=sponsors.findIndex(s=>s.id===id);if(idx<0)return json(res,404,{error:'Sponsor not found.'});
|
||||
|
||||
Reference in New Issue
Block a user