Owner agenda: per-Filiale show/hide toggle
Test backoffice (smb-crm) / test (push) Successful in 1m41s
Test backoffice (smb-crm) / test (push) Successful in 1m41s
Checkboxes above the week view, one per active resource -- client-side filtering (no reload needed), remembered across week navigation via localStorage since each week change is a full page load. Lets the owner view one location, the other, or both at once. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -40,11 +40,30 @@
|
|||||||
.new-booking { border: 1px solid var(--line); border-radius: 10px; padding: 16px; margin-top: 24px; }
|
.new-booking { border: 1px solid var(--line); border-radius: 10px; padding: 16px; margin-top: 24px; }
|
||||||
.new-booking .field { display: inline-block; margin: 0 8px 8px 0; }
|
.new-booking .field { display: inline-block; margin: 0 8px 8px 0; }
|
||||||
label { display: block; font-size: .75rem; color: var(--muted); margin-bottom: 3px; }
|
label { display: block; font-size: .75rem; color: var(--muted); margin-bottom: 3px; }
|
||||||
|
.filiale-filter { display: flex; gap: 16px; align-items: center; flex-wrap: wrap;
|
||||||
|
margin: 10px 0 18px; padding: 10px 14px; background: #f6faf9; border: 1px solid var(--line);
|
||||||
|
border-radius: 9px; }
|
||||||
|
.filiale-filter .flabel { font-size: .78rem; color: var(--muted); margin: 0; }
|
||||||
|
.filiale-filter label { display: flex; align-items: center; gap: 6px; margin: 0;
|
||||||
|
font-size: .85rem; color: var(--ink); cursor: pointer; }
|
||||||
|
.filiale-filter input[type=checkbox] { width: 15px; height: 15px; accent-color: var(--brand);
|
||||||
|
cursor: pointer; }
|
||||||
|
tr.res-hidden { display: none; }
|
||||||
|
.day-no-match { color: var(--muted); font-size: .85rem; margin: 0; display: none; }
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<h1>{{ client.business_name if client else 'Kalender' }}</h1>
|
<h1>{{ client.business_name if client else 'Kalender' }}</h1>
|
||||||
|
|
||||||
|
{% if resources|length > 1 %}
|
||||||
|
<div class="filiale-filter" id="filialeFilter">
|
||||||
|
<p class="flabel">Filialen:</p>
|
||||||
|
{% for r in resources %}
|
||||||
|
<label><input type="checkbox" class="res-toggle" value="{{ r.resource_id }}" checked> {{ r.name }}</label>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
{% if error == "missing_fields" %}
|
{% if error == "missing_fields" %}
|
||||||
<div class="error">Bitte alle Felder ausfüllen.</div>
|
<div class="error">Bitte alle Felder ausfüllen.</div>
|
||||||
{% elif error == "not_found" %}
|
{% elif error == "not_found" %}
|
||||||
@@ -78,7 +97,7 @@
|
|||||||
<thead><tr><th>Zeit</th><th>Kunde</th><th>Leistung</th><th>Ressource</th><th>Status</th><th></th></tr></thead>
|
<thead><tr><th>Zeit</th><th>Kunde</th><th>Leistung</th><th>Ressource</th><th>Status</th><th></th></tr></thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{% for b in bookings %}
|
{% for b in bookings %}
|
||||||
<tr class="status-{{ b.status }}">
|
<tr class="status-{{ b.status }}" data-resource="{{ b.resource_id }}">
|
||||||
<td>{{ b.start_local.strftime('%H:%M') }}</td>
|
<td>{{ b.start_local.strftime('%H:%M') }}</td>
|
||||||
<td>{{ b.customer_name }}</td>
|
<td>{{ b.customer_name }}</td>
|
||||||
<td>{{ b.service }}</td>
|
<td>{{ b.service }}</td>
|
||||||
@@ -103,6 +122,7 @@
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
<p class="day-no-match">Keine Buchungen für die ausgewählten Filialen.</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
@@ -146,5 +166,44 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p class="muted" style="margin-top:20px;"><a href="{{ url_for('owner_auth.dashboard') }}">Zurück</a></p>
|
<p class="muted" style="margin-top:20px;"><a href="{{ url_for('owner_auth.dashboard') }}">Zurück</a></p>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// Per-Filiale show/hide (#toggle both/either), remembered across
|
||||||
|
// week navigation via localStorage since each week is a full page load.
|
||||||
|
(function () {
|
||||||
|
var STORAGE_KEY = 'ownerAgendaFilialeFilter';
|
||||||
|
var checkboxes = document.querySelectorAll('.res-toggle');
|
||||||
|
if (!checkboxes.length) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
var saved = JSON.parse(localStorage.getItem(STORAGE_KEY) || 'null');
|
||||||
|
if (saved && saved.length) {
|
||||||
|
checkboxes.forEach(function (cb) { cb.checked = saved.indexOf(cb.value) !== -1; });
|
||||||
|
}
|
||||||
|
} catch (e) {}
|
||||||
|
|
||||||
|
function applyFilter() {
|
||||||
|
var active = [];
|
||||||
|
checkboxes.forEach(function (cb) { if (cb.checked) active.push(cb.value); });
|
||||||
|
document.querySelectorAll('table tbody tr[data-resource]').forEach(function (tr) {
|
||||||
|
tr.classList.toggle('res-hidden', active.indexOf(tr.getAttribute('data-resource')) === -1);
|
||||||
|
});
|
||||||
|
document.querySelectorAll('.day').forEach(function (dayEl) {
|
||||||
|
var table = dayEl.querySelector('table');
|
||||||
|
var noMatch = dayEl.querySelector('.day-no-match');
|
||||||
|
if (!table) return;
|
||||||
|
var anyVisible = Array.prototype.some.call(
|
||||||
|
table.querySelectorAll('tbody tr'),
|
||||||
|
function (tr) { return !tr.classList.contains('res-hidden'); });
|
||||||
|
table.style.display = anyVisible ? '' : 'none';
|
||||||
|
if (noMatch) noMatch.style.display = anyVisible ? 'none' : 'block';
|
||||||
|
});
|
||||||
|
try { localStorage.setItem(STORAGE_KEY, JSON.stringify(active)); } catch (e) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
checkboxes.forEach(function (cb) { cb.addEventListener('change', applyFilter); });
|
||||||
|
applyFilter();
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
Reference in New Issue
Block a user