436 lines
32 KiB
Plaintext
436 lines
32 KiB
Plaintext
<!DOCTYPE html>
|
||
<html lang="fr">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||
<title>Ethica — Send Engine</title>
|
||
<link href="https://fonts.googleapis.com/css2?family=DM+Sans:wght@400;500;700&family=JetBrains+Mono:wght@400;600&display=swap" rel="stylesheet">
|
||
<style>
|
||
:root{--bg:#0f0e17;--surface:#1a1930;--surface2:#232145;--border:#2d2b55;--text:#e8e6f0;--text2:#a9a5c4;--text3:#6b6794;--purple:#a78bfa;--green:#10b981;--orange:#f59e0b;--red:#ef4444;--blue:#3b82f6;--cyan:#06b6d4}
|
||
*{margin:0;padding:0;box-sizing:border-box}
|
||
body{font-family:'DM Sans',sans-serif;background:var(--bg);color:var(--text);overflow-x:hidden;font-size:13px}
|
||
.mono{font-family:'JetBrains Mono',monospace}
|
||
.container{max-width:1400px;margin:0 auto;padding:20px}
|
||
.header{display:flex;justify-content:space-between;align-items:center;margin-bottom:24px}
|
||
.header h1{font-size:20px;font-weight:700;display:flex;align-items:center;gap:10px}
|
||
.header h1 .dot{width:8px;height:8px;border-radius:50%;animation:blink 2s infinite}
|
||
@keyframes blink{0%,100%{opacity:1}50%{opacity:.3}}
|
||
.header .actions{display:flex;gap:8px}
|
||
.btn{padding:8px 16px;border:none;border-radius:8px;font-family:inherit;font-size:12px;font-weight:600;cursor:pointer;transition:.15s;display:flex;align-items:center;gap:6px}
|
||
.btn-purple{background:var(--purple);color:#fff}.btn-purple:hover{filter:brightness(1.15)}
|
||
.btn-green{background:var(--green);color:#fff}.btn-green:hover{filter:brightness(1.15)}
|
||
.btn-ghost{background:transparent;border:1px solid var(--border);color:var(--text2)}.btn-ghost:hover{border-color:var(--purple);color:var(--text)}
|
||
.btn-red{background:var(--red);color:#fff}.btn-red:hover{filter:brightness(1.15)}
|
||
.btn:disabled{opacity:.4;cursor:not-allowed}
|
||
|
||
/* KPI Cards */
|
||
.kpi-row{display:grid;grid-template-columns:repeat(5,1fr);gap:12px;margin-bottom:20px}
|
||
.kpi{background:var(--surface);border:1px solid var(--border);border-radius:12px;padding:16px;position:relative;overflow:hidden}
|
||
.kpi::before{content:'';position:absolute;top:0;left:0;right:0;height:2px}
|
||
.kpi.green::before{background:var(--green)}.kpi.purple::before{background:var(--purple)}.kpi.orange::before{background:var(--orange)}.kpi.blue::before{background:var(--blue)}.kpi.cyan::before{background:var(--cyan)}
|
||
.kpi-label{font-size:11px;color:var(--text3);text-transform:uppercase;letter-spacing:.5px;margin-bottom:6px}
|
||
.kpi-value{font-size:24px;font-weight:700;font-family:'JetBrains Mono',monospace}
|
||
.kpi-sub{font-size:11px;color:var(--text2);margin-top:4px}
|
||
|
||
/* Grid layout */
|
||
.grid-2{display:grid;grid-template-columns:1fr 1fr;gap:16px;margin-bottom:16px}
|
||
.grid-3{display:grid;grid-template-columns:2fr 1fr;gap:16px;margin-bottom:16px}
|
||
|
||
/* Cards */
|
||
.card{background:var(--surface);border:1px solid var(--border);border-radius:12px;padding:20px}
|
||
.card-title{font-size:14px;font-weight:700;margin-bottom:14px;display:flex;justify-content:space-between;align-items:center}
|
||
.card-title .tag{font-size:10px;padding:3px 8px;border-radius:6px;font-weight:600;font-family:'JetBrains Mono',monospace}
|
||
.tag-live{background:rgba(16,185,129,.15);color:var(--green)}.tag-draft{background:rgba(245,158,11,.15);color:var(--orange)}
|
||
|
||
/* ISP Bars */
|
||
.isp-bar{margin-bottom:10px}
|
||
.isp-bar .isp-label{display:flex;justify-content:space-between;font-size:12px;margin-bottom:4px}
|
||
.isp-bar .bar-bg{height:8px;background:var(--surface2);border-radius:4px;overflow:hidden}
|
||
.isp-bar .bar-fill{height:100%;border-radius:4px;transition:width .6s}
|
||
.isp-gmail .bar-fill{background:var(--red)}.isp-yahoo .bar-fill{background:var(--purple)}.isp-ms .bar-fill{background:var(--blue)}.isp-other .bar-fill{background:var(--text3)}
|
||
|
||
/* Sender Table */
|
||
.sender-table{width:100%;border-collapse:collapse;font-size:12px}
|
||
.sender-table th{text-align:left;padding:8px 10px;color:var(--text3);font-size:10px;text-transform:uppercase;letter-spacing:.5px;border-bottom:1px solid var(--border)}
|
||
.sender-table td{padding:7px 10px;border-bottom:1px solid rgba(45,43,85,.5)}
|
||
.sender-table tr:hover{background:rgba(167,139,250,.05)}
|
||
.st-dot{width:6px;height:6px;border-radius:50%;display:inline-block;margin-right:6px}
|
||
.st-active{background:var(--green)}.st-failed{background:var(--red)}.st-idle{background:var(--text3)}
|
||
|
||
/* Send Log */
|
||
.log-area{background:var(--bg);border:1px solid var(--border);border-radius:8px;padding:12px;max-height:300px;overflow-y:auto;font-family:'JetBrains Mono',monospace;font-size:11px;line-height:1.7}
|
||
.log-sent{color:var(--green)}.log-fail{color:var(--red)}.log-info{color:var(--text3)}.log-warn{color:var(--orange)}
|
||
|
||
/* Campaign Queue */
|
||
.camp-item{display:flex;justify-content:space-between;align-items:center;padding:10px 0;border-bottom:1px solid rgba(45,43,85,.5)}
|
||
.camp-progress{width:120px;height:6px;background:var(--surface2);border-radius:3px;overflow:hidden}
|
||
.camp-progress .fill{height:100%;background:var(--green);border-radius:3px;transition:width .4s}
|
||
|
||
/* Test Send */
|
||
.test-send{background:var(--surface2);border:1px dashed var(--border);border-radius:10px;padding:20px;text-align:center}
|
||
.test-send input{background:var(--bg);border:1px solid var(--border);border-radius:8px;padding:8px 14px;color:var(--text);font-family:inherit;width:300px;text-align:center;font-size:13px}
|
||
.test-send input:focus{outline:none;border-color:var(--purple)}
|
||
|
||
/* Chatbot */
|
||
.chatbot-toggle{position:fixed;bottom:20px;right:20px;width:50px;height:50px;background:linear-gradient(135deg,#7c3aed,#a78bfa);border-radius:50%;display:flex;align-items:center;justify-content:center;cursor:pointer;box-shadow:0 4px 20px rgba(124,58,237,.4);z-index:1000;font-size:20px;transition:.2s}
|
||
.chatbot-toggle:hover{transform:scale(1.1)}
|
||
.chatbot-panel{position:fixed;bottom:80px;right:20px;width:380px;height:500px;background:var(--surface);border:1px solid var(--border);border-radius:16px;box-shadow:0 8px 40px rgba(0,0,0,.5);z-index:1000;display:none;flex-direction:column;overflow:hidden}
|
||
.chatbot-panel.open{display:flex}
|
||
.chatbot-header{background:linear-gradient(135deg,#1a1a2e,#2d2b55);padding:14px 18px;display:flex;justify-content:space-between;align-items:center}
|
||
.chatbot-header h3{font-size:14px;font-weight:700}
|
||
.chatbot-messages{flex:1;overflow-y:auto;padding:14px;display:flex;flex-direction:column;gap:10px}
|
||
.msg{max-width:85%;padding:10px 14px;border-radius:12px;font-size:12px;line-height:1.6}
|
||
.msg.bot{background:var(--surface2);align-self:flex-start;border-bottom-left-radius:4px}
|
||
.msg.user{background:var(--purple);align-self:flex-end;border-bottom-right-radius:4px}
|
||
.chatbot-input{display:flex;gap:8px;padding:12px;border-top:1px solid var(--border)}
|
||
.chatbot-input input{flex:1;background:var(--bg);border:1px solid var(--border);border-radius:8px;padding:8px 12px;color:var(--text);font-family:inherit;font-size:12px}
|
||
.chatbot-input input:focus{outline:none;border-color:var(--purple)}
|
||
.chatbot-quick{display:flex;flex-wrap:wrap;gap:6px;padding:0 14px 10px}
|
||
.chatbot-quick button{background:var(--surface2);border:1px solid var(--border);border-radius:6px;padding:4px 10px;color:var(--text2);font-size:10px;cursor:pointer;font-family:inherit}
|
||
.chatbot-quick button:hover{border-color:var(--purple);color:var(--text)}
|
||
|
||
/* Toast */
|
||
.toast{position:fixed;top:20px;right:20px;background:var(--green);color:#fff;padding:12px 20px;border-radius:10px;font-weight:600;display:none;z-index:9999;box-shadow:0 4px 20px rgba(16,185,129,.3)}
|
||
|
||
@media(max-width:900px){.kpi-row{grid-template-columns:repeat(2,1fr)}.grid-2,.grid-3{grid-template-columns:1fr}}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div id="toast" class="toast"></div>
|
||
|
||
<div class="container">
|
||
<!-- Header -->
|
||
<div class="header">
|
||
<h1><span class="dot" id="pmta-dot" style="background:var(--text3)"></span> Send Engine <span class="mono" style="font-size:12px;color:var(--text3)">PMTA v5.0r3</span></h1>
|
||
<div class="actions">
|
||
<button class="btn btn-ghost" onclick="loadStatus()">↻ Refresh</button>
|
||
<button class="btn btn-purple" onclick="openTestSend()">✉ Test Send</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- KPI Row -->
|
||
<div class="kpi-row">
|
||
<div class="kpi green"><div class="kpi-label">PMTA Status</div><div class="kpi-value" id="k-pmta">—</div><div class="kpi-sub" id="k-pmta-sub">Checking...</div></div>
|
||
<div class="kpi purple"><div class="kpi-label">Senders Actifs</div><div class="kpi-value" id="k-senders">—</div><div class="kpi-sub" id="k-senders-sub">pool O365</div></div>
|
||
<div class="kpi blue"><div class="kpi-label">Capacité / Jour</div><div class="kpi-value" id="k-capacity">—</div><div class="kpi-sub">emails estimés</div></div>
|
||
<div class="kpi orange"><div class="kpi-label">Envoyés Aujourd'hui</div><div class="kpi-value" id="k-today">—</div><div class="kpi-sub" id="k-today-sub">sent + failed</div></div>
|
||
<div class="kpi cyan"><div class="kpi-label">Taux Succès</div><div class="kpi-value" id="k-rate">—</div><div class="kpi-sub">des dernières 24h</div></div>
|
||
</div>
|
||
|
||
<!-- ISP Distribution + Campaign Queue -->
|
||
<div class="grid-2">
|
||
<div class="card">
|
||
<div class="card-title">📊 Distribution ISP — Base HCP <span class="tag tag-live">LIVE</span></div>
|
||
<div id="isp-dist">
|
||
<div class="isp-bar isp-gmail"><div class="isp-label"><span>📧 Gmail</span><span id="isp-gmail-pct">—</span></div><div class="bar-bg"><div class="bar-fill" id="isp-gmail-bar" style="width:0"></div></div></div>
|
||
<div class="isp-bar isp-yahoo"><div class="isp-label"><span>📧 Yahoo / Hotmail</span><span id="isp-yahoo-pct">—</span></div><div class="bar-bg"><div class="bar-fill" id="isp-yahoo-bar" style="width:0"></div></div></div>
|
||
<div class="isp-bar isp-ms"><div class="isp-label"><span>📧 Microsoft (Outlook)</span><span id="isp-ms-pct">—</span></div><div class="bar-bg"><div class="bar-fill" id="isp-ms-bar" style="width:0"></div></div></div>
|
||
<div class="isp-bar isp-other"><div class="isp-label"><span>📧 Autres (topnet, menara, etc)</span><span id="isp-other-pct">—</span></div><div class="bar-bg"><div class="bar-fill" id="isp-other-bar" style="width:0"></div></div></div>
|
||
</div>
|
||
<div style="margin-top:14px;padding-top:12px;border-top:1px solid var(--border)">
|
||
<div style="font-size:11px;color:var(--text3);margin-bottom:8px">⚙️ PMTA Smart Routing</div>
|
||
<div style="font-size:11px;display:flex;gap:16px;color:var(--text2)">
|
||
<span>Gmail → bcg_local (warmup)</span>
|
||
<span>Yahoo → MTA-EU relay</span>
|
||
<span>Microsoft → O365 direct</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="card">
|
||
<div class="card-title">📋 File d'envoi — Campaigns</div>
|
||
<div id="campaign-queue">
|
||
<div style="color:var(--text3);font-size:12px;text-align:center;padding:20px">Chargement...</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Sender Pool + Send Log -->
|
||
<div class="grid-3">
|
||
<div class="card">
|
||
<div class="card-title">👥 Sender Pool <span class="mono" style="font-size:11px;color:var(--text3)" id="sender-count">—</span></div>
|
||
<div style="max-height:300px;overflow-y:auto">
|
||
<table class="sender-table">
|
||
<thead><tr><th>Sender</th><th>Tenant</th><th>Status</th><th>Dernière Utilisation</th></tr></thead>
|
||
<tbody id="sender-tbody"><tr><td colspan="4" style="text-align:center;color:var(--text3)">Chargement...</td></tr></tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="card">
|
||
<div class="card-title">📜 Send Log (Live) <button class="btn btn-ghost" style="padding:4px 10px;font-size:10px" onclick="clearLog()">Clear</button></div>
|
||
<div class="log-area" id="send-log">
|
||
<div class="log-info">En attente de données...</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Test Send Section -->
|
||
<div class="card" id="test-section" style="display:none">
|
||
<div class="card-title">🧪 Test Send — Mode Sécurisé <span class="tag tag-draft">TEST ONLY</span></div>
|
||
<div class="test-send">
|
||
<p style="color:var(--text2);margin-bottom:12px;font-size:12px">Envoi test uniquement vers les adresses autorisées. Aucun envoi réel vers les HCPs.</p>
|
||
<select id="test-email" class="btn btn-ghost" style="background:var(--bg);color:var(--text);width:320px;text-align:center;padding:10px;font-size:13px;margin-bottom:12px">
|
||
<option value="yacineutt@gmail.com">yacineutt@gmail.com</option>
|
||
<option value="ymahboub@weval-consulting.com">ymahboub@weval-consulting.com</option>
|
||
<option value="joecloud@proton.me">joecloud@proton.me</option>
|
||
</select>
|
||
<div style="display:flex;gap:8px;justify-content:center;margin-top:10px">
|
||
<select id="test-template" class="btn btn-ghost" style="background:var(--bg);color:var(--text)">
|
||
<option value="consent">Template Consent</option>
|
||
<option value="product_launch">Template Lancement Produit</option>
|
||
<option value="webinar">Template Webinar</option>
|
||
</select>
|
||
<select id="test-campaign" class="btn btn-ghost" style="background:var(--bg);color:var(--text)">
|
||
<option value="4">Ethica Consent TN</option>
|
||
<option value="5">Ethica Consent DZ</option>
|
||
<option value="6">Ethica Consent MA</option>
|
||
</select>
|
||
<button class="btn btn-green" onclick="sendTest()" id="btn-test">▶ Envoyer Test</button>
|
||
</div>
|
||
<div id="test-result" style="margin-top:12px;font-size:12px"></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Chatbot Toggle + Panel -->
|
||
<div class="chatbot-toggle" onclick="toggleChat()" title="Ethica AI Assistant">🤖</div>
|
||
<div class="chatbot-panel" id="chatbot">
|
||
<div class="chatbot-header">
|
||
<h3>🤖 Ethica Send Assistant</h3>
|
||
<span style="cursor:pointer;opacity:.6" onclick="toggleChat()">✕</span>
|
||
</div>
|
||
<div class="chatbot-messages" id="chat-msgs">
|
||
<div class="msg bot">Bonjour ! Je suis l'assistant Ethica — expert <b>emailing pharma</b>, <b>marketing digital</b> et <b>deliverability ISP</b>.<br><br>Je peux vous aider avec :<br>• 💊 Stratégie marketing pharma HCP<br>• 📧 Deliverability ISP (Gmail, Yahoo, Microsoft)<br>• 🎯 Segmentation, A/B testing, ROI<br>• 📋 Consentement & réglementation Maghreb<br>• 🖥️ Utilisation de la plateforme Ethica<br>• 💰 Tarifs & capacités d'envoi</div>
|
||
</div>
|
||
<div class="chatbot-quick">
|
||
<button onclick="askBot('gmail')">Gmail</button>
|
||
<button onclick="askBot('yahoo')">Yahoo</button>
|
||
<button onclick="askBot('warmup')">Warmup</button>
|
||
<button onclick="askBot('pharma')">Stratégie Pharma</button>
|
||
<button onclick="askBot('marques')">18 Marques</button>
|
||
<button onclick="askBot('consentement')">Consent</button>
|
||
<button onclick="askBot('plateforme')">Aide Plateforme</button>
|
||
<button onclick="askBot('grille')">Tarifs</button>
|
||
</div>
|
||
<div class="chatbot-input">
|
||
<input id="chat-input" placeholder="Posez votre question..." onkeydown="if(event.key==='Enter')sendChat()">
|
||
<button class="btn btn-purple" onclick="sendChat()" style="padding:8px 12px">→</button>
|
||
</div>
|
||
</div>
|
||
|
||
<script>
|
||
const API = window.location.origin;
|
||
const SE_API = API + '/api/ethica-sendengine-api.php';
|
||
const SEND_API = API + '/api/ethica-send-api.php';
|
||
|
||
function toast(m){const t=document.getElementById('toast');t.textContent=m;t.style.display='block';setTimeout(()=>t.style.display='none',3000)}
|
||
function n(v){return(v||0).toLocaleString('fr')}
|
||
|
||
async function fetchJ(url){
|
||
try{const r=await fetch(url);return await r.json();}
|
||
catch(e){return null;}
|
||
}
|
||
|
||
// ═══ Load Status ═══
|
||
async function loadStatus(){
|
||
const [status, isp, senders, logs, campaigns] = await Promise.all([
|
||
fetchJ(SE_API+'?action=status'),
|
||
fetchJ(SE_API+'?action=isp_distribution'),
|
||
fetchJ(SE_API+'?action=senders&limit=20'),
|
||
fetchJ(SE_API+'?action=send_log&limit=30'),
|
||
fetchJ(SE_API+'?action=campaigns')
|
||
]);
|
||
|
||
// KPI
|
||
if(status && status.ok){
|
||
const s=status;
|
||
const dot=document.getElementById('pmta-dot');
|
||
dot.style.background=s.pmta_reachable?'var(--green)':'var(--red)';
|
||
document.getElementById('k-pmta').textContent=s.pmta_reachable?'ONLINE':'OFFLINE';
|
||
document.getElementById('k-pmta-sub').textContent=s.pmta_reachable?'10.1.0.2:25 reachable':'Connection failed';
|
||
document.getElementById('k-senders').textContent=n(s.senders_active);
|
||
document.getElementById('k-senders-sub').textContent=n(s.senders_total)+' total pool';
|
||
document.getElementById('k-capacity').textContent=n(s.capacity_per_day);
|
||
document.getElementById('k-today').textContent=n(s.sent_today);
|
||
document.getElementById('k-today-sub').textContent=n(s.sent_today_ok)+' sent, '+n(s.sent_today_fail)+' failed';
|
||
const rate=s.sent_today>0?Math.round(s.sent_today_ok/s.sent_today*100):100;
|
||
document.getElementById('k-rate').textContent=rate+'%';
|
||
}
|
||
|
||
// ISP
|
||
if(isp && isp.ok){
|
||
const d=isp.distribution;
|
||
const total=d.gmail+d.yahoo+d.microsoft+d.other;
|
||
if(total>0){
|
||
const pct=(v)=>Math.round(v/total*100);
|
||
document.getElementById('isp-gmail-pct').textContent=n(d.gmail)+' ('+pct(d.gmail)+'%)';
|
||
document.getElementById('isp-gmail-bar').style.width=pct(d.gmail)+'%';
|
||
document.getElementById('isp-yahoo-pct').textContent=n(d.yahoo)+' ('+pct(d.yahoo)+'%)';
|
||
document.getElementById('isp-yahoo-bar').style.width=pct(d.yahoo)+'%';
|
||
document.getElementById('isp-ms-pct').textContent=n(d.microsoft)+' ('+pct(d.microsoft)+'%)';
|
||
document.getElementById('isp-ms-bar').style.width=pct(d.microsoft)+'%';
|
||
document.getElementById('isp-other-pct').textContent=n(d.other)+' ('+pct(d.other)+'%)';
|
||
document.getElementById('isp-other-bar').style.width=pct(d.other)+'%';
|
||
}
|
||
}
|
||
|
||
// Senders
|
||
if(senders && senders.ok){
|
||
document.getElementById('sender-count').textContent=senders.senders.length+' loaded';
|
||
document.getElementById('sender-tbody').innerHTML=senders.senders.map(s=>`<tr>
|
||
<td><span class="st-dot ${s.status==='ok'?'st-active':'st-failed'}"></span><span class="mono" style="font-size:11px">${s.email.length>35?s.email.substr(0,35)+'...':s.email}</span></td>
|
||
<td style="color:var(--text3);font-size:11px">${(s.email.split('@')[1]||'').substr(0,20)}</td>
|
||
<td><span style="color:${s.status==='ok'?'var(--green)':'var(--red)'}">●</span> ${s.status}</td>
|
||
<td style="color:var(--text3);font-size:11px">${s.last_used||'—'}</td>
|
||
</tr>`).join('');
|
||
}
|
||
|
||
// Send Log
|
||
if(logs && logs.ok && logs.logs.length){
|
||
document.getElementById('send-log').innerHTML=logs.logs.map(l=>{
|
||
const cls=l.status==='sent'?'log-sent':l.status==='failed'?'log-fail':'log-info';
|
||
return `<div class="${cls}">[${(l.sent_at||'').substr(11,8)}] ${l.status.toUpperCase()} → ${l.email} via ${(l.sender_account||'').split('@')[0]} (${l.isp})</div>`;
|
||
}).join('');
|
||
}
|
||
|
||
// Campaigns
|
||
if(campaigns && campaigns.ok){
|
||
document.getElementById('campaign-queue').innerHTML=campaigns.campaigns.map(c=>{
|
||
const pct=c.target_count>0?Math.round((c.sent_count||0)/c.target_count*100):0;
|
||
const statusColor=c.status==='active'?'var(--green)':c.status==='draft'?'var(--orange)':'var(--text3)';
|
||
return `<div class="camp-item">
|
||
<div><strong>${c.name}</strong><br><span style="font-size:11px;color:var(--text3)">${c.target_pays} · ${n(c.target_count)} cibles · ${c.status}</span></div>
|
||
<div style="display:flex;align-items:center;gap:10px">
|
||
<span class="mono" style="font-size:11px;color:${statusColor}">${pct}%</span>
|
||
<div class="camp-progress"><div class="fill" style="width:${pct}%"></div></div>
|
||
</div>
|
||
</div>`;
|
||
}).join('')||'<div style="color:var(--text3);text-align:center;padding:16px">Aucune campagne</div>';
|
||
}
|
||
}
|
||
|
||
// ═══ Test Send ═══
|
||
function openTestSend(){
|
||
const s=document.getElementById('test-section');
|
||
s.style.display=s.style.display==='none'?'block':'none';
|
||
s.scrollIntoView({behavior:'smooth'});
|
||
}
|
||
|
||
async function sendTest(){
|
||
const btn=document.getElementById('btn-test');
|
||
const res=document.getElementById('test-result');
|
||
btn.disabled=true;btn.textContent='Envoi...';
|
||
res.innerHTML='<span style="color:var(--orange)">Envoi en cours via PMTA...</span>';
|
||
|
||
try{
|
||
const r=await fetch(SE_API+'?action=test_send&email='+encodeURIComponent(document.getElementById('test-email').value)+'&template='+
|
||
document.getElementById('test-template').value+'&campaign='+document.getElementById('test-campaign').value);
|
||
const d=await r.json();
|
||
if(d.ok && d.sent){
|
||
res.innerHTML='<span style="color:var(--green)">✓ Email envoyé via '+d.sender+' — vérifie la boîte yacineutt@gmail.com</span>';
|
||
toast('Test envoyé !');
|
||
} else {
|
||
res.innerHTML='<span style="color:var(--red)">✗ Échec: '+(d.error||'erreur inconnue')+'</span>';
|
||
}
|
||
}catch(e){
|
||
res.innerHTML='<span style="color:var(--red)">✗ Erreur réseau: '+e.message+'</span>';
|
||
}
|
||
btn.disabled=false;btn.textContent='▶ Envoyer Test';
|
||
}
|
||
|
||
function clearLog(){document.getElementById('send-log').innerHTML='<div class="log-info">Log effacé.</div>'}
|
||
|
||
// ═══ Chatbot ═══
|
||
function toggleChat(){document.getElementById('chatbot').classList.toggle('open')}
|
||
|
||
// ═══ ETHICA CHATBOT — Full Expert Knowledge Base ═══
|
||
const KB={
|
||
// ISP Deliverability
|
||
gmail:`<b>🔴 Gmail — Best Practices</b><br><br>• <b>Warmup</b>: 20/jour, +20/jour sur 2 semaines<br>• <b>List-Unsubscribe-Post</b> obligatoire (RFC 8058)<br>• <b>HTML ratio</b>: texte/html > 60%, max 1 image<br>• <b>SPF+DKIM+DMARC</b> alignés<br>• <b>Delay</b>: 3-6s entre envois<br>• <b>Limite</b>: 2000/jour/IP en warmup<br>• <b>ARC headers</b> si relay PMTA<br>• <b>Pas de spamwords</b>: "gratuit", "offre", "urgent"<br>• Gmail = 92% de notre base → priorité #1`,
|
||
yahoo:`<b>🟣 Yahoo/Hotmail</b><br><br>• <b>Precedence: bulk</b> header requis<br>• <b>List-Unsubscribe</b> (mailto: préféré)<br>• <b>Feedback loop</b>: feedback.yahoo.com<br>• <b>Rate limit</b>: ~5000/h par IP<br>• <b>TLS obligatoire</b><br>• Yahoo = ~5% de la base`,
|
||
microsoft:`<b>🔵 Microsoft/Outlook</b><br><br>• <b>JMRP</b> feedback loop requis<br>• <b>SNDS</b> (postmaster.live.com) monitoring<br>• <b>EOP filtering strict</b><br>• Delay 2-4s recommandé<br>• Microsoft = ~1.5% de la base`,
|
||
timing:`<b>⏰ Timing Optimal HCP Maghreb</b><br><br>• <b>Mardi-Jeudi</b>: meilleurs jours<br>• <b>9h-11h</b> locale: ouverture max médecins<br>• <b>Éviter</b>: weekends, fériés, vendredi PM<br>• <b>Fuseau</b>: TN/DZ/MA = GMT+1<br>• <b>Ramadan</b>: après iftar 20h-22h<br>• <b>Volume</b>: max 5000/h en warmup`,
|
||
bounce:`<b>📉 Gestion Bounces</b><br><br>• <b>Hard</b> (5.1.x): supprimer immédiatement<br>• <b>Soft</b> (4.x.x): 3 réessais sur 72h<br>• <b>Acceptable</b>: < 2% hard<br>• <b>Auto-cleanup</b>: email_valid='bounced'<br>• <b>Check</b>: mxtoolbox.com, dnsstuff.com`,
|
||
warmup:`<b>🔥 Plan Warmup PMTA</b><br><br><b>S1</b>: 50/sender/j → 2,500/j<br><b>S2</b>: 100 → 5,000/j<br><b>S3</b>: 150 → 7,500/j<br><b>S4</b>: 200 → 10,000/j<br><br>• Round-robin automatique<br>• Gmail first (92%)<br>• Si spam > 5% → STOP<br>• Inbox > 80% avant augmenter`,
|
||
template:`<b>📝 Template Email Tips</b><br><br>• <b>Subject</b>: max 50 chars, {{PRENOM}}<br>• <b>HTML</b>: max 100KB, 1 image, pas de JS<br>• <b>Plain text</b>: toujours inclure<br>• <b>Mobile</b>: 60% → responsive<br>• <b>CTA</b>: 1 seul, bouton > 44px<br>• <b>From</b>: "Ethica Santé"<br>• <b>Pas d'attachments</b>`,
|
||
// Pharma Marketing Strategy
|
||
pharma:`<b>💊 Stratégie Marketing Pharma HCP</b><br><br>• <b>Segmentation</b>: spécialité × pays × potentiel prescripteur<br>• <b>Fréquence</b>: max 2-3 emails/mois/HCP (fatigue)<br>• <b>Contenu ROI</b>: études cliniques > promo > invitations<br>• <b>Compliance</b>: mentions légales AMM + RCP obligatoires<br>• <b>KPI secteur</b>: open 18-35%, click 2.5-4.5%, unsub <0.25%<br>• <b>Veeva benchmark</b>: 40% open, 0.50-2€/email<br>• <b>Multi-channel</b>: email + terrain + webinar = x3 impact<br>• <b>Cycle</b>: lancement → rappel → fidélisation`,
|
||
hcp:`<b>👨⚕️ Ciblage HCP Maghreb</b><br><br>• <b>TN</b>: 22,541 — Tunis, Sfax, Sousse<br>• <b>DZ</b>: 13,706 — Alger, Oran, Constantine<br>• <b>MA</b>: 13,459 — Casa, Rabat, Marrakech<br>• <b>Top spécialités</b>: généralistes (volume), cardio/gastro (valeur)<br>• <b>Langue</b>: français, arabe dialectal pour SMS<br>• <b>Vérification</b>: Google Maps + registre officiel`,
|
||
consentement:`<b>📋 Consentement — Réglementation 3 Pays</b><br><br>• <b>Maroc</b>: Loi 09-08 CNDP — opt-in obligatoire<br>• <b>Tunisie</b>: Loi 63-2004 INPDP — opt-in strict, consentement séparé par canal<br>• <b>Algérie</b>: Loi 18-07/25-11 ANPDP — opt-in, DPO obligatoire<br>• <b>AUCUNE exception B2B</b><br>• <b>Sanctions</b>: 300K MAD (MA), 5 ans prison (TN)<br>• <b>Taux opt-in</b>: 20-30% digital, 40-50% tél<br>• <b>Durée campagne</b>: 3-6 mois pour 50%+`,
|
||
marques:`<b>🏷️ 18 Marques Ethica</b><br><br><b>TN (8)</b>: Doliprane 1g, Doliprane Vit C, Maxilase, Enterogermina, Telfast, Nasacort, + 2<br><b>MA (8)</b>: No Spa, Aspégic, Flagyl, Uvedose, Allegra, Nasacort, Enterogermina, + 1<br><b>DZ (4)</b>: Doliprane Ped, Telfast, Aspégic, Maxilase, Doliprane 1g<br><br>• <b>Sanofi OTC</b> (Opella): Doliprane, Maxilase, Enterogermina<br>• <b>Sanofi Rx</b>: Telfast, Nasacort, Flagyl, Allegra`,
|
||
roi:`<b>📊 ROI & KPIs Pharma</b><br><br>• <b>Open</b>: 18-35%, cible 25%+<br>• <b>Click</b>: 2.25-4.5%, cible 3%+<br>• <b>Bounce</b>: < 2% hard<br>• <b>Unsub</b>: < 0.25%<br>• <b>Cost/HCP</b>: 0.14-0.20€<br>• <b>Veeva</b>: 40% open mais 0.50-2€/email<br>• <b>Notre avantage</b>: 3-10x moins cher`,
|
||
// Digital Marketing
|
||
ab_testing:`<b>🧪 A/B Testing Email</b><br><br>• <b>Subject</b>: 2-3 variantes sur 10% avant full send<br>• <b>From</b>: "Ethica Santé" vs "Dr. [Nom]" vs "Info Médicale"<br>• <b>CTA</b>: couleur, texte, position<br>• <b>Timing</b>: mardi 9h vs jeudi 10h<br>• <b>Segment</b>: spécialistes vs généralistes<br>• <b>Min 500</b> par variante, 24h pour résultats`,
|
||
segmentation:`<b>🎯 Segmentation Avancée</b><br><br>• <b>Spécialité</b>: Telfast → allergologues+ORL+généralistes<br>• <b>Pays</b>: adapter langue, timing, références<br>• <b>Engagement</b>: openers vs non-openers<br>• <b>Source</b>: dabadoc (qualité) vs cnam_tn (volume)<br>• <b>Ville</b>: urbain vs rural<br>• <b>Suppression</b>: bounced, opted-out, already-sent`,
|
||
sms:`<b>📱 SMS Marketing HCP</b><br><br>• <b>Coût</b>: MA ~0.03€, TN ~0.01-0.05€, DZ ~0.03-0.05€<br>• <b>Sender ID</b>: "ETHICA" brandé<br>• <b>160 chars max</b>, pas d'accents si possible<br>• <b>10h-18h</b> uniquement, jamais weekend<br>• <b>"STOP au XXXXX"</b> obligatoire<br>• <b>Taux</b>: 15-25% consentement<br>• <b>Credentials OVH</b>: chez Yanis`,
|
||
landing:`<b>🌐 Landing Pages Conversion</b><br><br>• <b>Consent</b>: consent.wevup.app<br>• <b>Éléments</b>: identité, finalité, cases non pré-cochées<br>• <b>Mobile first</b> (60%+)<br>• <b>Load < 3s</b><br>• <b>CTA unique</b><br>• <b>Trust signals</b>: logos + mentions légales<br>• <b>Tracking</b>: pixel + UTM`,
|
||
// Plateforme Ethica — Aide
|
||
plateforme:`<b>🖥️ Plateforme Ethica — Guide</b><br><br>10 modules sur <b>ethica.wevup.app</b>:<br><br>• <b>Dashboard</b>: KPIs globaux<br>• <b>Scraping</b>: sources HCP multi-pays<br>• <b>Validation</b>: pipeline qualité<br>• <b>Campagnes</b>: 18 marques × 3 pays<br>• <b>Send Engine</b>: PMTA + sender pool<br>• <b>Tracking</b>: opens, clicks, bounces<br>• <b>Consents</b>: opt-in/opt-out<br>• <b>Sentinel</b>: actions automatisées<br>• <b>Tokens</b>: tokens consent<br>• <b>Exports</b>: téléchargement`,
|
||
campagne_creation:`<b>📧 Créer une Campagne</b><br><br>1. Aller dans <b>Campagnes</b> → sélectionner marque + pays<br>2. Paramétrer objet, from name, template, ISP<br>3. Uploader ou sélectionner creative HTML<br>4. Preview pour vérifier le rendu<br>5. Ajuster la vitesse (50-500/h)<br>6. <b>Test d'abord</b> vers adresse autorisée<br>7. Lancer <b>uniquement après validation Yacine</b>`,
|
||
send_engine_help:`<b>⚡ Send Engine — Fonctionnement</b><br><br>• <b>PMTA v5.0r3</b> sur S204 (10.1.0.2:25)<br>• <b>115 comptes O365</b> rotation round-robin<br>• <b>50 emails/sender/jour</b><br>• <b>2,500/jour</b> capacité conservative<br>• <b>Smart routing</b>: Gmail→bcg_local, Yahoo→relay<br>• <b>Anti-spam</b>: Exchange headers, List-Unsubscribe<br>• Logs temps réel dans le panel`,
|
||
test_send_help:`<b>🧪 Test Send — Mode Sécurisé</b><br><br>Adresses autorisées uniquement:<br>• yacineutt@gmail.com<br>• ymahboub@weval-consulting.com<br>• joecloud@proton.me<br><br>• Sujet préfixé <b>[TEST]</b><br>• Sender aléatoire du pool<br>• Logé avec campaign_id=0<br>• <b>AUCUN envoi réel HCP</b> sans validation`,
|
||
grille:`<b>💰 Grille Tarifaire Ethica</b><br><br>• <b>1-15K/mois</b>: 2,800€ (0.187€/email)<br>• <b>15-30K/mois</b>: 4,200€ (0.140€)<br>• <b>30-45K/mois</b>: 6,000€ (0.133€)<br>• <b>+15K supp</b>: +1,800€ (0.120€)<br>• Engagement <b>12 mois</b><br>• Inclus: base, ciblage, template, routage, KPIs, dashboard<br>• <b>Consent</b>: 3,700€ séparé`,
|
||
capacite:`<b>⚙️ Capacité Actuelle</b><br><br>• <b>115 senders</b> / 1,364 pool<br>• <b>PMTA ONLINE</b> (S204:25)<br>• <b>2,500/jour</b> conservative<br>• Consent 28K → <b>~11 jours</b><br>• Promo 45K/mois → <b>57% capacité = OK</b><br>• ISP: Gmail 92%, Yahoo 5.5%<br>• <b>27,854 tokens</b> générés`
|
||
};
|
||
|
||
// Keyword → topic mapping
|
||
const KEYWORDS = [
|
||
[['gmail','google'], 'gmail'],
|
||
[['yahoo','hotmail'], 'yahoo'],
|
||
[['microsoft','outlook','office'], 'microsoft'],
|
||
[['timing','heure','quand','horaire','jour'], 'timing'],
|
||
[['bounce','rebond','rejet'], 'bounce'],
|
||
[['warmup','warm','chauffe','montee'], 'warmup'],
|
||
[['template','html','subject','objet','sujet','creative'],'template'],
|
||
[['pharma','strateg','marketing pharma','labo','laboratoire'],'pharma'],
|
||
[['hcp','medecin','docteur','ciblage','cible','specialite'],'hcp'],
|
||
[['consent','consentement','rgpd','cndp','opt-in','loi'],'consentement'],
|
||
[['marque','brand','doliprane','telfast','maxilase','ethica marque','18 marques','produit'],'marques'],
|
||
[['roi','kpi','performance','resultat','taux','ouverture','clic','open rate'],'roi'],
|
||
[['ab test','a/b','test','split','variante'],'ab_testing'],
|
||
[['segment','ciblage avance','filtr'], 'segmentation'],
|
||
[['sms','texto','telephone','mobile'], 'sms'],
|
||
[['landing','page','conversion','consent.wevup'],'landing'],
|
||
[['plateforme','module','aide','help','comment','interface','ethica.wevup'],'plateforme'],
|
||
[['campagne','creer','creation','lancer'], 'campagne_creation'],
|
||
[['send engine','moteur','pmta','envoi','sender','envoyer'],'send_engine_help'],
|
||
[['test send','test envoi','tester'], 'test_send_help'],
|
||
[['tracking','open','click','suivi','pixel'], 'tracking_help'],
|
||
[['tarif','prix','grille','cout','devis','combien'], 'grille'],
|
||
[['capacit','volume','vitesse','debit','jour'],'capacite'],
|
||
];
|
||
|
||
function askBot(topic){
|
||
const labels={gmail:'Gmail tips',yahoo:'Yahoo tips',microsoft:'Microsoft tips',timing:'Timing optimal',bounce:'Bounces',warmup:'Plan warmup',template:'Template tips',pharma:'Stratégie pharma',hcp:'Ciblage HCP',consentement:'Consentement',marques:'18 Marques Ethica',roi:'ROI & KPIs',ab_testing:'A/B Testing',segmentation:'Segmentation',sms:'SMS marketing',landing:'Landing pages',plateforme:'Aide plateforme',campagne_creation:'Créer campagne',send_engine_help:'Send Engine',test_send_help:'Test send',grille:'Tarifs',capacite:'Capacité'};
|
||
addMsg(labels[topic]||topic,'user');
|
||
setTimeout(()=>addMsg(KB[topic]||'Sujet non trouvé.','bot'),300);
|
||
}
|
||
|
||
function sendChat(){
|
||
const inp=document.getElementById('chat-input');
|
||
const q=inp.value.trim();if(!q)return;
|
||
inp.value='';addMsg(q,'user');
|
||
setTimeout(()=>{
|
||
const ql=q.toLowerCase();
|
||
let found=false;
|
||
for(const [keys,topic] of KEYWORDS){
|
||
if(keys.some(k=>ql.includes(k))){addMsg(KB[topic],'bot');found=true;break;}
|
||
}
|
||
if(!found) addMsg('Je peux vous aider sur ces sujets :<br><br><b>📧 Deliverability</b>: gmail, yahoo, microsoft, bounce, warmup, template<br><b>💊 Pharma</b>: stratégie, ciblage HCP, marques, ROI, consentement<br><b>🎯 Digital</b>: A/B testing, segmentation, SMS, landing pages<br><b>🖥️ Plateforme</b>: aide, campagnes, send engine, test, tracking, tarifs, capacité','bot');
|
||
},400);
|
||
}
|
||
|
||
function addMsg(text,role){
|
||
const d=document.getElementById('chat-msgs');
|
||
d.innerHTML+=`<div class="msg ${role}">${text}</div>`;
|
||
d.scrollTop=d.scrollHeight;
|
||
}
|
||
|
||
// Init
|
||
loadStatus();
|
||
setInterval(loadStatus,30000);
|
||
</script>
|
||
</body>
|
||
</html>
|