|
|
|
@@ -14,7 +14,7 @@
|
|
|
|
|
{# ── Header ───────────────────────────────────────────────────────────── #}
|
|
|
|
|
<div class="d-flex flex-wrap justify-content-between align-items-end mb-4 gap-2">
|
|
|
|
|
<div>
|
|
|
|
|
<div class="jqc-page-title" style="text-align:left;">Welcome, {{ current_user.display_name }}</div>
|
|
|
|
|
<div class="jqc-page-title">Welcome, {{ current_user.display_name }}</div>
|
|
|
|
|
<div class="jqc-page-sub">{{ current_user.role.replace('_',' ')|title }}</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="text-muted">{{ now_display }}</div>
|
|
|
|
@@ -242,8 +242,15 @@
|
|
|
|
|
</thead>
|
|
|
|
|
<tbody>
|
|
|
|
|
{% for insp in recent_inspections %}
|
|
|
|
|
<tr style="cursor:pointer;" onclick="window.location='{{ url_for('inspections.view', inspection_id=insp.id) }}'">
|
|
|
|
|
<td><small>{{ insp.inspection_date.strftime('%b %d, %Y') }}</small></td>
|
|
|
|
|
{# The row stays click-anywhere for the mouse, but the date is a real
|
|
|
|
|
link so the row is keyboard-reachable and openable in a new tab.
|
|
|
|
|
The guard stops the row handler from double-firing on that link. #}
|
|
|
|
|
<tr style="cursor:pointer;"
|
|
|
|
|
onclick="if(!event.target.closest('a')) window.location='{{ url_for('inspections.view', inspection_id=insp.id) }}'">
|
|
|
|
|
<td>
|
|
|
|
|
<a href="{{ url_for('inspections.view', inspection_id=insp.id) }}"
|
|
|
|
|
class="text-decoration-none"><small>{{ insp.inspection_date.strftime('%b %d, %Y') }}</small></a>
|
|
|
|
|
</td>
|
|
|
|
|
<td>{{ insp.facility.name }}</td>
|
|
|
|
|
<td>{{ insp.area.name if insp.area else '—' }}</td>
|
|
|
|
|
{% if current_user.role != 'inspector' %}<td>{{ insp.inspector.display_name }}</td>{% endif %}
|
|
|
|
@@ -383,10 +390,16 @@
|
|
|
|
|
<span class="jqc-tile-icon"><i class="bi bi-building"></i></span>Your Facilities
|
|
|
|
|
<span class="badge bg-secondary rounded-pill ms-2">{{ customer_facilities|length }}</span>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="row g-3">
|
|
|
|
|
{% if customer_facilities|length > 6 %}
|
|
|
|
|
<div class="mb-3">
|
|
|
|
|
<input type="text" id="facilitySearch" class="form-control form-control-sm"
|
|
|
|
|
placeholder="Search facilities…" aria-label="Search facilities">
|
|
|
|
|
</div>
|
|
|
|
|
{% endif %}
|
|
|
|
|
<div class="row g-3" id="facilityGrid">
|
|
|
|
|
{% for f in customer_facilities %}
|
|
|
|
|
<div class="col-12 col-sm-6 col-lg-4">
|
|
|
|
|
<div class="border rounded-3 p-3 h-100 d-flex flex-column">
|
|
|
|
|
<div class="col-12 col-sm-6 col-lg-4 facility-col">
|
|
|
|
|
<div class="border rounded-3 p-3 h-100 d-flex flex-column facility-card">
|
|
|
|
|
<div class="fw-semibold mb-1">{{ f.name }}</div>
|
|
|
|
|
<div class="text-muted" style="font-size:.82rem;">{{ f.address or '—' }}</div>
|
|
|
|
|
<div class="my-2">
|
|
|
|
@@ -402,7 +415,49 @@
|
|
|
|
|
</div>
|
|
|
|
|
{% endfor %}
|
|
|
|
|
</div>
|
|
|
|
|
{% if customer_facilities|length > 9 %}
|
|
|
|
|
<div id="facilityShowMore" class="text-center mt-3">
|
|
|
|
|
<button class="btn btn-sm btn-link text-muted" id="toggleFacilities">
|
|
|
|
|
Show all {{ customer_facilities|length }} facilities <i class="bi bi-chevron-down"></i>
|
|
|
|
|
</button>
|
|
|
|
|
</div>
|
|
|
|
|
{% endif %}
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
{# Same VISIBLE = 9 / search > 6 thresholds as the classic dashboard (rule 65). #}
|
|
|
|
|
<script>
|
|
|
|
|
(function () {
|
|
|
|
|
{% if customer_facilities|length > 9 %}
|
|
|
|
|
var VISIBLE = 9;
|
|
|
|
|
var cols = document.querySelectorAll('#facilityGrid .facility-col');
|
|
|
|
|
var btn = document.getElementById('toggleFacilities');
|
|
|
|
|
var expanded = false;
|
|
|
|
|
|
|
|
|
|
cols.forEach(function (c, i) { if (i >= VISIBLE) c.style.display = 'none'; });
|
|
|
|
|
|
|
|
|
|
btn.addEventListener('click', function () {
|
|
|
|
|
expanded = !expanded;
|
|
|
|
|
cols.forEach(function (c, i) {
|
|
|
|
|
if (i >= VISIBLE) c.style.display = expanded ? '' : 'none';
|
|
|
|
|
});
|
|
|
|
|
btn.innerHTML = expanded
|
|
|
|
|
? 'Show fewer <i class="bi bi-chevron-up"></i>'
|
|
|
|
|
: 'Show all {{ customer_facilities|length }} facilities <i class="bi bi-chevron-down"></i>';
|
|
|
|
|
});
|
|
|
|
|
{% endif %}
|
|
|
|
|
{% if customer_facilities|length > 6 %}
|
|
|
|
|
document.getElementById('facilitySearch').addEventListener('input', function () {
|
|
|
|
|
var q = this.value.toLowerCase();
|
|
|
|
|
document.querySelectorAll('#facilityGrid .facility-col').forEach(function (col) {
|
|
|
|
|
var match = col.querySelector('.facility-card').textContent.toLowerCase().includes(q);
|
|
|
|
|
col.style.display = match ? '' : 'none';
|
|
|
|
|
});
|
|
|
|
|
var more = document.getElementById('facilityShowMore');
|
|
|
|
|
if (more) more.style.display = this.value ? 'none' : '';
|
|
|
|
|
});
|
|
|
|
|
{% endif %}
|
|
|
|
|
})();
|
|
|
|
|
</script>
|
|
|
|
|
{% endif %}
|
|
|
|
|
|
|
|
|
|
{% endblock %}
|
|
|
|
|