Unblock testing: message-your-sponsor entries, video pause-on-blur, tour polish
- Sponsor messaging is now reachable everywhere a new referral looks: a "Message your sponsor" card on My line, the Overview quick action, and a pinned "Message your sponsor" row atop the Messages drawer (even with no thread yet). Chat stores the sponsor from the dashboard. - Watch-to-earn video + Shorts now PAUSE when the tab/window loses focus and resume on return, so a viewer must stay on the page for the watch to count. - Welcome tour hides its frame on completion (no white about:blank panel). NOTE: rmcircle.team allows framing (frame-ancestors *); the blank was just the post-dwell blank state. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+30
-4
@@ -769,6 +769,14 @@
|
||||
$('vidStartBtn').textContent = 'Next video';
|
||||
}
|
||||
$('vidStartBtn').addEventListener('click', () => loadVideoAd());
|
||||
// presence enforcement: pause the watch-to-earn video when the tab/window loses focus,
|
||||
// resume when it comes back — the viewer must stay on the page for the watch to complete
|
||||
document.addEventListener('visibilitychange', () => {
|
||||
const p = $('vidPlayer'); if (!p || !p.src) return;
|
||||
if (document.hidden) p.pause(); else if (!vidState.done) p.play().catch(() => {});
|
||||
});
|
||||
window.addEventListener('blur', () => { const p = $('vidPlayer'); if (p && p.src) p.pause(); });
|
||||
window.addEventListener('focus', () => { const p = $('vidPlayer'); if (p && p.src && !vidState.done) p.play().catch(() => {}); });
|
||||
|
||||
// ── unmissable sponsor-message modal on sign-in ──
|
||||
function showSponsorModal(msg) {
|
||||
@@ -1215,6 +1223,7 @@
|
||||
const s = g.slides[i];
|
||||
$('ggWho').textContent = 'Position ' + (i + 1) + ': ' + s.name + (i === 0 ? ' — the person who invited you' : '');
|
||||
$('ggProgress').textContent = 'Meeting your line: ' + (i + 1) + ' of ' + g.slides.length;
|
||||
$('ggFrame').hidden = false;
|
||||
$('ggFrame').src = s.targetUrl;
|
||||
let left = g.dwell || 10;
|
||||
$('ggTimer').textContent = left + 's';
|
||||
@@ -1228,6 +1237,7 @@
|
||||
});
|
||||
}
|
||||
$('ggFrame').src = 'about:blank';
|
||||
$('ggFrame').hidden = true; // avoid a white about:blank panel once the tour is done
|
||||
$('ggTimer').textContent = '✓';
|
||||
$('ggWho').textContent = 'That is your line. When you grow, they earn — and yours starts the day you share.';
|
||||
$('ggClaim').hidden = false;
|
||||
@@ -1371,17 +1381,24 @@
|
||||
}
|
||||
|
||||
// ── SPONSOR CHAT: two-way threads, presence-aware, with a slide-in drawer ──
|
||||
let CHAT_ME = null, CHAT_OTHER = null, CHAT_LASTID = 0, CHAT_POLL = null, CHAT_CANMUTE = false, CHAT_IMUTE = false;
|
||||
let CHAT_ME = null, CHAT_OTHER = null, CHAT_LASTID = 0, CHAT_POLL = null, CHAT_CANMUTE = false, CHAT_IMUTE = false, CHAT_SPONSOR = null;
|
||||
function chatSync(d) {
|
||||
CHAT_ME = d.email || CHAT_ME;
|
||||
CHAT_SPONSOR = (d.sponsor && d.sponsor.email) ? d.sponsor : null;
|
||||
const link = $('chatMenuBtn'); if (link && link.closest('.bo-links')) link.closest('.bo-links').hidden = !d.email;
|
||||
setChatBadge(d.chatUnread || 0);
|
||||
const tog = $('chatAvailToggle'); if (tog) tog.checked = d.chatAvailable !== false;
|
||||
// Overview quick action + My line card: message-your-sponsor entry points
|
||||
const qs = $('qaMsgSponsor');
|
||||
if (qs) {
|
||||
if (d.sponsor && d.sponsor.email) { qs.hidden = false; qs.dataset.email = d.sponsor.email; qs.dataset.name = d.sponsor.name || 'your sponsor'; }
|
||||
if (CHAT_SPONSOR) { qs.hidden = false; qs.dataset.email = CHAT_SPONSOR.email; qs.dataset.name = CHAT_SPONSOR.name || 'your sponsor'; }
|
||||
else qs.hidden = true;
|
||||
}
|
||||
const card = $('sponsorMsgCard');
|
||||
if (card) {
|
||||
card.hidden = !CHAT_SPONSOR;
|
||||
if (CHAT_SPONSOR && $('sponsorMsgName')) $('sponsorMsgName').textContent = CHAT_SPONSOR.name || 'your sponsor';
|
||||
}
|
||||
}
|
||||
function setChatBadge(n) { const b = $('chatNavBadge'); if (b) { b.hidden = !n; b.textContent = n > 9 ? '9+' : n; } }
|
||||
function stopPoll() { if (CHAT_POLL) { clearInterval(CHAT_POLL); CHAT_POLL = null; } }
|
||||
@@ -1399,8 +1416,16 @@
|
||||
try {
|
||||
const r = await (await fetch('/api/my/chat/threads')).json();
|
||||
const list = r.threads || [];
|
||||
if (!list.length) { $('chatThreads').innerHTML = '<div class="chat-empty">No conversations yet. Message your sponsor from Overview, or anyone in your line from “My line”.</div>'; return; }
|
||||
$('chatThreads').innerHTML = list.map(t =>
|
||||
// always offer "message your sponsor" up top when they have one and no thread yet
|
||||
const hasSponsorThread = CHAT_SPONSOR && list.some(t => t.email === CHAT_SPONSOR.email);
|
||||
const sponsorRow = (CHAT_SPONSOR && !hasSponsorThread)
|
||||
? '<div class="chat-thread" data-email="' + esc(CHAT_SPONSOR.email) + '" data-name="' + esc(CHAT_SPONSOR.name) + '">'
|
||||
+ '<span class="pres-dot' + (CHAT_SPONSOR.online ? ' on' : '') + '"></span>'
|
||||
+ '<div class="ct-main"><div class="ct-name">' + esc(CHAT_SPONSOR.name) + '</div>'
|
||||
+ '<div class="ct-last">Your sponsor · tap to message</div></div></div>'
|
||||
: '';
|
||||
if (!list.length && !sponsorRow) { $('chatThreads').innerHTML = '<div class="chat-empty">No conversations yet. You can message anyone in your line from “My line”.</div>'; return; }
|
||||
$('chatThreads').innerHTML = sponsorRow + list.map(t =>
|
||||
'<div class="chat-thread" data-email="' + esc(t.email) + '" data-name="' + esc(t.name) + '">'
|
||||
+ '<span class="pres-dot' + (t.online ? ' on' : '') + '"></span>'
|
||||
+ '<div class="ct-main"><div class="ct-name">' + esc(t.name) + '</div>'
|
||||
@@ -1491,6 +1516,7 @@
|
||||
inp.addEventListener('keydown', e => { if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); chatSend(); } });
|
||||
}
|
||||
on('qaMsgSponsor', 'click', () => { const q = $('qaMsgSponsor'); if (q.dataset.email) openConvo(q.dataset.email, q.dataset.name || 'your sponsor'); });
|
||||
on('lineMsgSponsor', 'click', () => { if (CHAT_SPONSOR) openConvo(CHAT_SPONSOR.email, CHAT_SPONSOR.name || 'your sponsor'); });
|
||||
on('chatAvailToggle', 'change', async () => {
|
||||
const t = $('chatAvailToggle');
|
||||
try { await api('/api/my/chat/available', { available: t.checked }); IAP.status(t.checked ? 'You are available to chat with your line.' : 'Live chat off. People can still leave you a note.', 'ok'); }
|
||||
|
||||
Reference in New Issue
Block a user