fix(telefoni): keep SSR call rows when initial API refresh is empty

This commit is contained in:
Christian 2026-05-17 09:44:28 +02:00
parent e162ee3fe1
commit 08f40977f9

View File

@ -61,7 +61,7 @@
<tbody id="telefoniRows"> <tbody id="telefoniRows">
{% if initial_calls and initial_calls|length > 0 %} {% if initial_calls and initial_calls|length > 0 %}
{% for call in initial_calls %} {% for call in initial_calls %}
<tr> <tr data-call-id="{{ call.id }}">
<td>{{ call.started_at or '-' }}</td> <td>{{ call.started_at or '-' }}</td>
<td>{{ call.full_name or call.username or '-' }}</td> <td>{{ call.full_name or call.username or '-' }}</td>
<td>{% if call.direction == 'outbound' %}Udgående{% else %}Indgående{% endif %}</td> <td>{% if call.direction == 'outbound' %}Udgående{% else %}Indgående{% endif %}</td>
@ -846,9 +846,28 @@ async function loadUsers() {
} }
} }
async function loadCalls() { function hasExistingCallRows(tbody) {
return Boolean(tbody && tbody.querySelector('tr[data-call-id]'));
}
function hasActiveCallFilters() {
const userId = document.getElementById('filterUser')?.value;
const from = document.getElementById('filterFrom')?.value;
const to = document.getElementById('filterTo')?.value;
const withoutCase = document.getElementById('filterWithoutCase')?.checked;
return Boolean(userId || from || to || withoutCase);
}
async function loadCalls(options = {}) {
const preserveOnEmpty = Boolean(options.preserveOnEmpty);
const skipLoadingState = Boolean(options.skipLoadingState);
const tbody = document.getElementById('telefoniRows'); const tbody = document.getElementById('telefoniRows');
tbody.innerHTML = '<tr><td colspan="7" class="text-muted small"><span class="spinner-border spinner-border-sm me-2"></span>Indlæser...</td></tr>'; const hadRowsBeforeLoad = hasExistingCallRows(tbody);
const noActiveFilters = !hasActiveCallFilters();
if (!skipLoadingState) {
tbody.innerHTML = '<tr><td colspan="7" class="text-muted small"><span class="spinner-border spinner-border-sm me-2"></span>Indlæser...</td></tr>';
}
const userId = document.getElementById('filterUser').value; const userId = document.getElementById('filterUser').value;
const from = document.getElementById('filterFrom').value; const from = document.getElementById('filterFrom').value;
@ -865,6 +884,10 @@ async function loadCalls() {
const res = await fetch('/api/v1/telefoni/calls?' + qs.toString(), { credentials: 'include' }); const res = await fetch('/api/v1/telefoni/calls?' + qs.toString(), { credentials: 'include' });
if (!res.ok) { if (!res.ok) {
const t = await res.text(); const t = await res.text();
if (preserveOnEmpty && hadRowsBeforeLoad && noActiveFilters) {
console.warn('Telefoni: bevarer SSR-rækker efter tom/fejlende auto-refresh');
return;
}
tbody.innerHTML = `<tr><td colspan="7" class="text-danger small">Fejl: ${escapeHtml(t)}</td></tr>`; tbody.innerHTML = `<tr><td colspan="7" class="text-danger small">Fejl: ${escapeHtml(t)}</td></tr>`;
return; return;
} }
@ -872,6 +895,10 @@ async function loadCalls() {
telefoniCallMap.clear(); telefoniCallMap.clear();
(rows || []).forEach(r => telefoniCallMap.set(Number(r.id), r)); (rows || []).forEach(r => telefoniCallMap.set(Number(r.id), r));
if (!rows || rows.length === 0) { if (!rows || rows.length === 0) {
if (preserveOnEmpty && hadRowsBeforeLoad && noActiveFilters) {
console.warn('Telefoni: API returnerede 0 rækker, bevarer eksisterende SSR-visning');
return;
}
tbody.innerHTML = '<tr><td colspan="7" class="text-muted small">Ingen opkald fundet</td></tr>'; tbody.innerHTML = '<tr><td colspan="7" class="text-muted small">Ingen opkald fundet</td></tr>';
return; return;
} }
@ -928,7 +955,7 @@ async function loadCalls() {
: '<span class="text-muted small">Ingen sag</span>'); : '<span class="text-muted small">Ingen sag</span>');
return ` return `
<tr> <tr data-call-id="${callId}">
<td>${escapeHtml(dateTxt)}</td> <td>${escapeHtml(dateTxt)}</td>
<td>${userTxt}</td> <td>${userTxt}</td>
<td>${escapeHtml(dirTxt)}</td> <td>${escapeHtml(dirTxt)}</td>
@ -941,6 +968,10 @@ async function loadCalls() {
}).join(''); }).join('');
} catch (e) { } catch (e) {
console.error('Failed loading calls', e); console.error('Failed loading calls', e);
if (preserveOnEmpty && hadRowsBeforeLoad && noActiveFilters) {
console.warn('Telefoni: bevarer SSR-rækker efter exception i auto-refresh');
return;
}
tbody.innerHTML = '<tr><td colspan="7" class="text-danger small">Kunne ikke hente opkald</td></tr>'; tbody.innerHTML = '<tr><td colspan="7" class="text-danger small">Kunne ikke hente opkald</td></tr>';
} }
} }
@ -1017,7 +1048,7 @@ document.addEventListener('DOMContentLoaded', async () => {
document.getElementById('filterFrom').addEventListener('change', loadCalls); document.getElementById('filterFrom').addEventListener('change', loadCalls);
document.getElementById('filterTo').addEventListener('change', loadCalls); document.getElementById('filterTo').addEventListener('change', loadCalls);
document.getElementById('filterWithoutCase').addEventListener('change', loadCalls); document.getElementById('filterWithoutCase').addEventListener('change', loadCalls);
await loadCalls(); await loadCalls({ preserveOnEmpty: true, skipLoadingState: true });
}); });
</script> </script>
{% endblock %} {% endblock %}