';
}
const IAP = 'https://instantadpay.com';
function until(ms) { const s = Math.max(0, Math.round((ms - Date.now()) / 60000)); const h = Math.floor(s / 60), m = s % 60; return h ? h + 'h ' + m + 'm' : m + 'm'; }
// no wallet on the InstantAdPay account yet: the three steps, in place of the missions
function onboarding() {
return '
One thing before your first hunt. Drips are paid to the wallet on your InstantAdPay account, and yours has none yet.
'
+ '
'
+ '
Create your free InstantAdPay account. Already done: you are signed in as ' + esc(board.me.username ? '@' + board.me.username : '#' + board.me.memberId) + '.
'
+ '
Link your wallet. In your InstantAdPay dashboard open Wallet, press connect wallet and approve. Any Polygon wallet works (MetaMask, Trust, Phantom with Polygon on).
'
+ '
Come back through the door. Return to your dashboard and press Open my board again. Your missions unlock the moment a wallet is on the account.
'
+ '
';
}
// badge cards: art, lock state, share
function badgeStrip() {
const el = $('badgeStrip'); if (!el || !board.badgeCards) return;
el.innerHTML = board.badgeCards.map(b => '
' + b.icon + ' ' + esc(b.name) + '
' + esc(b.why) + '
' + (b.earned ? '' : '
\u{1F512} locked
') + '
').join('');
el.querySelectorAll('[data-share]').forEach(x => x.addEventListener('click', () => shareBadge(x.dataset.share, false)));
}
function shareBadge(id, unlocked) {
const b = (board.badgeCards || []).find(x => x.id === id); if (!b || !b.earned) return;
const text = (unlocked ? 'Achievement unlocked on PolHunter: ' : 'I earned ') + b.name + ' (' + b.why + ') on PolHunter. Visit a site, find your code, get a drip of POL to your wallet. ' + b.page;
const T = encodeURIComponent(text), U = encodeURIComponent(b.page);
$('shareBody').innerHTML = '
';
document.querySelectorAll('[data-start]').forEach(b => b.addEventListener('click', () => start(b.dataset.start)));
const s = $('submit'); if (s) { s.addEventListener('click', submit); $('code').addEventListener('keydown', e => { if (e.key === 'Enter') submit(); }); tick(); }
}
let explorer = 'https://polygonscan.com';
async function load() { board = await api('/api/my/board'); render(); }
async function start(id) {
const r = await api('/api/my/start', { missionId: id });
if (r.error) { toast(esc(r.error), 'bad'); if (r.spent || r.dailyDone) await load(); return; }
open = { missionId: id, token: r.token, url: r.url, dwell: r.dwell, started: Date.now(), expires: r.expires };
window.open(r.url, '_blank', 'noopener');
render();
}
function tick() {
const el = $('timer'); if (!el || !open) return;
const left = Math.max(0, open.dwell - Math.floor((Date.now() - open.started) / 1000));
el.innerHTML = left > 0 ? 'Your code appears on the site in about ' + left + 's. Stay on the site tab until it shows (switching away pauses it), then come back and type it here.' : 'Your code should be showing on the site now. If it is not, switch to the site tab and give it a few seconds. Then type it here.';
if (open.expires && Date.now() > open.expires) { el.innerHTML = 'This attempt timed out. Start the mission again.'; return; }
setTimeout(tick, 1000);
}
async function submit() {
const code = $('code').value.trim(); if (!code) return;
$('submit').disabled = true;
const r = await api('/api/my/submit', { token: open.token, code });
const m = $('msg'); m.className = 'msg ' + (r.error ? 'bad' : 'ok'); m.textContent = r.error || r.message;
if (r.error) toast(esc(r.error), 'bad'); else toast('\u{1F389} Found it! ' + r.pol + ' POL is on its way to your wallet.', 'big');
if (!r.error) { const a = document.createElement('a'); a.href = '#share'; a.textContent = ' Share this find \u2197'; a.style.marginLeft = '6px'; m.appendChild(a); delete $('sharetext').dataset.touched; }
// an achievement unlocked by this find: celebrate it once the board has reloaded
if (!r.error && r.unlocked && r.unlocked.length) { const id = r.unlocked[0]; toast('\u{1F3C6} Achievement unlocked!', 'big'); setTimeout(async () => { await load(); shareBadge(id, true); }, 1200); }
$('submit').disabled = false;
if (!r.error || r.spent) { open = null; setTimeout(load, 900); }
}
fetch('/api/config').then(r => r.json()).then(c => { explorer = c.explorer || explorer; }).catch(() => {});
load();
})();