Ad reporting + featured rotates one link + clear campaign form on submit
- Ad reporting (auto-approved ads need a safety valve): new reports.js store (dual-mode) + ad_reports table + POST /api/report-ad; a "⚠ report" control on served ad slots opens a reason prompt and notifies the admin by email (siteConfig.adminEmail / ADMIN_EMAIL). - Featured links now show ONE link at a time and cycle (true rotation), instead of listing all links at once. - Campaign form now clears EVERY field on submit (target/creative/title/etc.). A leftover target URL was carrying into the next campaign — the same reason a video short was saved with the wrong (massifly) CTA target. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+19
-3
@@ -96,6 +96,21 @@ window.IAP = (function () {
|
||||
return div;
|
||||
}
|
||||
// Render one served ad into #<elId>. Silent if no inventory.
|
||||
// report an ad (auto-approved ads need a member-facing flag → admin notified)
|
||||
function reportAd(campaignId) {
|
||||
if (!campaignId) return;
|
||||
const reason = (prompt('Report this ad. Reason: broken, inappropriate, spam, scam, or other', 'broken') || '').trim().toLowerCase();
|
||||
if (!reason) return;
|
||||
const note = prompt('Anything to add? (optional)') || '';
|
||||
fetch('/api/report-ad', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ campaignId, reason, note }) })
|
||||
.then(() => status('Thanks — this ad was reported to the admin for review.', 'ok'))
|
||||
.catch(() => status('Could not send the report. Try again.', 'bad'));
|
||||
}
|
||||
const reportTag = ad => ' <a class="ad-report small muted" href="#" data-cid="' + ad.id + '" style="margin-left:8px">⚠ report</a>';
|
||||
function wireReport(el) {
|
||||
const rl = el.querySelector('.ad-report');
|
||||
if (rl) rl.addEventListener('click', e => { e.preventDefault(); reportAd(Number(rl.dataset.cid)); });
|
||||
}
|
||||
async function adSlot(type, elId) {
|
||||
try {
|
||||
const { ad } = await (await fetch('/api/ads/slot?type=' + type)).json();
|
||||
@@ -104,13 +119,14 @@ window.IAP = (function () {
|
||||
if (ad.imageUrl) {
|
||||
el.innerHTML = '<a href="' + ad.targetUrl + '" target="_blank" rel="noopener nofollow">'
|
||||
+ '<img src="' + ad.imageUrl + '" alt="advertisement" style="max-width:100%;border-radius:8px"></a>'
|
||||
+ '<div class="small muted">member ad</div>';
|
||||
+ '<div class="small muted">member ad' + reportTag(ad) + '</div>';
|
||||
} else {
|
||||
el.innerHTML = '<a href="' + ad.targetUrl + '" target="_blank" rel="noopener nofollow"><b>' + ad.title + '</b>'
|
||||
+ (ad.body ? ' · ' + ad.body : '') + '</a> <span class="small muted">member ad</span>';
|
||||
+ (ad.body ? ' · ' + ad.body : '') + '</a> <span class="small muted">member ad' + reportTag(ad) + '</span>';
|
||||
}
|
||||
wireReport(el);
|
||||
el.hidden = false;
|
||||
} catch (e) {}
|
||||
}
|
||||
return { getConfig, fmtPol, fmtUsd, status, renderNav, refreshNavWallet, describeEvent, feedRow, adSlot, $ };
|
||||
return { getConfig, fmtPol, fmtUsd, status, renderNav, refreshNavWallet, describeEvent, feedRow, adSlot, reportAd, $ };
|
||||
})();
|
||||
|
||||
Reference in New Issue
Block a user