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'); }
|
||||
|
||||
@@ -53,6 +53,13 @@
|
||||
$('shNext').hidden = false;
|
||||
}
|
||||
$('shNext').addEventListener('click', load);
|
||||
// presence enforcement: pause when the tab/window loses focus, resume on return
|
||||
document.addEventListener('visibilitychange', () => {
|
||||
const v = $('shVideo'); if (!v || !v.src) return;
|
||||
if (document.hidden) v.pause(); else if (!st.done) v.play().catch(() => {});
|
||||
});
|
||||
window.addEventListener('blur', () => { const v = $('shVideo'); if (v && v.src) v.pause(); });
|
||||
window.addEventListener('focus', () => { const v = $('shVideo'); if (v && v.src && !st.done) v.play().catch(() => {}); });
|
||||
// tap the video to pause/resume
|
||||
$('shVideo').addEventListener('click', () => { const v = $('shVideo'); if (v.paused) v.play(); else v.pause(); });
|
||||
load();
|
||||
|
||||
+11
-5
@@ -4,7 +4,7 @@
|
||||
<meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
|
||||
<title>Member area | InstantAdPay</title>
|
||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Sora:wght@600;700;800&display=swap">
|
||||
<link rel="stylesheet" href="/assets/site.css?v=20260907d">
|
||||
<link rel="stylesheet" href="/assets/site.css?v=20260907e">
|
||||
</head>
|
||||
<body class="bo-body">
|
||||
|
||||
@@ -222,6 +222,12 @@
|
||||
</div>
|
||||
|
||||
<div class="pane" id="pane-line" hidden>
|
||||
<div class="card" id="sponsorMsgCard" hidden>
|
||||
<h3>Your sponsor has your back</h3>
|
||||
<p class="muted small">Questions getting started? Message your sponsor <b id="sponsorMsgName"></b> directly.
|
||||
If they are online you chat live; if not, it lands in their inbox and they are notified.</p>
|
||||
<p><button class="btn" id="lineMsgSponsor" type="button">Message your sponsor</button></p>
|
||||
</div>
|
||||
<div class="card">
|
||||
<h3>Your invite link, live from day one</h3>
|
||||
<p class="muted small">Share it anywhere, starting now. Everyone who joins through it becomes part of
|
||||
@@ -627,9 +633,9 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script src="/assets/common.js?v=20260907d"></script>
|
||||
<script src="/assets/wallet.js?v=20260907d"></script>
|
||||
<script src="/assets/my.js?v=20260907d"></script>
|
||||
<script src="/assets/chat.js?v=20260907d"></script>
|
||||
<script src="/assets/common.js?v=20260907e"></script>
|
||||
<script src="/assets/wallet.js?v=20260907e"></script>
|
||||
<script src="/assets/my.js?v=20260907e"></script>
|
||||
<script src="/assets/chat.js?v=20260907e"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
+1
-1
@@ -43,6 +43,6 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script src="/assets/shorts.js?v=20260907c"></script>
|
||||
<script src="/assets/shorts.js?v=20260907e"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user