bmc_hub/app/subscriptions/frontend/list.html

165 lines
5.8 KiB
HTML
Raw Normal View History

{% extends "shared/frontend/base.html" %}
{% block title %}Abonnementer - BMC Hub{% endblock %}
{% block content %}
<div class="container-fluid py-4">
<div class="row mb-4">
<div class="col">
<h1 class="h3 mb-0">🔁 Abonnementer</h1>
<p class="text-muted">Alle solgte, aktive abonnementer</p>
</div>
</div>
<div class="row g-3 mb-4" id="statsCards">
<div class="col-md-4">
<div class="card border-0 shadow-sm">
<div class="card-body">
<p class="text-muted small mb-1">Aktive Abonnementer</p>
<h3 class="mb-0" id="activeCount">-</h3>
</div>
</div>
</div>
<div class="col-md-4">
<div class="card border-0 shadow-sm">
<div class="card-body">
<p class="text-muted small mb-1">Total Pris (aktive)</p>
<h3 class="mb-0" id="totalAmount">-</h3>
</div>
</div>
</div>
<div class="col-md-4">
<div class="card border-0 shadow-sm">
<div class="card-body">
<p class="text-muted small mb-1">Gns. Pris</p>
<h3 class="mb-0" id="avgAmount">-</h3>
</div>
</div>
</div>
</div>
<div class="card border-0 shadow-sm">
<div class="card-header bg-white border-0 py-3">
<h5 class="mb-0">Aktive abonnementer</h5>
</div>
<div class="card-body p-0">
<div class="table-responsive">
<table class="table table-hover align-middle mb-0">
<thead class="bg-light">
<tr>
<th>Abonnement</th>
<th>Kunde</th>
<th>Sag</th>
<th>Produkt</th>
<th>Interval</th>
<th>Pris</th>
<th>Start</th>
<th>Status</th>
</tr>
</thead>
<tbody id="subscriptionsBody">
<tr>
<td colspan="8" class="text-center text-muted py-5">
<span class="spinner-border spinner-border-sm me-2"></span>Indlaeser...
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
<script>
async function loadSubscriptions() {
try {
const stats = await fetch('/api/v1/subscriptions/stats/summary').then(r => r.json());
document.getElementById('activeCount').textContent = stats.subscription_count || 0;
document.getElementById('totalAmount').textContent = formatCurrency(stats.total_amount || 0);
document.getElementById('avgAmount').textContent = formatCurrency(stats.avg_amount || 0);
const subscriptions = await fetch('/api/v1/subscriptions').then(r => r.json());
renderSubscriptions(subscriptions);
} catch (e) {
console.error('Error loading subscriptions:', e);
document.getElementById('subscriptionsBody').innerHTML = `
<tr><td colspan="8" class="text-center text-danger py-5">
<i class="bi bi-exclamation-triangle fs-1 mb-3"></i>
<p>Fejl ved indlaesning</p>
</td></tr>
`;
}
}
function renderSubscriptions(subscriptions) {
const tbody = document.getElementById('subscriptionsBody');
if (!subscriptions || subscriptions.length === 0) {
tbody.innerHTML = `
<tr><td colspan="8" class="text-center text-muted py-5">
<i class="bi bi-inbox fs-1 mb-3"></i>
<p>Ingen aktive abonnementer</p>
</td></tr>
`;
return;
}
tbody.innerHTML = subscriptions.map(sub => {
const intervalLabel = formatInterval(sub.billing_interval);
const statusBadge = getStatusBadge(sub.status);
const sagLink = sub.sag_id ? `<a href="/sag/${sub.sag_id}">${sub.sag_title || 'Sag #' + sub.sag_id}</a>` : '-';
const subNumber = sub.subscription_number || `#${sub.id}`;
return `
<tr>
<td><strong>${subNumber}</strong></td>
<td>${sub.customer_name || '-'}</td>
<td>${sagLink}</td>
<td>${sub.product_name || '-'}</td>
<td>${intervalLabel}${sub.billing_day ? ' (dag ' + sub.billing_day + ')' : ''}</td>
<td>${formatCurrency(sub.price || 0)}</td>
<td>${formatDate(sub.start_date)}</td>
<td>${statusBadge}</td>
</tr>
`;
}).join('');
}
function formatInterval(interval) {
const map = {
'monthly': 'Maaned',
'quarterly': 'Kvartal',
'yearly': 'Aar'
};
return map[interval] || interval || '-';
}
function getStatusBadge(status) {
const badges = {
'active': '<span class="badge bg-success">Aktiv</span>',
'paused': '<span class="badge bg-warning">Pauset</span>',
'cancelled': '<span class="badge bg-secondary">Opsagt</span>',
'draft': '<span class="badge bg-light text-dark">Kladde</span>'
};
return badges[status] || status || '-';
}
function formatCurrency(amount) {
return new Intl.NumberFormat('da-DK', {
style: 'currency',
currency: 'DKK',
minimumFractionDigits: 0,
maximumFractionDigits: 0
}).format(amount);
}
function formatDate(dateStr) {
if (!dateStr) return '-';
const date = new Date(dateStr);
return date.toLocaleDateString('da-DK');
}
document.addEventListener('DOMContentLoaded', loadSubscriptions);
</script>
{% endblock %}