feat: include balance for home page
This commit is contained in:
+53
-9
@@ -92,9 +92,9 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-6 col-sm-3">
|
||||
<div class="stat-card border-0">
|
||||
<div class="stat-label">Estimated Cost</div>
|
||||
<div class="stat-value" id="stat-cost">—</div>
|
||||
<div class="stat-card border-0" id="spendCard" role="button" tabindex="0" style="cursor:pointer;">
|
||||
<div class="stat-label" id="stat-spend-label">Balance</div>
|
||||
<div class="stat-value" id="stat-spend">—</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -280,23 +280,67 @@
|
||||
}
|
||||
}
|
||||
|
||||
let spendView = 'balance';
|
||||
let spendData = { balance: null, currency: null, estimatedCost: null };
|
||||
|
||||
function formatCurrency(amount, currency) {
|
||||
if (amount == null || Number.isNaN(Number(amount))) return '—';
|
||||
const sym = currency === 'GBP' ? '£' : currency === 'USD' ? '$' : currency === 'EUR' ? '€' : (currency ?? '');
|
||||
return sym + Number(amount).toFixed(2);
|
||||
}
|
||||
|
||||
function renderSpendCard() {
|
||||
const labelEl = document.getElementById('stat-spend-label');
|
||||
const valueEl = document.getElementById('stat-spend');
|
||||
if (!labelEl || !valueEl) return;
|
||||
|
||||
if (spendView === 'cost') {
|
||||
labelEl.textContent = 'EST. COST';
|
||||
valueEl.textContent = formatCurrency(spendData.estimatedCost, spendData.currency);
|
||||
return;
|
||||
}
|
||||
|
||||
labelEl.textContent = 'Balance';
|
||||
valueEl.textContent = formatCurrency(spendData.balance, spendData.currency);
|
||||
}
|
||||
|
||||
function toggleSpendCard() {
|
||||
spendView = spendView === 'balance' ? 'cost' : 'balance';
|
||||
renderSpendCard();
|
||||
}
|
||||
|
||||
async function loadStats() {
|
||||
try {
|
||||
const [att, log] = await Promise.all([
|
||||
const [att, log, bal, cost, admin] = await Promise.all([
|
||||
fetch('/api/attendees.php').then(r => r.json()),
|
||||
fetch('/api/delivery-log.php').then(r => r.json()),
|
||||
fetch('/api/balance.php').then(r => r.json()),
|
||||
fetch('/api/settings.php?key=clickatell_cost_per_sms').then(r => r.json()),
|
||||
fetch('/api/admin.php').then(r => r.json()),
|
||||
]);
|
||||
document.getElementById('stat-attendees').textContent = att.total ?? '—';
|
||||
document.getElementById('stat-sent').textContent = log.stats?.total_sent ?? '—';
|
||||
const rate = log.stats?.success_rate;
|
||||
document.getElementById('stat-rate').textContent = rate != null ? rate + '%' : '—';
|
||||
const sent = log.stats?.total_sent;
|
||||
const costPerSms = parseFloat((await fetch('/api/settings.php?key=clickatell_cost_per_sms').then(r => r.json())).value ?? '0.04849');
|
||||
document.getElementById('stat-cost').textContent = sent != null
|
||||
? '£' + (sent * costPerSms).toFixed(2)
|
||||
: '—';
|
||||
spendData.balance = bal.balance != null ? Number(bal.balance) : null;
|
||||
spendData.currency = bal.currency ?? 'GBP';
|
||||
|
||||
const realSent = Number(admin.delivery_log_real_sent);
|
||||
const costPerSms = Number(cost.value);
|
||||
spendData.estimatedCost = Number.isFinite(realSent) && Number.isFinite(costPerSms)
|
||||
? realSent * costPerSms
|
||||
: null;
|
||||
|
||||
renderSpendCard();
|
||||
} catch { /* DB unavailable — stats stay as dashes */ }
|
||||
}
|
||||
document.getElementById('spendCard')?.addEventListener('click', toggleSpendCard);
|
||||
document.getElementById('spendCard')?.addEventListener('keydown', e => {
|
||||
if (e.key === 'Enter' || e.key === ' ') {
|
||||
e.preventDefault();
|
||||
toggleSpendCard();
|
||||
}
|
||||
});
|
||||
loadStats();
|
||||
setInterval(() => loadStats(), 10_000);
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user