Files
wevads-platform/scripts/tracking-dashboard.php
2026-02-26 04:53:11 +01:00

138 lines
19 KiB
PHP
Executable File

<?php
session_start();
$base_url = 'http://89.167.40.150:5821';
$tracking_ip = '151.80.235.110';
if (isset($_GET['action'])) {
header('Content-Type: application/json');
try {
$db = new PDO('pgsql:host=localhost;dbname=adx_system', 'admin', 'admin123');
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (Exception $e) {
echo json_encode(['status' => 'error', 'message' => 'Database connection failed']);
exit;
}
if ($_GET['action'] === 'daily_stats') {
$days = intval($_GET['days'] ?? 7);
$days = min(max($days, 1), 30);
$stats = [];
for ($i = $days - 1; $i >= 0; $i--) {
$date = date('Y-m-d', strtotime("-{$i} days"));
$dateLabel = date('M j', strtotime($date));
$clicks = $db->query("SELECT COUNT(*) FROM actions.clicks WHERE DATE(action_time) = '{$date}'")->fetchColumn();
$opens = $db->query("SELECT COUNT(*) FROM actions.opens WHERE DATE(action_time) = '{$date}'")->fetchColumn();
$leads = $db->query("SELECT COUNT(*) FROM actions.leads WHERE DATE(action_time) = '{$date}'")->fetchColumn();
$unsubs = $db->query("SELECT COUNT(*) FROM actions.unsubscribes WHERE DATE(action_time) = '{$date}'")->fetchColumn();
$bounces = $db->query("SELECT COUNT(*) FROM actions.optouts WHERE DATE(action_time) = '{$date}'")->fetchColumn();
$stats[] = ['date' => $date, 'label' => $dateLabel, 'clicks' => intval($clicks), 'opens' => intval($opens), 'leads' => intval($leads), 'unsubs' => intval($unsubs), 'bounces' => intval($bounces)];
}
echo json_encode(['status' => 'success', 'data' => $stats]);
exit;
}
if ($_GET['action'] === 'global_stats') {
$period = $_GET['period'] ?? 'all';
$where = '';
if ($period === 'today') { $where = "WHERE DATE(action_time) = CURRENT_DATE"; }
elseif ($period === 'week') { $where = "WHERE action_time >= NOW() - INTERVAL '7 days'"; }
elseif ($period === 'month') { $where = "WHERE action_time >= NOW() - INTERVAL '30 days'"; }
$clicks = $db->query("SELECT COUNT(*) FROM actions.clicks {$where}")->fetchColumn();
$opens = $db->query("SELECT COUNT(*) FROM actions.opens {$where}")->fetchColumn();
$leads = $db->query("SELECT COUNT(*) FROM actions.leads {$where}")->fetchColumn();
$unsubs = $db->query("SELECT COUNT(*) FROM actions.unsubscribes {$where}")->fetchColumn();
$bounces = $db->query("SELECT COUNT(*) FROM actions.optouts {$where}")->fetchColumn();
echo json_encode(['status' => 'success', 'data' => ['clicks' => intval($clicks), 'opens' => intval($opens), 'leads' => intval($leads), 'unsubs' => intval($unsubs), 'bounces' => intval($bounces)], 'period' => $period]);
exit;
}
if ($_GET['action'] === 'today_comparison') {
$todayClicks = $db->query("SELECT COUNT(*) FROM actions.clicks WHERE DATE(action_time) = CURRENT_DATE")->fetchColumn();
$todayOpens = $db->query("SELECT COUNT(*) FROM actions.opens WHERE DATE(action_time) = CURRENT_DATE")->fetchColumn();
$todayLeads = $db->query("SELECT COUNT(*) FROM actions.leads WHERE DATE(action_time) = CURRENT_DATE")->fetchColumn();
$todayUnsubs = $db->query("SELECT COUNT(*) FROM actions.unsubscribes WHERE DATE(action_time) = CURRENT_DATE")->fetchColumn();
$todayBounces = $db->query("SELECT COUNT(*) FROM actions.optouts WHERE DATE(action_time) = CURRENT_DATE")->fetchColumn();
$yestClicks = $db->query("SELECT COUNT(*) FROM actions.clicks WHERE DATE(action_time) = CURRENT_DATE - INTERVAL '1 day'")->fetchColumn();
$yestOpens = $db->query("SELECT COUNT(*) FROM actions.opens WHERE DATE(action_time) = CURRENT_DATE - INTERVAL '1 day'")->fetchColumn();
$yestLeads = $db->query("SELECT COUNT(*) FROM actions.leads WHERE DATE(action_time) = CURRENT_DATE - INTERVAL '1 day'")->fetchColumn();
$yestUnsubs = $db->query("SELECT COUNT(*) FROM actions.unsubscribes WHERE DATE(action_time) = CURRENT_DATE - INTERVAL '1 day'")->fetchColumn();
$yestBounces = $db->query("SELECT COUNT(*) FROM actions.optouts WHERE DATE(action_time) = CURRENT_DATE - INTERVAL '1 day'")->fetchColumn();
$comparison = [];
$metrics = ['clicks' => [$todayClicks, $yestClicks], 'opens' => [$todayOpens, $yestOpens], 'leads' => [$todayLeads, $yestLeads], 'unsubs' => [$todayUnsubs, $yestUnsubs], 'bounces' => [$todayBounces, $yestBounces]];
foreach ($metrics as $name => $vals) {
$t = intval($vals[0]); $y = intval($vals[1]); $diff = $t - $y; $pct = $y > 0 ? round(($diff / $y) * 100, 1) : 0;
$comparison[$name] = ['today' => $t, 'yesterday' => $y, 'diff' => $diff, 'pct' => $pct];
}
echo json_encode(['status' => 'success', 'data' => $comparison]);
exit;
}
if ($_GET['action'] === 'recent_activity') {
$clicks = $db->query("SELECT id, 'click' as action_name, process_id, vmta_id, offer_production_id as offer_id, action_time FROM actions.clicks ORDER BY action_time DESC LIMIT 5")->fetchAll(PDO::FETCH_ASSOC);
$opens = $db->query("SELECT id, 'open' as action_name, process_id, vmta_id, offer_production_id as offer_id, action_time FROM actions.opens ORDER BY action_time DESC LIMIT 5")->fetchAll(PDO::FETCH_ASSOC);
$leads = $db->query("SELECT id, 'lead' as action_name, process_id, vmta_id, offer_production_id as offer_id, action_time FROM actions.leads ORDER BY action_time DESC LIMIT 5")->fetchAll(PDO::FETCH_ASSOC);
$activities = array_merge($clicks, $opens, $leads);
usort($activities, function($a, $b) { return strtotime($b['action_time']) - strtotime($a['action_time']); });
echo json_encode(['status' => 'success', 'data' => array_slice($activities, 0, 10)]);
exit;
}
if ($_GET['action'] === 'system_status') {
$ch = curl_init();
curl_setopt_array($ch, [CURLOPT_URL => "http://{$tracking_ip}/", CURLOPT_RETURNTRANSFER => true, CURLOPT_TIMEOUT => 5]);
curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
echo json_encode(['status' => ($httpCode > 0) ? 'ok' : 'error', 'message' => ($httpCode > 0) ? 'Online' : 'Offline', 'tracking_ip' => $tracking_ip]);
exit;
}
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Tracking Dashboard - WEVAL</title>
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<style>
*{margin:0;padding:0;box-sizing:border-box}body{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;background:#f8fafc;min-height:100vh}.navbar{background:#fff;border-bottom:1px solid #e2e8f0;padding:15px 25px;display:flex;justify-content:space-between;align-items:center}.navbar h1{font-size:22px;color:#1e293b;display:flex;align-items:center;gap:12px}.navbar h1 i{color:#0ea5e9}.navbar-right{display:flex;align-items:center;gap:20px}.status-badge{display:flex;align-items:center;gap:8px;padding:8px 16px;border-radius:20px;font-size:13px;font-weight:600}.status-badge.ok{background:#d1fae5;color:#065f46}.status-badge.error{background:#fee2e2;color:#991b1b}.status-badge .dot{width:10px;height:10px;border-radius:50%}.status-badge.ok .dot{background:#10b981;animation:blink 2s infinite}.status-badge.error .dot{background:#ef4444}@keyframes blink{0%,100%{opacity:1}50%{opacity:.5}}.main-content{padding:25px;max-width:1600px;margin:0 auto}.stats-grid{display:grid;grid-template-columns:repeat(5,1fr);gap:20px;margin-bottom:25px}@media(max-width:1200px){.stats-grid{grid-template-columns:repeat(3,1fr)}}@media(max-width:768px){.stats-grid{grid-template-columns:repeat(2,1fr)}}.stat-card{background:#fff;border-radius:12px;padding:20px;box-shadow:0 2px 8px rgba(0,0,0,.06)}.stat-card .stat-header{display:flex;justify-content:space-between;align-items:flex-start;margin-bottom:12px}.stat-card .stat-icon{width:45px;height:45px;border-radius:10px;display:flex;align-items:center;justify-content:center;font-size:20px}.stat-card .stat-icon.clicks{background:#dbeafe;color:#2563eb}.stat-card .stat-icon.opens{background:#d1fae5;color:#10b981}.stat-card .stat-icon.leads{background:#fef3c7;color:#f59e0b}.stat-card .stat-icon.unsubs{background:#fee2e2;color:#ef4444}.stat-card .stat-icon.bounces{background:#f3e8ff;color:#9333ea}.stat-card .stat-change{font-size:12px;padding:4px 8px;border-radius:12px;font-weight:600}.stat-card .stat-change.up{background:#d1fae5;color:#065f46}.stat-card .stat-change.down{background:#fee2e2;color:#991b1b}.stat-card .stat-change.neutral{background:#f1f5f9;color:#64748b}.stat-card .stat-value{font-size:32px;font-weight:700;color:#1e293b;margin-bottom:4px}.stat-card .stat-label{color:#64748b;font-size:14px;font-weight:500}.stat-card .stat-sub{color:#94a3b8;font-size:12px;margin-top:8px}.content-grid{display:grid;grid-template-columns:2fr 1fr;gap:25px}@media(max-width:1024px){.content-grid{grid-template-columns:1fr}}.card{background:#fff;border-radius:12px;box-shadow:0 2px 8px rgba(0,0,0,.06);overflow:hidden}.card-header{padding:18px 20px;border-bottom:1px solid #f1f5f9;display:flex;justify-content:space-between;align-items:center}.card-header h3{font-size:16px;color:#1e293b;display:flex;align-items:center;gap:10px}.card-header h3 i{color:#0ea5e9}.card-body{padding:20px}.period-selector{display:flex;gap:8px}.period-btn{padding:6px 14px;border-radius:6px;font-size:13px;font-weight:500;border:1px solid #e2e8f0;background:#fff;color:#64748b;cursor:pointer}.period-btn:hover{border-color:#0ea5e9;color:#0ea5e9}.period-btn.active{background:#0ea5e9;color:#fff;border-color:#0ea5e9}.chart-container{height:300px;margin-top:15px}.quick-action{display:flex;align-items:center;gap:12px;padding:14px;border-radius:10px;text-decoration:none;color:#374151;background:#f8fafc;margin-bottom:10px;border:1px solid transparent}.quick-action:hover{background:#f1f5f9;border-color:#0ea5e9}.quick-action i{width:40px;height:40px;border-radius:10px;background:#dbeafe;color:#2563eb;display:flex;align-items:center;justify-content:center}.quick-action span{font-weight:500}.activity-item{display:flex;align-items:center;gap:12px;padding:12px 0;border-bottom:1px solid #f1f5f9}.activity-item:last-child{border-bottom:none}.activity-icon{width:36px;height:36px;border-radius:8px;display:flex;align-items:center;justify-content:center;font-size:14px}.activity-icon.click{background:#dbeafe;color:#2563eb}.activity-icon.open{background:#d1fae5;color:#10b981}.activity-icon.lead{background:#fef3c7;color:#f59e0b}.activity-info{flex:1}.activity-info .type{font-weight:600;color:#1e293b;font-size:13px;text-transform:capitalize}.activity-info .details{color:#64748b;font-size:12px}.activity-time{color:#94a3b8;font-size:11px}.global-section{margin-top:25px}.global-grid{display:grid;grid-template-columns:repeat(5,1fr);gap:15px}@media(max-width:900px){.global-grid{grid-template-columns:repeat(3,1fr)}}.global-stat{text-align:center;padding:20px;background:#f8fafc;border-radius:10px}.global-stat .value{font-size:28px;font-weight:700;margin-bottom:5px}.global-stat .value.clicks{color:#2563eb}.global-stat .value.opens{color:#10b981}.global-stat .value.leads{color:#f59e0b}.global-stat .value.unsubs{color:#ef4444}.global-stat .value.bounces{color:#9333ea}.global-stat .label{color:#64748b;font-size:13px}.loading{color:#94a3b8;text-align:center;padding:40px}
</style>
</head>
<body>
<nav class="navbar"><h1><i class="fa fa-chart-line"></i> Tracking Dashboard</h1><div class="navbar-right"><div class="status-badge" id="system-status"><span class="dot"></span><span id="status-text">...</span></div><a href="<?php echo $base_url; ?>" style="color:#64748b;text-decoration:none"><i class="fa fa-arrow-left"></i> Back</a></div></nav>
<div class="main-content">
<div class="stats-grid">
<div class="stat-card"><div class="stat-header"><div class="stat-icon clicks"><i class="fa fa-mouse-pointer"></i></div><span class="stat-change neutral" id="clicks-change">-</span></div><div class="stat-value" id="clicks-value">-</div><div class="stat-label">Clicks Today</div><div class="stat-sub" id="clicks-yesterday">vs yesterday: -</div></div>
<div class="stat-card"><div class="stat-header"><div class="stat-icon opens"><i class="fa fa-envelope-open"></i></div><span class="stat-change neutral" id="opens-change">-</span></div><div class="stat-value" id="opens-value">-</div><div class="stat-label">Opens Today</div><div class="stat-sub" id="opens-yesterday">vs yesterday: -</div></div>
<div class="stat-card"><div class="stat-header"><div class="stat-icon leads"><i class="fa fa-user-plus"></i></div><span class="stat-change neutral" id="leads-change">-</span></div><div class="stat-value" id="leads-value">-</div><div class="stat-label">Leads Today</div><div class="stat-sub" id="leads-yesterday">vs yesterday: -</div></div>
<div class="stat-card"><div class="stat-header"><div class="stat-icon unsubs"><i class="fa fa-user-minus"></i></div><span class="stat-change neutral" id="unsubs-change">-</span></div><div class="stat-value" id="unsubs-value">-</div><div class="stat-label">Unsubs Today</div><div class="stat-sub" id="unsubs-yesterday">vs yesterday: -</div></div>
<div class="stat-card"><div class="stat-header"><div class="stat-icon bounces"><i class="fa fa-exclamation-triangle"></i></div><span class="stat-change neutral" id="bounces-change">-</span></div><div class="stat-value" id="bounces-value">-</div><div class="stat-label">Optouts Today</div><div class="stat-sub" id="bounces-yesterday">vs yesterday: -</div></div>
</div>
<div class="content-grid">
<div class="card"><div class="card-header"><h3><i class="fa fa-chart-area"></i> Daily Statistics</h3><div class="period-selector"><button class="period-btn" data-days="7">7D</button><button class="period-btn active" data-days="14">14D</button><button class="period-btn" data-days="30">30D</button></div></div><div class="card-body"><div class="chart-container"><canvas id="dailyChart"></canvas></div></div></div>
<div>
<div class="card" style="margin-bottom:20px"><div class="card-header"><h3><i class="fa fa-bolt"></i> Quick Actions</h3></div><div class="card-body"><a href="<?php echo $base_url; ?>/tracking-system-standalone.php" class="quick-action"><i class="fa fa-heartbeat"></i><span>Run Diagnostic</span></a><a href="<?php echo $base_url; ?>/tracking-deploy.php" class="quick-action"><i class="fa fa-rocket"></i><span>Deploy Server</span></a><a href="http://<?php echo $tracking_ip; ?>/" target="_blank" class="quick-action"><i class="fa fa-external-link-alt"></i><span>Open Tracking</span></a></div></div>
<div class="card"><div class="card-header"><h3><i class="fa fa-history"></i> Recent Activity</h3></div><div class="card-body" id="activity-feed"><div class="loading"><i class="fa fa-spinner fa-spin"></i></div></div></div>
</div>
</div>
<div class="global-section"><div class="card"><div class="card-header"><h3><i class="fa fa-globe"></i> Global Statistics</h3><div class="period-selector"><button class="period-btn global-btn" data-period="today">Today</button><button class="period-btn global-btn" data-period="week">7D</button><button class="period-btn global-btn active" data-period="month">30D</button><button class="period-btn global-btn" data-period="all">All</button></div></div><div class="card-body"><div class="global-grid"><div class="global-stat"><div class="value clicks" id="global-clicks">-</div><div class="label">Clicks</div></div><div class="global-stat"><div class="value opens" id="global-opens">-</div><div class="label">Opens</div></div><div class="global-stat"><div class="value leads" id="global-leads">-</div><div class="label">Leads</div></div><div class="global-stat"><div class="value unsubs" id="global-unsubs">-</div><div class="label">Unsubs</div></div><div class="global-stat"><div class="value bounces" id="global-bounces">-</div><div class="label">Optouts</div></div></div></div></div></div>
</div>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script>
var dailyChart=null;function fmt(n){if(n>=1e6)return(n/1e6).toFixed(1)+'M';if(n>=1e3)return(n/1e3).toFixed(1)+'K';return n.toString()}
function loadStatus(){$.get('?action=system_status',function(d){$('#system-status').removeClass('ok error').addClass(d.status);$('#status-text').text(d.status==='ok'?'Online':'Offline')})}
function loadToday(){$.get('?action=today_comparison',function(r){if(r.status!=='success')return;['clicks','opens','leads','unsubs','bounces'].forEach(function(m){var d=r.data[m];$('#'+m+'-value').text(fmt(d.today));$('#'+m+'-yesterday').text('vs yesterday: '+fmt(d.yesterday));var el=$('#'+m+'-change').removeClass('up down neutral');if(d.diff>0)el.addClass('up').text('+'+d.pct+'%');else if(d.diff<0)el.addClass('down').text(d.pct+'%');else el.addClass('neutral').text('0%')})})}
function loadDaily(days){$.get('?action=daily_stats&days='+days,function(r){if(r.status!=='success')return;var labels=r.data.map(function(d){return d.label});var ds=[{label:'Clicks',data:r.data.map(function(d){return d.clicks}),borderColor:'#2563eb',backgroundColor:'rgba(37,99,235,0.1)',tension:0.3,fill:true},{label:'Opens',data:r.data.map(function(d){return d.opens}),borderColor:'#10b981',backgroundColor:'rgba(16,185,129,0.1)',tension:0.3,fill:true},{label:'Leads',data:r.data.map(function(d){return d.leads}),borderColor:'#f59e0b',backgroundColor:'rgba(245,158,11,0.1)',tension:0.3,fill:true}];if(dailyChart){dailyChart.data.labels=labels;dailyChart.data.datasets=ds;dailyChart.update()}else{dailyChart=new Chart(document.getElementById('dailyChart').getContext('2d'),{type:'line',data:{labels:labels,datasets:ds},options:{responsive:true,maintainAspectRatio:false,plugins:{legend:{position:'top'}},scales:{y:{beginAtZero:true},x:{}}}})}})}
function loadGlobal(p){$.get('?action=global_stats&period='+p,function(r){if(r.status!=='success')return;$('#global-clicks').text(fmt(r.data.clicks));$('#global-opens').text(fmt(r.data.opens));$('#global-leads').text(fmt(r.data.leads));$('#global-unsubs').text(fmt(r.data.unsubs));$('#global-bounces').text(fmt(r.data.bounces))})}
function loadActivity(){$.get('?action=recent_activity',function(r){if(r.status!=='success')return;var html='';if(r.data.length===0){html='<div class="loading">No activity</div>'}else{r.data.forEach(function(i){var ic=i.action_name==='click'?'click':(i.action_name==='open'?'open':'lead');var ico=ic==='click'?'fa-mouse-pointer':(ic==='open'?'fa-envelope-open':'fa-user-plus');html+='<div class="activity-item"><div class="activity-icon '+ic+'"><i class="fa '+ico+'"></i></div><div class="activity-info"><div class="type">'+i.action_name+'</div><div class="details">Process: '+i.process_id+'</div></div><div class="activity-time">'+new Date(i.action_time).toLocaleTimeString()+'</div></div>'})}$('#activity-feed').html(html)})}
$(document).ready(function(){loadStatus();loadToday();loadDaily(14);loadGlobal('month');loadActivity();$('.period-btn:not(.global-btn)').click(function(){$(this).siblings().removeClass('active');$(this).addClass('active');loadDaily($(this).data('days'))});$('.global-btn').click(function(){$(this).siblings().removeClass('active');$(this).addClass('active');loadGlobal($(this).data('period'))});setInterval(function(){loadStatus();loadToday();loadActivity()},30000)});
</script>
<?php include("includes/chatbot-widget.php"); ?>
</body>
</html>