141 lines
35 KiB
HTML
Executable File
141 lines
35 KiB
HTML
Executable File
<?php include_once("/opt/wevads-arsenal/public/api/wevads-metrics.php"); ?>
|
|
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>Pipeline Command Center V2 — WEVADS</title>
|
|
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600;700&family=Plus+Jakarta+Sans:wght@400;500;600;700;800&display=swap" rel="stylesheet">
|
|
<style>
|
|
:root{--bg:#060a10;--s1:#0b1018;--s2:#111a24;--s3:#1a2636;--b1:#1c2a3a;--b2:#2a3e55;--t:#e8edf5;--t2:#8b9ab5;--t3:#5a6a80;--g:#00d67e;--r:#ff4d6a;--bl:#3b82f6;--am:#f59e0b;--p:#a855f7;--cy:#06b6d4;--pk:#ec4899}
|
|
*{margin:0;padding:0;box-sizing:border-box}body{font-family:'Plus Jakarta Sans',sans-serif;background:var(--bg);color:var(--t);min-height:100vh;font-size:13px}
|
|
::-webkit-scrollbar{width:5px}::-webkit-scrollbar-track{background:var(--s1)}::-webkit-scrollbar-thumb{background:var(--b2);border-radius:3px}
|
|
.hdr{background:var(--s1);border-bottom:1px solid var(--b1);padding:12px 24px;display:flex;align-items:center;gap:14px;position:sticky;top:0;z-index:100}
|
|
.hdr h1{font-size:17px;font-weight:800;letter-spacing:-.5px}.hdr h1 span{color:var(--cy)}
|
|
.pill{padding:2px 9px;border-radius:16px;font-size:10px;font-weight:700}.pill-g{background:rgba(0,214,126,.12);color:var(--g);border:1px solid rgba(0,214,126,.2)}.pill-c{background:var(--s3);color:var(--t2)}
|
|
.tabs{display:flex;gap:1px;padding:8px 24px;background:var(--s1);border-bottom:1px solid var(--b1);overflow-x:auto}
|
|
.tab{padding:7px 14px;border-radius:7px;font-size:12px;font-weight:600;cursor:pointer;color:var(--t3);transition:all .15s;white-space:nowrap;border:1px solid transparent}
|
|
.tab:hover{color:var(--t2);background:var(--s2)}.tab.on{color:var(--cy);background:rgba(6,182,212,.08);border-color:rgba(6,182,212,.2)}
|
|
.cnt{padding:16px 24px}.pnl{display:none}.pnl.on{display:block}
|
|
.sg{display:grid;grid-template-columns:repeat(auto-fill,minmax(145px,1fr));gap:10px;margin-bottom:18px}
|
|
.st{background:var(--s1);border:1px solid var(--b1);border-radius:9px;padding:12px 14px}.st .lb{font-size:10px;color:var(--t3);text-transform:uppercase;letter-spacing:.4px;font-weight:600;margin-bottom:4px}.st .vl{font-family:'JetBrains Mono',monospace;font-size:22px;font-weight:700}
|
|
.vl-g{color:var(--g)}.vl-b{color:var(--bl)}.vl-a{color:var(--am)}.vl-p{color:var(--p)}.vl-c{color:var(--cy)}.vl-r{color:var(--r)}.vl-k{color:var(--pk)}
|
|
.tw{background:var(--s1);border:1px solid var(--b1);border-radius:9px;overflow:hidden;margin-bottom:16px}
|
|
.th{padding:12px 16px;display:flex;align-items:center;gap:10px;border-bottom:1px solid var(--b1)}.th h3{font-size:13px;font-weight:700;flex:1}
|
|
.btn{padding:6px 14px;border-radius:6px;font-size:11px;font-weight:600;cursor:pointer;border:none;transition:all .15s;font-family:inherit}
|
|
.btn-cy{background:var(--cy);color:#000}.btn-g{background:var(--g);color:#000}.btn-gh{background:var(--s3);color:var(--t2);border:1px solid var(--b1)}.btn-r{background:rgba(255,77,106,.1);color:var(--r);border:1px solid rgba(255,77,106,.15)}
|
|
.btn-sm{padding:3px 8px;font-size:10px}
|
|
table{width:100%;border-collapse:collapse}th{text-align:left;padding:8px 12px;color:var(--t3);font-weight:600;font-size:10px;text-transform:uppercase;letter-spacing:.4px;border-bottom:1px solid var(--b1);background:var(--s2)}
|
|
td{padding:8px 12px;border-bottom:1px solid rgba(28,42,58,.4)}tr:hover td{background:rgba(6,182,212,.02)}
|
|
.bg{display:inline-block;padding:1px 7px;border-radius:3px;font-size:10px;font-weight:600}.bg-g{background:rgba(0,214,126,.12);color:var(--g)}.bg-r{background:rgba(255,77,106,.12);color:var(--r)}.bg-b{background:rgba(59,130,246,.12);color:var(--bl)}.bg-a{background:rgba(245,158,11,.12);color:var(--am)}.bg-p{background:rgba(168,85,247,.12);color:var(--p)}
|
|
.mn{font-family:'JetBrains Mono',monospace;font-size:11px}
|
|
.sw{width:34px;height:18px;border-radius:9px;border:none;cursor:pointer;position:relative;transition:background .2s}.sw::after{content:'';position:absolute;width:14px;height:14px;border-radius:50%;background:#fff;top:2px;left:2px;transition:left .2s}.sw.on{background:var(--g)}.sw.on::after{left:18px}.sw.off{background:var(--r)}.sw.off::after{left:2px}
|
|
.mo{position:fixed;inset:0;background:rgba(0,0,0,.6);z-index:200;display:none;align-items:flex-start;justify-content:center;padding-top:5vh;backdrop-filter:blur(3px);overflow-y:auto}.mo.show{display:flex}
|
|
.md{background:var(--s1);border:1px solid var(--b2);border-radius:12px;width:92%;max-width:700px;margin-bottom:5vh}
|
|
.md-h{padding:14px 18px;border-bottom:1px solid var(--b1);display:flex;align-items:center}.md-h h3{flex:1;font-size:15px;font-weight:700}.md-h .x{width:28px;height:28px;border-radius:7px;background:var(--s3);border:none;color:var(--t2);cursor:pointer;font-size:14px;display:flex;align-items:center;justify-content:center}
|
|
.md-b{padding:18px}.md-f{padding:12px 18px;border-top:1px solid var(--b1);display:flex;gap:8px;justify-content:flex-end}
|
|
.f{margin-bottom:12px}.f label{display:block;font-size:11px;font-weight:600;color:var(--t2);margin-bottom:4px}
|
|
.f input,.f select,.f textarea{width:100%;padding:8px 12px;background:var(--s2);border:1px solid var(--b1);border-radius:6px;color:var(--t);font-size:12px;font-family:inherit;outline:none}.f input:focus,.f select:focus{border-color:var(--cy)}.f textarea{min-height:60px;resize:vertical}
|
|
.fr{display:grid;grid-template-columns:1fr 1fr;gap:10px}.fr3{display:grid;grid-template-columns:1fr 1fr 1fr;gap:10px}
|
|
.toast{position:fixed;bottom:20px;right:20px;padding:10px 18px;border-radius:8px;font-size:12px;font-weight:600;z-index:300;transform:translateY(60px);opacity:0;transition:all .3s}.toast.show{transform:translateY(0);opacity:1}.toast-ok{background:var(--g);color:#000}.toast-err{background:var(--r);color:#fff}
|
|
.drop-bar{height:6px;background:var(--s3);border-radius:3px;overflow:hidden;margin-top:10px}.drop-fill{height:100%;background:var(--cy);border-radius:3px;transition:width .3s}
|
|
.brand-g{display:flex;gap:8px;flex-wrap:wrap;margin:10px 0}.brand-c{background:var(--s2);border:1px solid var(--b1);border-radius:7px;padding:10px 16px;text-align:center;min-width:100px}.brand-c .n{font-weight:700;font-size:13px;margin-bottom:2px}.brand-c .v{font-family:'JetBrains Mono',monospace;font-size:20px;font-weight:700;color:var(--cy)}
|
|
.isp-g{display:flex;gap:6px;flex-wrap:wrap;margin:10px 0}.isp-c{background:var(--s2);border:1px solid var(--b1);border-radius:6px;padding:6px 12px;font-size:11px}.isp-c b{color:var(--cy);margin-right:4px}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="hdr"><h1>⚡ Pipeline <span>Command Center</span></h1><span class="pill pill-g" id="h-live">● LIVE</span><span class="pill pill-c" id="h-sends">—</span><span class="pill pill-c" id="h-contacts">—</span><a href="menu.html" style="margin-left:auto;color:var(--t3);font-size:11px;text-decoration:none">☰ Menu</a></div>
|
|
<div class="tabs" id="tabs">
|
|
<div class="tab on" data-t="dash">📊 Dashboard</div><div class="tab" data-t="crea">🎨 Creatives</div><div class="tab" data-t="offer">💰 Offers</div><div class="tab" data-t="acc">📧 O365</div><div class="tab" data-t="meth">⚙️ Methods</div><div class="tab" data-t="isp">🌐 ISP</div><div class="tab" data-t="brain">🧠 Brain</div><div class="tab" data-t="spons">🤝 Sponsors</div><div class="tab" data-t="log">📋 Log</div><div class="tab" data-t="track">📡 Tracking</div><div class="tab" data-t="drop">🚀 Drop</div><div class="tab" data-t="test">🧪 Test</div>
|
|
</div>
|
|
<div class="cnt">
|
|
<div class="pnl on" id="p-dash"><div class="sg" id="sg"></div><div class="tw"><div class="th"><h3>🏷️ Brand Pool</h3></div><div class="brand-g" id="bp" style="padding:12px"></div></div><div class="tw"><div class="th"><h3>📊 Contacts par ISP</h3></div><div class="isp-g" id="ig" style="padding:12px"></div></div></div>
|
|
<div class="pnl" id="p-crea"><div class="tw"><div class="th"><h3>🎨 Creatives</h3><button class="btn btn-cy" onclick="eCrea()">+ New</button></div><div style="overflow-x:auto"><table><thead><tr><th>ID</th><th>From</th><th>Subject</th><th>Offer</th><th>$</th><th>On/Off</th><th>Act</th></tr></thead><tbody id="tb-crea"></tbody></table></div></div></div>
|
|
<div class="pnl" id="p-offer"><div class="tw"><div class="th"><h3>💰 Offers</h3><button class="btn btn-cy" onclick="eOffer()">+ New</button></div><div style="overflow-x:auto"><table><thead><tr><th>ID</th><th>Name</th><th>$</th><th>CC</th><th>Network</th><th>URL</th><th>Status</th><th>Stats</th><th>Act</th></tr></thead><tbody id="tb-offer"></tbody></table></div></div></div>
|
|
<div class="pnl" id="p-acc"><div class="tw"><div class="th"><h3>📧 O365 Accounts</h3></div><div style="overflow-x:auto"><table><thead><tr><th>ID</th><th>Email</th><th>Brand</th><th>Status</th><th>Rebrand</th></tr></thead><tbody id="tb-acc"></tbody></table></div></div></div>
|
|
<div class="pnl" id="p-meth"><div class="tw"><div class="th"><h3>⚙️ Send Methods</h3><button class="btn btn-cy" onclick="eMeth()">+ New</button></div><div style="overflow-x:auto"><table><thead><tr><th>ID</th><th>Key</th><th>Name</th><th>Type</th><th>Prio</th><th>Rate%</th><th>Sends</th><th>On/Off</th><th>Act</th></tr></thead><tbody id="tb-meth"></tbody></table></div></div></div>
|
|
<div class="pnl" id="p-isp"><div class="tw"><div class="th"><h3>🌐 ISP Routing</h3></div><div style="overflow-x:auto"><table><thead><tr><th>ISP</th><th>CC</th><th>Domains</th><th>Method</th><th>O365</th><th>GSuite</th><th>SMTP</th><th>Contacts</th><th>Filtres</th><th>Max/D</th><th>Delay</th><th>Act</th></tr></thead><tbody id="tb-isp"></tbody></table></div></div></div>
|
|
<div class="pnl" id="p-brain"><div class="tw"><div class="th"><h3>🧠 Brain Configs</h3><span class="pill pill-c" id="brain-cnt">0</span><button class="btn btn-cy" onclick="eBrain()" style="margin-left:8px">+ New</button></div><div style="overflow-x:auto"><table><thead><tr><th>ID</th><th>ISP</th><th>Method</th><th>From</th><th>Domain</th><th>Inbox%</th><th>Conf</th><th>Sent</th><th>In</th><th>Sp</th><th>Win</th><th>On</th><th>Status</th><th>Act</th></tr></thead><tbody id="tb-brain"></tbody></table></div></div></div>
|
|
<div class="pnl" id="p-spons"><div class="tw"><div class="th"><h3>🤝 Sponsors</h3></div><div style="overflow-x:auto"><table><thead><tr><th>ID</th><th>Name</th><th>Domain</th><th>Type</th><th>AffID</th><th>Status</th><th>AM</th><th>Act</th></tr></thead><tbody id="tb-spons"></tbody></table></div></div></div>
|
|
<div class="pnl" id="p-log"><div class="tw"><div class="th"><h3>📋 Send Log</h3><button class="btn btn-gh" onclick="lLog()">↻</button></div><div style="overflow-x:auto"><table><thead><tr><th>ID</th><th>To</th><th>Subject</th><th>Method</th><th>ISP</th><th>Status</th><th>Time</th></tr></thead><tbody id="tb-log"></tbody></table></div></div></div>
|
|
<div class="pnl" id="p-track"><div class="tw"><div class="th"><h3>📡 OVH Tracking</h3><button class="btn btn-gh" onclick="lTrack()">↻</button></div><div style="padding:16px" id="track-data">Loading...</div></div></div>
|
|
<div class="pnl" id="p-drop"><div class="tw" style="max-width:650px"><div class="th"><h3>🚀 Drop Launcher</h3></div><div style="padding:18px"><div class="fr"><div class="f"><label>Volume</label><select id="d-count"><option>100</option><option>500</option><option selected>1000</option><option>2000</option><option>5000</option></select></div><div class="f"><label>ISPs</label><select id="d-isps" multiple style="height:80px"><option value="gmx" selected>GMX</option><option value="tonline" selected>T-Online</option><option value="webde" selected>Web.de</option><option value="hotmail">Hotmail</option><option value="videotron">Videotron</option></select></div></div><div style="display:flex;gap:8px;margin-top:12px"><button class="btn btn-g" onclick="dropGo()" id="d-go">🚀 Launch</button><button class="btn btn-r" onclick="dropStop()" id="d-stop" disabled>⏹ Stop</button></div><div style="background:var(--s2);border:2px dashed var(--b2);border-radius:10px;padding:20px;text-align:center;margin-top:14px"><div id="d-info" style="font-size:14px;font-weight:700;color:var(--t2)">Ready</div><div class="drop-bar"><div class="drop-fill" id="d-bar" style="width:0"></div></div><div id="d-stats" class="mn" style="margin-top:8px;color:var(--t3)"></div></div></div></div></div>
|
|
<div class="pnl" id="p-test"><div class="tw" style="max-width:500px"><div class="th"><h3>🧪 Test Send</h3></div><div style="padding:18px"><div class="f"><label>Creative</label><select id="t-crea"></select></div><div class="f"><label>To</label><input id="t-to" value="yacineutt@gmail.com"></div><button class="btn btn-g" onclick="tSend()" id="t-go">Send Test</button><div id="t-res" class="mn" style="margin-top:12px"></div></div></div></div>
|
|
</div>
|
|
|
|
<!-- MODALS -->
|
|
<div class="mo" id="mo-crea"><div class="md"><div class="md-h"><h3 id="mo-crea-t">Creative</h3><button class="x" onclick="cm('mo-crea')">✕</button></div><div class="md-b"><input type="hidden" id="c-id"><div class="fr"><div class="f"><label>From Name</label><input id="c-fn"></div><div class="f"><label>Offer</label><select id="c-oid"></select></div></div><div class="f"><label>Subject</label><input id="c-sub"></div><div class="f"><label>Image URL</label><input id="c-img" oninput="cPrev()"></div><div class="fr"><div class="f"><label>Unsub</label><input id="c-uns" value="Abmelden"></div><div class="f"><label>Status</label><select id="c-st"><option value="active">Active</option><option value="disabled">Disabled</option></select></div></div><div id="c-prev" style="background:var(--s3);border-radius:6px;padding:8px;text-align:center;min-height:40px;margin-top:8px;font-size:11px;color:var(--t3)">No image</div></div><div class="md-f"><button class="btn btn-gh" onclick="cm('mo-crea')">Cancel</button><button class="btn btn-cy" onclick="sCrea()">Save</button></div></div></div>
|
|
<div class="mo" id="mo-offer"><div class="md"><div class="md-h"><h3 id="mo-off-t">Offer</h3><button class="x" onclick="cm('mo-offer')">✕</button></div><div class="md-b"><input type="hidden" id="o-id"><div class="f"><label>Name</label><input id="o-nm"></div><div class="fr3"><div class="f"><label>Payout $</label><input id="o-pay" type="number" step="0.01"></div><div class="f"><label>Country</label><input id="o-cc"></div><div class="f"><label>Vertical</label><input id="o-vert"></div></div><div class="f"><label>CX3 URL</label><input id="o-url"></div><div class="f"><label>Preview</label><input id="o-prev"></div><div class="f"><label>Status</label><select id="o-st"><option value="active">Active</option><option value="paused">Paused</option></select></div></div><div class="md-f"><button class="btn btn-gh" onclick="cm('mo-offer')">Cancel</button><button class="btn btn-cy" onclick="sOffer()">Save</button></div></div></div>
|
|
<div class="mo" id="mo-meth"><div class="md"><div class="md-h"><h3 id="mo-me-t">Method</h3><button class="x" onclick="cm('mo-meth')">✕</button></div><div class="md-b"><input type="hidden" id="m-id"><div class="fr"><div class="f"><label>Key</label><input id="m-key"></div><div class="f"><label>Name</label><input id="m-nm"></div></div><div class="fr3"><div class="f"><label>Type</label><select id="m-type"><option>smtp</option><option>api</option><option>relay</option><option>sms</option></select></div><div class="f"><label>Priority</label><input id="m-pri" type="number"></div><div class="f"><label>Active</label><select id="m-act"><option value="t">Yes</option><option value="f">No</option></select></div></div><div class="f"><label>Description</label><textarea id="m-desc"></textarea></div><div class="f"><label>Config JSON</label><textarea id="m-cfg" class="mn">{}</textarea></div></div><div class="md-f"><button class="btn btn-gh" onclick="cm('mo-meth')">Cancel</button><button class="btn btn-cy" onclick="sMeth()">Save</button></div></div></div>
|
|
<div class="mo" id="mo-isp"><div class="md"><div class="md-h"><h3>ISP Config</h3><button class="x" onclick="cm('mo-isp')">✕</button></div><div class="md-b"><input type="hidden" id="i-id"><div class="fr"><div class="f"><label>ISP</label><input id="i-nm" readonly></div><div class="f"><label>Method</label><input id="i-met"></div></div><div class="fr3"><div class="f"><label>Max/Day</label><input id="i-max" type="number"></div><div class="f"><label>Delay(s)</label><input id="i-del" type="number"></div><div class="f"><label>Opts</label><label style="font-size:10px"><input type="checkbox" id="i-o365"> O365</label> <label style="font-size:10px"><input type="checkbox" id="i-gs"> GS</label> <label style="font-size:10px"><input type="checkbox" id="i-smtp"> SMTP</label></div></div><div class="f"><label>Notes</label><textarea id="i-notes"></textarea></div></div><div class="md-f"><button class="btn btn-gh" onclick="cm('mo-isp')">Cancel</button><button class="btn btn-cy" onclick="sIsp()">Save</button></div></div></div>
|
|
<div class="mo" id="mo-brain"><div class="md"><div class="md-h"><h3 id="mo-br-t">Brain Config</h3><button class="x" onclick="cm('mo-brain')">✕</button></div><div class="md-b"><input type="hidden" id="b-id"><div class="fr3"><div class="f"><label>ISP</label><input id="b-isp"></div><div class="f"><label>Method</label><input id="b-met"></div><div class="f"><label>Status</label><select id="b-stat"><option>learning</option><option>testing</option><option>winner</option><option>retired</option></select></div></div><div class="fr"><div class="f"><label>From Name</label><input id="b-fn"></div><div class="f"><label>From Email</label><input id="b-fe"></div></div><div class="fr"><div class="f"><label>Domain</label><input id="b-dom"></div><div class="f"><label>Content-Type</label><input id="b-ct"></div></div><div class="fr"><div class="f"><label>Encoding</label><input id="b-enc"></div><div class="f"><label>DKIM</label><input id="b-dkim"></div></div><div class="fr"><div class="f"><label>DMARC</label><input id="b-dmarc"></div><div class="f"><label>Flags</label><label style="font-size:10px"><input type="checkbox" id="b-active"> Active</label> <label style="font-size:10px"><input type="checkbox" id="b-win"> Winner</label></div></div><div class="fr"><div class="f"><label>H1 Name</label><input id="b-h1n"></div><div class="f"><label>H1 Value</label><input id="b-h1v"></div></div><div class="fr"><div class="f"><label>H2 Name</label><input id="b-h2n"></div><div class="f"><label>H2 Value</label><input id="b-h2v"></div></div><div class="f"><label>Notes</label><textarea id="b-notes"></textarea></div></div><div class="md-f"><button class="btn btn-gh" onclick="cm('mo-brain')">Cancel</button><button class="btn btn-cy" onclick="sBrain()">Save</button></div></div></div>
|
|
<div class="mo" id="mo-spons"><div class="md"><div class="md-h"><h3>Sponsor</h3><button class="x" onclick="cm('mo-spons')">✕</button></div><div class="md-b"><input type="hidden" id="sp-id"><div class="fr"><div class="f"><label>Name</label><input id="sp-nm"></div><div class="f"><label>Domain</label><input id="sp-dom"></div></div><div class="fr"><div class="f"><label>Aff ID</label><input id="sp-aff"></div><div class="f"><label>API Key</label><input id="sp-key"></div></div><div class="fr"><div class="f"><label>Status</label><select id="sp-st"><option>active</option><option>paused</option></select></div><div class="f"><label>Notes</label><input id="sp-notes"></div></div></div><div class="md-f"><button class="btn btn-gh" onclick="cm('mo-spons')">Cancel</button><button class="btn btn-cy" onclick="sSpons()">Save</button></div></div></div>
|
|
<div class="toast" id="toast"></div>
|
|
<script>
|
|
const A='api/pipeline-admin-api.php';let _o=[],_m=[],_b=[],_c=[],_isps=[],_sp=[];
|
|
document.querySelectorAll('.tab').forEach(t=>t.onclick=()=>{document.querySelectorAll('.tab').forEach(x=>x.classList.remove('on'));document.querySelectorAll('.pnl').forEach(x=>x.classList.remove('on'));t.classList.add('on');document.getElementById('p-'+t.dataset.t).classList.add('on');L[t.dataset.t]?.()});
|
|
async function api(a,b=null){const o=b?{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify(b)}:{};return(await fetch(A+'?action='+a,o)).json()}
|
|
function toast(m,ok=true){const t=$('toast');t.textContent=m;t.className='toast show '+(ok?'toast-ok':'toast-err');setTimeout(()=>t.classList.remove('show'),2500)}
|
|
function $(id){return document.getElementById(id)}
|
|
function cm(id){$(id).classList.remove('show')}function om(id){$(id).classList.add('show')}
|
|
function cPrev(){const u=$('c-img').value;$('c-prev').innerHTML=u?'<img src="'+u+'" style="max-width:100%;max-height:150px;border-radius:4px" onerror="this.parentNode.textContent=\'err\'">':'No image'}
|
|
function sw(on){return '<button class="sw '+(on?'on':'off')+'" style="pointer-events:none"></button>'}
|
|
function rt(v){v=parseFloat(v)||0;return '<span style="color:'+(v>=80?'var(--g)':v>=50?'var(--am)':'var(--r)')+'"><b>'+v+'%</b></span>'}
|
|
|
|
async function lDash(){const s=await api('stats');$('h-sends').textContent=s.sends_today+' sends';$('h-contacts').textContent=Number(s.contacts).toLocaleString()+' contacts';
|
|
$('sg').innerHTML=[['Creatives',s.creatives_active,'vl-c'],['Offers',s.offers,'vl-g'],['Senders',s.o365_send,'vl-p'],['Graph OK',s.o365_graph,'vl-b'],['Methods',s.methods_active,'vl-c'],['Brain',s.brain_total,'vl-a'],['Winners',s.brain_winners,'vl-g'],['Active',s.brain_total,'vl-b'],['FreeDNS',s.domains,'vl-p'],['Sends',s.sends_today,'vl-a'],['ISPs',s.isps,'vl-c'],['Contacts',Number(s.contacts).toLocaleString(),'vl-k']].map(([l,v,c])=>'<div class="st"><div class="lb">'+l+'</div><div class="vl '+c+'">'+v+'</div></div>').join('');
|
|
$('bp').innerHTML=(s.brands||[]).map(b=>'<div class="brand-c"><div class="n">'+b.brand+'</div><div class="v">'+b.c+'</div></div>').join('');
|
|
$('ig').innerHTML=(s.isp_contacts||[]).map(i=>'<div class="isp-c"><b>'+i.isp+'</b>'+Number(i.c).toLocaleString()+'</div>').join('')}
|
|
|
|
async function lCrea(){const[c,o]=await Promise.all([api('creatives'),api('offers')]);_o=o;_c=c;
|
|
$('tb-crea').innerHTML=c.map(r=>'<tr style="'+(r.status!='active'?'opacity:.4':'')+'"><td class="mn">'+r.id+'</td><td><b>'+( r.from_name||'—')+'</b></td><td>'+(r.subject_line||'—')+'</td><td>'+(r.offer_name||'—')+'</td><td class="mn" style="color:var(--g)">'+(r.payout?'$'+r.payout:'—')+'</td><td>'+sw(r.status=='active')+'</td><td><button class="btn btn-sm btn-gh" onclick="eCrea('+r.id+')">✏️</button> <button class="btn btn-sm btn-gh" onclick="tgCrea('+r.id+')">'+(r.status=='active'?'⏸':'▶')+'</button></td></tr>').join('');
|
|
$('t-crea').innerHTML=c.filter(x=>x.status=='active').map(x=>'<option value="'+x.id+'">#'+x.id+' '+x.from_name+'</option>').join('')}
|
|
async function eCrea(id){if(!_o.length)_o=await api('offers');$('c-oid').innerHTML=_o.map(o=>'<option value="'+o.id+'">'+o.name+' ($'+o.payout+')</option>').join('');if(id){const c=_c.find(x=>x.id==id);if(!c)return;$('c-id').value=c.id;$('c-fn').value=c.from_name||'';$('c-sub').value=c.subject_line||'';$('c-img').value=c.s3_image_url||'';$('c-st').value=c.status;if(c.offer_id)$('c-oid').value=c.offer_id;$('mo-crea-t').textContent='Edit #'+c.id}else{$('c-id').value='';$('c-fn').value='';$('c-sub').value='';$('c-img').value='';$('c-st').value='active';$('mo-crea-t').textContent='New Creative'}cPrev();om('mo-crea')}
|
|
async function sCrea(){await api('creative_save',{id:$('c-id').value,from_name:$('c-fn').value,subject:$('c-sub').value,image_url:$('c-img').value,offer_id:$('c-oid').value,unsub:$('c-uns').value,status:$('c-st').value});cm('mo-crea');toast('Saved');lCrea()}
|
|
async function tgCrea(id){await api('creative_toggle',{id});toast('Toggled');lCrea()}
|
|
|
|
async function tgOffer(id){await api("offer_toggle",{id});toast("Toggled");lOffer()}
|
|
async function lOffer(){const o=await api('offers');_o=o;$('tb-offer').innerHTML=o.map(r=>'<tr><td class="mn">'+r.id+'</td><td><b>'+r.name+'</b></td><td class="mn" style="color:var(--g)">$'+r.payout+'</td><td>'+r.countries+'</td><td>'+(r.network||'—')+'</td><td class="mn" style="max-width:180px;overflow:hidden;text-overflow:ellipsis">'+(r.offer_url||'—')+'</td><td><span class="bg '+(r.status=='Activated'?'bg-g':'bg-a')+'">'+r.status+'</span></td><td>C:'+r.creative_count+' L:'+r.link_count+'</td><td><button class="btn btn-sm btn-gh" onclick="eOffer('+r.id+')">✏️</button> <button class="btn btn-sm btn-gh" onclick="tgOffer('+r.id+')">'+(r.status=='Activated'?'⏸':'▶')+'</button></td></tr>').join('')}
|
|
function eOffer(id){if(id){const o=_o.find(x=>x.id==id);if(!o)return;$('o-id').value=o.id;$('o-nm').value=o.name;$('o-pay').value=o.payout;$('o-cc').value=o.countries;$('o-vert').value=o.network||'';$('o-url').value=o.offer_url||'';$('o-prev').value=o.unsub_url||'';$('o-st').value=o.status;$('mo-off-t').textContent='Edit #'+o.id}else{['o-id','o-nm','o-pay','o-cc','o-vert','o-url','o-prev'].forEach(x=>$(x).value='');$('o-st').value='active';$('mo-off-t').textContent='New Offer'}om('mo-offer')}
|
|
async function sOffer(){await api('offer_save',{id:$('o-id').value,name:$('o-nm').value,payout:$('o-pay').value,country:$('o-cc').value,vertical:$('o-vert').value,tracking_url:$('o-url').value,preview_url:$('o-prev').value,status:$('o-st').value});cm('mo-offer');toast('Saved');lOffer()}
|
|
|
|
async function lAcc(){const a=await api('accounts');$('tb-acc').innerHTML=a.map(r=>'<tr><td class="mn">'+r.id+'</td><td class="mn" style="font-size:10px">'+r.admin_email+'</td><td><span class="bg bg-p">'+(r.brand||'—')+'</span></td><td><span class="bg '+(r.password_status=='graph_send'?'bg-g':'bg-b')+'">'+r.password_status+'</span></td><td><select class="btn btn-sm btn-gh" onchange="reBrand('+r.id+',this.value)" style="padding:2px 6px;font-size:10px">'+['Wellnee','Lulutox','Akusoli','GlucoTrust','Service'].map(b=>'<option '+(r.brand==b?'selected':'')+'>'+b+'</option>').join('')+'</select></td></tr>').join('')}
|
|
async function reBrand(id,b){await api('account_rebrand',{id,brand:b});toast('→ '+b)}
|
|
|
|
async function lMeth(){const m=await api('methods');_m=m;$('tb-meth').innerHTML=m.map(r=>'<tr style="'+(r.is_active!='t'?'opacity:.4':'')+'"><td class="mn">'+r.id+'</td><td class="mn">'+r.method_key+'</td><td><b>'+r.name+'</b></td><td>'+r.type+'</td><td class="mn">'+r.priority+'</td><td class="mn">'+r.success_rate+'%</td><td class="mn">'+r.total_sends+'</td><td><button class="sw '+(r.is_active=='t'?'on':'off')+'" onclick="tgMeth('+r.id+')"></button></td><td><button class="btn btn-sm btn-gh" onclick="eMeth('+r.id+')">✏️</button></td></tr>').join('')}
|
|
function eMeth(id){if(id){const m=_m.find(x=>x.id==id);if(!m)return;$('m-id').value=m.id;$('m-key').value=m.method_key;$('m-nm').value=m.name;$('m-type').value=m.type;$('m-pri').value=m.priority;$('m-act').value=m.is_active;$('m-desc').value=m.description||'';$('m-cfg').value=m.config||'{}';$('m-key').readOnly=true;$('mo-me-t').textContent='Edit '+m.name}else{['m-id','m-key','m-nm','m-desc'].forEach(x=>$(x).value='');$('m-pri').value=5;$('m-act').value='t';$('m-cfg').value='{}';$('m-key').readOnly=false;$('mo-me-t').textContent='New Method'}om('mo-meth')}
|
|
async function sMeth(){await api('method_save',{id:$('m-id').value,method_key:$('m-key').value,name:$('m-nm').value,type:$('m-type').value,priority:$('m-pri').value,is_active:$('m-act').value,description:$('m-desc').value,config:$('m-cfg').value});cm('mo-meth');toast('Saved');lMeth()}
|
|
async function tgMeth(id){await api('method_toggle',{id});toast('Toggled');lMeth()}
|
|
|
|
async function lIsp(){const i=await api('isps');_isps=i;$('tb-isp').innerHTML=i.map(r=>'<tr><td><b>'+r.isp_name+'</b></td><td>'+r.country+'</td><td class="mn" style="font-size:10px;max-width:180px;overflow:hidden">'+(r.domains||'').replace(/[{}]/g,'')+'</td><td class="mn">'+r.method+'</td><td>'+sw(r.uses_office=='t')+'</td><td>'+sw(r.uses_gsuite=='t')+'</td><td>'+sw(r.uses_smtp_direct=='t')+'</td><td class="mn" style="color:var(--cy)">'+(r.contacts ? Number(r.contacts).toLocaleString() : '0')+'</td><td><a href="isp-deliverability.html" style="color:var(--gn)">'+(r.filter_count||0)+' filtres</a></td><td class="mn">'+r.max_daily_ip+'</td><td class="mn">'+r.delay_seconds+'s</td><td><button class="btn btn-sm btn-gh" onclick="eIsp('+r.id+')">✏️</button></td></tr>').join('')}
|
|
function eIsp(id){const r=_isps.find(x=>x.id==id);if(!r)return;$('i-id').value=r.id;$('i-nm').value=r.isp_name;$('i-met').value=r.method;$('i-max').value=r.max_daily_ip;$('i-del').value=r.delay_seconds;$('i-o365').checked=r.uses_office=='t';$('i-gs').checked=r.uses_gsuite=='t';$('i-smtp').checked=r.uses_smtp_direct=='t';$('i-notes').value=r.notes||'';om('mo-isp')}
|
|
async function sIsp(){await api('isp_save',{id:$('i-id').value,method:$('i-met').value,max_daily:$('i-max').value,delay:$('i-del').value,uses_office:$('i-o365').checked?'t':'f',uses_gsuite:$('i-gs').checked?'t':'f',uses_smtp:$('i-smtp').checked?'t':'f',notes:$('i-notes').value});cm('mo-isp');toast('Saved');lIsp()}
|
|
|
|
async function lBrain(){const b=await api('brain');_b=b;$('brain-cnt').textContent=b.length;
|
|
$('tb-brain').innerHTML=b.map(r=>'<tr style="'+(r.is_active!='t'?'opacity:.35':'')+'"><td class="mn">'+r.id+'</td><td><b>'+r.isp_target+'</b></td><td class="mn">'+r.send_method+'</td><td>'+(r.from_name||'—')+'</td><td class="mn" style="font-size:10px">'+(r.domain_used||'—')+'</td><td>'+rt(r.inbox_rate)+'</td><td class="mn">'+(r.confidence_score||0)+'%</td><td class="mn">'+(r.total_sent||0)+'</td><td class="mn" style="color:var(--g)">'+(r.inbox_count||0)+'</td><td class="mn" style="color:var(--r)">'+(r.spam_count||0)+'</td><td><button class="sw '+(r.is_winner=='t'?'on':'off')+'" onclick="tgBr('+r.id+',\'is_winner\')"></button></td><td><button class="sw '+(r.is_active=='t'?'on':'off')+'" onclick="tgBr('+r.id+',\'is_active\')"></button></td><td><span class="bg bg-'+(r.status=='winner'?'g':r.status=='learning'?'b':'a')+'">'+r.status+'</span></td><td><button class="btn btn-sm btn-gh" onclick="eBrain('+r.id+')">✏️</button></td></tr>').join('')}
|
|
function eBrain(id){if(id){const r=_b.find(x=>x.id==id);if(!r)return;$('b-id').value=r.id;$('b-isp').value=r.isp_target;$('b-met').value=r.send_method;$('b-fn').value=r.from_name||'';$('b-fe').value=r.from_email||'';$('b-dom').value=r.domain_used||'';$('b-ct').value=r.content_type||'';$('b-enc').value=r.encoding||'';$('b-dkim').value=r.dkim_selector||'';$('b-dmarc').value=r.dmarc_policy||'';$('b-active').checked=r.is_active=='t';$('b-win').checked=r.is_winner=='t';$('b-stat').value=r.status||'learning';$('b-h1n').value=r.header_1_name||'';$('b-h1v').value=r.header_1_value||'';$('b-h2n').value=r.header_2_name||'';$('b-h2v').value=r.header_2_value||'';$('b-notes').value=r.notes||'';$('mo-br-t').textContent='Edit #'+r.id}else{['b-id','b-isp','b-met','b-fn','b-fe','b-dom','b-ct','b-enc','b-dkim','b-dmarc','b-h1n','b-h1v','b-h2n','b-h2v','b-notes'].forEach(x=>$(x).value='');$('b-active').checked=true;$('b-win').checked=false;$('b-stat').value='learning';$('mo-br-t').textContent='New Brain'}om('mo-brain')}
|
|
async function sBrain(){await api('brain_save',{id:$('b-id').value,isp:$('b-isp').value,method:$('b-met').value,from_name:$('b-fn').value,from_email:$('b-fe').value,domain:$('b-dom').value,content_type:$('b-ct').value,encoding:$('b-enc').value,dkim:$('b-dkim').value,dmarc:$('b-dmarc').value,is_active:$('b-active').checked?'t':'f',is_winner:$('b-win').checked?'t':'f',status:$('b-stat').value,h1_name:$('b-h1n').value,h1_value:$('b-h1v').value,h2_name:$('b-h2n').value,h2_value:$('b-h2v').value,notes:$('b-notes').value});cm('mo-brain');toast('Saved');lBrain()}
|
|
async function tgBr(id,f){await api('brain_toggle',{id,field:f});toast('Toggled');lBrain()}
|
|
|
|
async function lSpons(){const s=await api('sponsors');_sp=s;$('tb-spons').innerHTML=s.map(r=>'<tr><td class="mn">'+r.id+'</td><td><b>'+r.sponsor_name+'</b></td><td class="mn">'+r.tracking_domain+'</td><td>'+r.api_type+'</td><td class="mn">'+r.affiliate_id+'</td><td><span class="bg '+(r.status=='active'?'bg-g':'bg-a')+'">'+r.status+'</span></td><td>'+(r.account_manager||'—')+'</td><td><button class="btn btn-sm btn-gh" onclick="eSpons('+r.id+')">✏️</button></td></tr>').join('')}
|
|
function eSpons(id){const r=_sp.find(x=>x.id==id);if(!r)return;$('sp-id').value=r.id;$('sp-nm').value=r.sponsor_name;$('sp-dom').value=r.tracking_domain;$('sp-aff').value=r.affiliate_id;$('sp-key').value=r.api_key||'';$('sp-st').value=r.status;$('sp-notes').value=r.notes||'';om('mo-spons')}
|
|
async function sSpons(){await api('sponsor_save',{id:$('sp-id').value,name:$('sp-nm').value,domain:$('sp-dom').value,aff_id:$('sp-aff').value,api_key:$('sp-key').value,status:$('sp-st').value,notes:$('sp-notes').value});cm('mo-spons');toast('Saved');lSpons()}
|
|
|
|
async function lLog(){const l=await api('log');$('tb-log').innerHTML=l.map(r=>'<tr><td class="mn">'+r.id+'</td><td class="mn" style="font-size:10px">'+(r.recipient||'—')+'</td><td>'+(r.subject||'—')+'</td><td class="mn">'+(r.send_method||'—')+'</td><td>'+(r.isp||'—')+'</td><td><span class="bg '+(r.status=='sent'?'bg-g':'bg-r')+'">'+r.status+'</span></td><td class="mn" style="font-size:10px">'+(r.created_at?.substring(11,19)||'—')+'</td></tr>').join('')}
|
|
|
|
async function lTrack(){$('track-data').innerHTML='Loading...';const t=await api('tracking');$('track-data').innerHTML='<div class="fr" style="margin-bottom:16px"><div class="st"><div class="lb">Opens</div><div class="vl vl-c">'+t.opens+'</div></div><div class="st"><div class="lb">Clicks</div><div class="vl vl-g">'+t.clicks+'</div></div></div><h4 style="margin:12px 0 6px;font-size:12px;color:var(--t3)">Recent Opens</h4><pre class="mn" style="background:var(--s2);padding:10px;border-radius:6px;max-height:200px;overflow:auto;font-size:10px;color:var(--t2)">'+(t.recent_opens||'No data')+'</pre><h4 style="margin:12px 0 6px;font-size:12px;color:var(--t3)">Recent Clicks</h4><pre class="mn" style="background:var(--s2);padding:10px;border-radius:6px;max-height:200px;overflow:auto;font-size:10px;color:var(--t2)">'+(t.recent_clicks||'No data')+'</pre>'}
|
|
|
|
let dI;
|
|
async function dropGo(){const isps=[...$('d-isps').selectedOptions].map(o=>o.value);$('d-go').disabled=true;$('d-stop').disabled=false;await api('drop_start',{count:parseInt($('d-count').value),isps});toast('Launched!');dI=setInterval(dPoll,3000);dPoll()}
|
|
async function dropStop(){await api('drop_stop');$('d-go').disabled=false;$('d-stop').disabled=true;clearInterval(dI);toast('Stopped',false)}
|
|
async function dPoll(){const s=await api('drop_status');const p=s.total>0?Math.round(s.sent/s.total*100):0;$('d-bar').style.width=p+'%';$('d-info').textContent=s.status=='running'?'Sending... '+s.sent+'/'+s.total:s.status=='done'?'✅ Done! '+s.sent+' sent':s.status=='stopped'?'⏹ Stopped':'Ready';$('d-stats').textContent=s.elapsed?s.sent+' sent | '+s.failed+' fail | '+s.elapsed+'s | ~'+Math.round(s.sent/Math.max(s.elapsed,1)*3600)+'/h':'';if(s.status=='done'||s.status=='stopped'){$('d-go').disabled=false;$('d-stop').disabled=true;clearInterval(dI)}}
|
|
|
|
async function tSend(){$('t-go').disabled=true;$('t-go').textContent='...';const r=await api('test_send',{creative_id:$('t-crea').value,to:$('t-to').value});$('t-go').disabled=false;$('t-go').textContent='Send Test';$('t-res').innerHTML=r.ok?'<span style="color:var(--g)">✅ '+r.result+'</span>':'<span style="color:var(--r)">❌ '+r.result+'</span>'}
|
|
|
|
const L={dash:lDash,crea:lCrea,offer:lOffer,acc:lAcc,meth:lMeth,isp:lIsp,brain:lBrain,spons:lSpons,log:lLog,track:lTrack,drop:dPoll,test:lCrea};
|
|
lDash();
|
|
</script>
|
|
<?php include("/opt/wevads-arsenal/public/universal-drill.html"); ?>
|
|
</body>
|
|
</html>
|