diff --git a/public/assets/my.js b/public/assets/my.js
index b54562d..5cf1b21 100644
--- a/public/assets/my.js
+++ b/public/assets/my.js
@@ -1280,12 +1280,40 @@
: 'No member ads are live in rotation right now. Views resume the moment a campaign is running.') + '';
return;
}
- const w = window.open(r.viewUrl, '_blank');
- box.innerHTML = 'Ad open in its own tab. Watch the countdown, pass the quick '
- + 'check, and the view credits itself — this page updates the moment it does.'
- + (w ? '' : '
Pop-up blocked — open the ad here.');
+ openAdOverlay(r.viewUrl);
+ box.innerHTML = 'Watch the countdown and pass the quick check. Your view credits itself and this page updates right away.';
$('earnStartBtn').textContent = 'View next ad';
}
+ // In-page ad overlay: no new tab (mobile and in-app wallet browsers handle tabs
+ // badly), no window.close needed. The /view page runs the dwell + check inside,
+ // messages back when it credits or when the user is done.
+ function openAdOverlay(url) {
+ closeAdOverlay();
+ const back = document.createElement('div');
+ back.id = 'adOverlay';
+ back.style.cssText = 'position:fixed;inset:0;z-index:100000;background:#050b09;display:flex;flex-direction:column';
+ const x = document.createElement('button');
+ x.type = 'button'; x.setAttribute('aria-label', 'Close ad');
+ x.textContent = '✕';
+ x.style.cssText = 'position:absolute;top:10px;right:12px;z-index:2;width:40px;height:40px;border-radius:50%;border:1px solid rgba(255,255,255,.25);background:rgba(6,10,16,.85);color:#fff;font-size:20px;font-weight:700;cursor:pointer';
+ x.addEventListener('click', closeAdOverlay);
+ const ifr = document.createElement('iframe');
+ ifr.src = url;
+ ifr.style.cssText = 'flex:1;width:100%;border:0;background:#050b09';
+ back.appendChild(ifr); back.appendChild(x);
+ document.body.appendChild(back);
+ document.body.style.overflow = 'hidden';
+ }
+ function closeAdOverlay() {
+ const m = $('adOverlay'); if (m) m.remove();
+ document.body.style.overflow = '';
+ earnRefresh(); loadDashboard();
+ }
+ window.addEventListener('message', e => {
+ if (e.origin !== location.origin || !e.data) return;
+ if (e.data.t === 'iap-view-close') closeAdOverlay();
+ else if (e.data.t === 'iap-view-done') { earnRefresh(); loadDashboard(); }
+ });
$('earnStartBtn').addEventListener('click', () => earnShowAd());
// the viewer tab pings localStorage when a view credits; refresh instantly
window.addEventListener('storage', e => {
diff --git a/public/assets/view.js b/public/assets/view.js
index 89d6046..ceaa90b 100644
--- a/public/assets/view.js
+++ b/public/assets/view.js
@@ -5,6 +5,7 @@
(() => {
const $ = id => document.getElementById(id);
const token = location.pathname.split('/').pop();
+ const framed = window.self !== window.top; // shown inside the dashboard's in-page ad overlay
let left = 5, timer = null, credited = false, asking = false;
const setMsg = t => { $('vMsg').textContent = t; };
async function j(url, body) {
@@ -15,10 +16,12 @@
}
function tick() {
if (credited || asking) return;
- if (document.visibilityState !== 'visible' || !document.hasFocus()) {
+ // In the in-page overlay the iframe often doesn't hold focus even though it's
+ // fully on screen, so gate on tab visibility only when framed.
+ if (document.visibilityState !== 'visible' || (!framed && !document.hasFocus())) {
$('vTimer').classList.add('paused');
$('vTimer').textContent = 'paused';
- setMsg('Come back to this tab to keep the countdown moving.');
+ setMsg(framed ? 'Keep this ad on screen to finish the countdown.' : 'Come back to this tab to keep the countdown moving.');
return;
}
$('vTimer').classList.remove('paused');
@@ -71,6 +74,7 @@
+ (st.views >= st.target && !st.claimed ? ' Head back and claim your credits.' : ''));
$('vDone').classList.add('on');
try { localStorage.setItem('iap-view-done', String(Date.now())); } catch (e) {}
+ try { if (framed) window.parent.postMessage({ t: 'iap-view-done' }, location.origin); } catch (e) {}
}
function fail(msg) {
credited = true; // stop the loop; this view is over either way
@@ -89,6 +93,13 @@
if (!window.closed) { setMsg('Taking you back to your dashboard…'); location.href = '/my#earn'; }
}, 400);
});
+ // When shown inside the dashboard's in-page overlay there is no tab to close:
+ // hide "Close tab" and turn "Back to dashboard" into a close-the-overlay signal.
+ if (framed) {
+ const cb = $('vClose'); if (cb) cb.style.display = 'none';
+ const back = document.querySelector('#vDone a[href="/my#earn"]');
+ if (back) back.addEventListener('click', e => { e.preventDefault(); try { window.parent.postMessage({ t: 'iap-view-close' }, location.origin); } catch (x) {} });
+ }
(async () => {
const info = await j('/api/my/viewinfo?token=' + token);
if (info.error) {
diff --git a/public/my.html b/public/my.html
index da7eff1..cf73582 100644
--- a/public/my.html
+++ b/public/my.html
@@ -691,7 +691,7 @@
-
+