/**
* GMIIE Victim Action Desk — renders playbook on xxxiii.io/fraud#take-action
*/
(function () {
var STAGES = [
{ id: 'no-action-yet', label: 'No action yet — evaluating' },
{ id: 'funds-sent', label: 'Already sent funds' },
{ id: 'wallet-connected', label: 'Connected wallet to a site' },
{ id: 'signed-approval', label: 'Signed approval / transaction' },
{ id: 'fake-support', label: 'Fake support contacted me' },
];
function esc(s) {
return String(s || '')
.replace(/&/g, '&')
.replace(//g, '>')
.replace(/"/g, '"');
}
function renderLinks(links) {
if (!links || !links.length) return '';
return (
'
' +
links
.map(function (l) {
var href = esc(l.url);
var isMail = href.indexOf('mailto:') === 0;
return (
'
' +
esc(l.label || l.url) +
''
);
})
.join('') +
'
'
);
}
function renderStep(s) {
return (
'' +
'' +
'' +
esc(s.priority) +
'' +
'
' +
esc(s.title) +
'
' +
'' +
'' +
esc(s.description) +
'
' +
renderLinks(s.links) +
''
);
}
function renderQuickRef(rows) {
if (!rows || !rows.length) return '';
return (
'' +
'| Agency | Contact | Purpose | Priority |
' +
rows
.map(function (r) {
var contact = String(r.contact || '');
var contactCell =
contact.indexOf('http') === 0
? '' + esc(contact) + ''
: contact.indexOf('@') >= 0
? '' + esc(contact) + ''
: esc(contact);
return (
'| ' +
esc(r.agency) +
' | ' +
contactCell +
' | ' +
esc(r.purpose) +
' | ' +
esc(r.priority) +
' |
'
);
})
.join('') +
'
'
);
}
function renderWalletFlags(flags) {
if (!flags || !flags.length) return '';
return (
'' +
flags
.map(function (w) {
return (
'
' +
'
' +
esc(w.role) +
' · ' +
esc(w.chain) +
'
' +
'
' +
esc(w.address_truncated) +
'
' +
'
' +
esc(w.note) +
(w.freezable_usd != null ? ' · ~$' + esc(w.freezable_usd) + ' freezable' : '') +
'
'
);
})
.join('') +
'
'
);
}
function renderEmergency(box) {
if (!box) return '';
return (
'' +
'
Emergency
' +
'
' +
esc(box.title) +
'
' +
'
' +
(box.bullets || []).map(function (b) {
return '- ' + esc(b) + '
';
}).join('') +
'
'
);
}
function renderPlatformOffer(offer) {
if (!offer) return '';
return (
'' +
'
' +
esc(offer.name) +
'
' +
'
' +
esc(offer.tagline) +
'
' +
'
' +
esc(offer.description) +
'
' +
'
' +
'API: ' +
esc(offer.api_endpoint) +
'?stage=funds-sent&typology=advance-fee&score=85
' +
'Embed: ' +
esc(offer.embed_url) +
'
'
);
}
function setActiveTab(tier) {
document.querySelectorAll('.vad-tab').forEach(function (btn) {
btn.classList.toggle('active', btn.dataset.tier === tier);
});
document.querySelectorAll('.vad-tier-panel').forEach(function (panel) {
panel.classList.toggle('visible', panel.dataset.tier === tier);
});
}
function renderDesk(data) {
var root = document.getElementById('victim-action-desk');
if (!root || !data) return;
var stage = (document.getElementById('vad-stage') || {}).value || 'no-action-yet';
var emergency = renderEmergency(data.emergency_box);
var tiers = data.steps_by_tier || {};
var tierKeys = ['today', 'week', 'long_term'];
var tabs =
'' +
tierKeys
.map(function (k, i) {
var t = (data.tiers && data.tiers[k]) || {};
var count = (tiers[k] || []).length;
return (
''
);
})
.join('') +
'
';
var panels = tierKeys
.map(function (k, i) {
var t = (data.tiers && data.tiers[k]) || {};
var steps = tiers[k] || [];
return (
'' +
'
' +
esc(t.summary || '') +
' · ' +
esc(t.horizon || '') +
'
' +
(steps.length ? steps.map(renderStep).join('') : '
No steps for this stage in this horizon.
') +
'
'
);
})
.join('');
var caseEx = data.case_example;
var caseBlock = caseEx
? '' +
'
Documented pattern · ' +
esc(caseEx.case_id) +
'
' +
'
' +
esc(caseEx.summary) +
'
' +
'
Confirmed loss: $' +
esc(caseEx.confirmed_loss_usd) +
' · Freezable trace (editorial): ~$' +
esc(caseEx.freezable_usdt_usd) +
' USDT
'
: '';
root.innerHTML =
emergency +
'Stage: ' +
esc(data.meta && data.meta.stage_label) +
' · ' +
(data.meta && data.meta.step_count) +
' steps
' +
tabs +
'' +
panels +
'
' +
'' +
renderQuickRef(data.quick_reference) +
'Example Wallet Flags (redacted)
' +
renderWalletFlags(data.wallet_flags) +
caseBlock +
renderPlatformOffer(data.platform_offer);
root.querySelectorAll('.vad-tab').forEach(function (btn) {
btn.addEventListener('click', function () {
setActiveTab(btn.dataset.tier);
});
});
}
function fetchPlaybook(stage, typology, score) {
var q = new URLSearchParams();
q.set('stage', stage || 'no-action-yet');
if (typology) q.set('typology', typology);
if (score != null) q.set('score', String(score));
var laneInput = document.querySelector('#fraud-check-form [name=incident_stage]');
if (laneInput && laneInput.value) q.set('stage', laneInput.value);
return fetch('/api/gmiie/action-playbook?' + q.toString()).then(function (r) {
if (!r.ok) throw new Error('playbook ' + r.status);
return r.json();
});
}
function initStageSelector() {
var sel = document.getElementById('vad-stage');
if (!sel) return;
sel.innerHTML = '';
STAGES.forEach(function (s) {
var opt = document.createElement('option');
opt.value = s.id;
opt.textContent = s.label;
sel.appendChild(opt);
});
sel.addEventListener('change', function () {
var hidden = document.querySelector('#fraud-check-form [name=incident_stage]');
if (hidden) hidden.value = sel.value;
document.querySelectorAll('[name=checker_incident_stage]').forEach(function (r) {
r.checked = r.value === sel.value;
});
loadDesk();
});
}
function loadDesk(typology, score) {
var stage = (document.getElementById('vad-stage') || {}).value || 'no-action-yet';
var root = document.getElementById('victim-action-desk');
if (root) root.innerHTML = 'Loading recovery steps…
';
return fetchPlaybook(stage, typology, score)
.then(renderDesk)
.catch(function () {
if (root) {
root.innerHTML =
'Recovery playbook unavailable — refresh or visit blockchainfraud.org.
';
}
});
}
window.GMIIEVictimActionDesk = {
load: loadDesk,
fetchPlaybook: fetchPlaybook,
recoveryCtaHtml: function (score, level, stage) {
if (!level && score != null) {
level = score >= 75 ? 'Critical' : score >= 55 ? 'High' : score >= 30 ? 'Medium' : 'Low';
}
if (['Critical', 'High'].indexOf(level) < 0) return '';
var st = stage || 'funds-sent';
return (
''
);
},
};
document.addEventListener('click', function (e) {
var t = e.target;
if (t && t.getAttribute && t.getAttribute('data-vad-scroll') === '1') {
e.preventDefault();
var sec = document.getElementById('take-action');
if (sec) sec.scrollIntoView({ behavior: 'smooth' });
var hidden = document.querySelector('#fraud-check-form [name=incident_stage]');
var sel = document.getElementById('vad-stage');
if (sel && hidden) sel.value = hidden.value;
loadDesk();
}
});
initStageSelector();
loadDesk();
if (location.hash === '#take-action') {
setTimeout(function () {
var sec = document.getElementById('take-action');
if (sec) sec.scrollIntoView({ behavior: 'smooth' });
}, 400);
}
})();