UI redesign step 3: Provisionen in Stitch style
- Page header with title/subtitle on the left, primary PDF-Export
pill on the right.
- Filter bar matches the Übersicht layout: fixed-width fields with
label-caps labels, mono inputs for IDs/phone/date, range picker
in a 320px slot, Zurücksetzen pill on the right.
- Three KPI cards above the table: Shop-Provision and
Mitarbeiter-Provision in plain surface cards, total highlighted
with a primary-tinted border, shadow and bold accent number. All
use the JetBrains-Mono display-lg numeric font.
- Data table follows the same shell as Übersicht: sticky surface-
container-high header, label-caps column titles, 40px rows with
zebra stripes and hover. Anbieter renders as a primary pill. Shop-
and MA-amounts right-aligned and monospaced; "Quelle" replaced
with a single info glyph tooltip showing the source description.
- New formatEuro() helper renders amounts as "1.234,56 €" using
toLocaleString('de-DE'), so the totals and the cells share a
consistent German currency format.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
45c0c0047f
commit
b88938a1f6
2 files changed
+144
-91
No files matched your search
+46
-33
@@ -2285,50 +2285,63 @@ function updateSchaltungenTable(schaltungen) {
|
||||
renderSchaltungenRows(schaltungen);
|
||||
}
|
||||
|
||||
// Update Provisionen table with filtered data
|
||||
// Format a number as German currency: 1234.5 -> "1.234,50 €"
|
||||
function formatEuro(value) {
|
||||
const n = Number(value) || 0;
|
||||
return n.toLocaleString('de-DE', { minimumFractionDigits: 2, maximumFractionDigits: 2 }) + ' €';
|
||||
}
|
||||
|
||||
// Update Provisionen table with filtered data (Stitch style).
|
||||
function updateProvisionenTable(schaltungen, totalShopProvision, totalMitarbeiterProvision) {
|
||||
const tbody = document.querySelector('#provisionenTable tbody');
|
||||
const totalShopSpan = document.getElementById('totalShopProvision');
|
||||
const totalMitarbeiterSpan = document.getElementById('totalMitarbeiterProvision');
|
||||
|
||||
const totalGesamtSpan = document.getElementById('totalGesamtProvision');
|
||||
|
||||
if (!tbody) return;
|
||||
|
||||
|
||||
tbody.innerHTML = '';
|
||||
|
||||
if (schaltungen.length === 0) {
|
||||
// Show "no results" message
|
||||
const row = document.createElement('tr');
|
||||
row.innerHTML = `
|
||||
<td colspan="11" style="text-align: center; padding: 40px; color: #7f8c8d; font-style: italic; font-size: 16px;">
|
||||
💰 Keine Provisionen entsprechen den gewählten Filterkriterien
|
||||
</td>
|
||||
`;
|
||||
tbody.appendChild(row);
|
||||
|
||||
// Reset totals to 0
|
||||
if (totalShopSpan) totalShopSpan.textContent = '0,00 €';
|
||||
if (totalMitarbeiterSpan) totalMitarbeiterSpan.textContent = '0,00 €';
|
||||
|
||||
if (!schaltungen || schaltungen.length === 0) {
|
||||
const tr = document.createElement('tr');
|
||||
tr.innerHTML = '<td colspan="8" class="px-md py-lg text-center text-body-sm text-on-surface-variant">Keine Provisionen entsprechen den Filterkriterien</td>';
|
||||
tbody.appendChild(tr);
|
||||
if (totalShopSpan) totalShopSpan.textContent = formatEuro(0);
|
||||
if (totalMitarbeiterSpan) totalMitarbeiterSpan.textContent = formatEuro(0);
|
||||
if (totalGesamtSpan) totalGesamtSpan.textContent = formatEuro(0);
|
||||
return;
|
||||
}
|
||||
|
||||
schaltungen.forEach(s => {
|
||||
const row = document.createElement('tr');
|
||||
|
||||
row.innerHTML = `
|
||||
<td>${escapeHtml(s.schaltungs_id)}</td>
|
||||
<td>${escapeHtml(formatDate(s.schaltungs_datum))}</td>
|
||||
<td>${escapeHtml(s.vorname)} ${escapeHtml(s.nachname)}</td>
|
||||
<td>${escapeHtml(s.anbieter_name)}</td>
|
||||
<td>${escapeHtml(s.tarif_name)}</td>
|
||||
<td><strong>${escapeHtml(s.berechnete_shop_provision || '0.00')} €</strong></td>
|
||||
<td><strong>${escapeHtml(s.berechnete_mitarbeiter_provision || '0.00')} €</strong></td>
|
||||
schaltungen.forEach(s => {
|
||||
const shop = Number(s.berechnete_shop_provision) || 0;
|
||||
const ma = Number(s.berechnete_mitarbeiter_provision) || 0;
|
||||
const quelle = s.shop_quelle || s.quelle || '';
|
||||
const tr = document.createElement('tr');
|
||||
tr.className = 'border-b border-outline-variant/30 even:bg-surface-container-low/50 hover:bg-surface-variant/30 transition-colors';
|
||||
tr.innerHTML = `
|
||||
<td class="px-md py-xs font-label-numeric text-label-numeric text-right text-on-surface-variant">${escapeHtml(s.schaltungs_id)}</td>
|
||||
<td class="px-md py-xs font-label-numeric text-label-numeric text-on-surface">${escapeHtml(formatDate(s.schaltungs_datum))}</td>
|
||||
<td class="px-md py-xs">
|
||||
<div class="font-semibold text-on-background">${escapeHtml((s.vorname || '') + ' ' + (s.nachname || ''))}</div>
|
||||
<div class="text-[12px] text-on-surface-variant">${escapeHtml(s.firma || '–')}</div>
|
||||
</td>
|
||||
<td class="px-md py-xs">
|
||||
<span class="bg-primary/10 text-primary border border-primary/20 px-2 py-0.5 rounded-full text-label-caps">${escapeHtml(s.anbieter_name || '')}</span>
|
||||
</td>
|
||||
<td class="px-md py-xs">${escapeHtml(s.tarif_name || '')}</td>
|
||||
<td class="px-md py-xs font-label-numeric text-label-numeric text-right text-on-surface font-semibold">${escapeHtml(formatEuro(shop))}</td>
|
||||
<td class="px-md py-xs font-label-numeric text-label-numeric text-right text-on-surface font-semibold">${escapeHtml(formatEuro(ma))}</td>
|
||||
<td class="px-md py-xs text-center">
|
||||
<span class="material-symbols-outlined text-outline hover:text-primary transition-colors text-[18px] cursor-help" title="${escapeHtml(quelle)}">info</span>
|
||||
</td>
|
||||
`;
|
||||
tbody.appendChild(row);
|
||||
tbody.appendChild(tr);
|
||||
});
|
||||
|
||||
// Update totals
|
||||
if (totalShopSpan) totalShopSpan.textContent = `${totalShopProvision.toFixed(2)} €`;
|
||||
if (totalMitarbeiterSpan) totalMitarbeiterSpan.textContent = `${totalMitarbeiterProvision.toFixed(2)} €`;
|
||||
|
||||
const totalGesamt = (totalShopProvision || 0) + (totalMitarbeiterProvision || 0);
|
||||
if (totalShopSpan) totalShopSpan.textContent = formatEuro(totalShopProvision);
|
||||
if (totalMitarbeiterSpan) totalMitarbeiterSpan.textContent = formatEuro(totalMitarbeiterProvision);
|
||||
if (totalGesamtSpan) totalGesamtSpan.textContent = formatEuro(totalGesamt);
|
||||
}
|
||||
|
||||
// Clear filters functions
|
||||
|
||||
Reference in new issue
Block a user