48hr.email/infrastructure/web/public/javascripts/stats.js
2026-01-03 15:57:46 +01:00

112 lines
3.7 KiB
JavaScript

/**
* Statistics page functionality
* Handles Chart.js initialization and real-time updates via Socket.IO
*/
// Initialize stats chart if on stats page
document.addEventListener('DOMContentLoaded', function() {
const chartCanvas = document.getElementById('statsChart');
if (!chartCanvas) return; // Not on stats page
// Get initial data from global variable (set by template)
if (typeof window.initialStatsData === 'undefined') {
console.error('Initial stats data not found');
return;
}
const initialData = window.initialStatsData;
// Set up Socket.IO connection for real-time updates
if (typeof io !== 'undefined') {
const socket = io();
// Listen for stats updates (any email event: receive, delete, forward)
socket.on('stats-update', () => {
console.log('Stats update received, reloading page...');
location.reload();
});
socket.on('reconnect', () => {
console.log('Reconnected to server');
});
}
// Prepare chart data
const labels = initialData.map(d => {
const date = new Date(d.timestamp);
return date.toLocaleTimeString('en-US', { hour: '2-digit', minute: '2-digit' });
});
const ctx = chartCanvas.getContext('2d');
const chart = new Chart(ctx, {
type: 'line',
data: {
labels: labels,
datasets: [{
label: 'Received',
data: initialData.map(d => d.receives),
borderColor: '#9b4dca',
backgroundColor: 'rgba(155, 77, 202, 0.1)',
tension: 0.4,
fill: true
},
{
label: 'Deleted',
data: initialData.map(d => d.deletes),
borderColor: '#e74c3c',
backgroundColor: 'rgba(231, 76, 60, 0.1)',
tension: 0.4,
fill: true
},
{
label: 'Forwarded',
data: initialData.map(d => d.forwards),
borderColor: '#3498db',
backgroundColor: 'rgba(52, 152, 219, 0.1)',
tension: 0.4,
fill: true
}
]
},
options: {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
display: true,
position: 'top',
labels: {
color: getComputedStyle(document.documentElement).getPropertyValue('--color-text-light'),
font: { size: 14 }
}
},
tooltip: {
mode: 'index',
intersect: false
}
},
scales: {
y: {
beginAtZero: true,
ticks: {
color: getComputedStyle(document.documentElement).getPropertyValue('--color-text-dim'),
stepSize: 1
},
grid: {
color: 'rgba(255, 255, 255, 0.1)'
}
},
x: {
ticks: {
color: getComputedStyle(document.documentElement).getPropertyValue('--color-text-dim'),
maxRotation: 45,
minRotation: 45
},
grid: {
color: 'rgba(255, 255, 255, 0.05)'
}
}
}
}
});
});