{% extends "base.html" %} {% block title %}Dashboard{% endblock %} {% block content %} {# ── Grouped dashboard styling (colored section cards + white stat tiles) ──── #} {# Handler ("Handled by") breakdown chips for an issue KPI tile. `base` is a dict of extra issues.index query params identifying the tile's scope. #} {% macro handler_chips(bd, base) %}
Handled by: {% if bd.internal > 0 %} Janitorial {{ bd.internal }}{% endif %} {% if bd.facility > 0 %} Facility {{ bd.facility }}{% endif %} {% if bd.vendor > 0 %} Vendor {{ bd.vendor }}{% endif %}
{% endmacro %} {# One white stat tile: label (+ optional subtitle OR handler chips) left, big colored number right. Numbers render two-digit (01, 02, …) to match the design. When chips_bd is given and the value is > 0, the handler chips replace the subtitle; because the chips are themselves links, the whole tile is NOT wrapped in an anchor (nested is invalid) — only the number links. #} {% macro stat_tile(label, value, accent, href=None, subtitle=None, chips_bd=None, chips_base=None) %} {% set has_chips = chips_bd is not none and value and value > 0 %}
{% if href and not has_chips %}{% endif %}
{{ label }}
{% if has_chips %} {{ handler_chips(chips_bd, chips_base) }} {% elif subtitle %}
{{ subtitle }}
{% endif %}
{% if href and has_chips %} {{ '%02d'|format(value) }} {% else %} {{ '%02d'|format(value) if value is number else value }} {% endif %}
{% if href and not has_chips %}{% endif %}
{% endmacro %}

Welcome, {{ current_user.display_name }}!

{{ current_user.role.replace('_',' ')|title }}
{# ══════════════════════════════════════════════════════════════════════════ A. SCHEDULED INSPECTION (blue) ══════════════════════════════════════════════════════════════════════════ #} {% if current_user.role != 'customer' %}
Scheduled Inspection View all
{% if sched_overdue_count %}
{{ sched_overdue_count }} scheduled inspection{{ 's' if sched_overdue_count != 1 }} {{ 'are' if sched_overdue_count != 1 else 'is' }} overdue.
{% endif %} {% if sched_upcoming %}
{% for s in sched_upcoming %} {% endfor %}
Facility NameInspection TemplateInspector Name How Often?Due
{{ s.facility.name if s.facility else '—' }} {{ s.template.name if s.template else '—' }} {{ s.inspector.display_name if s.inspector else '—' }} {{ s.recurrence_label }} {{ s.next_due_date.strftime('%b %d') }} {# Start is shown only to the assignee — the inspection is theirs to do. #} {% if s.inspector_id and s.inspector_id == current_user.id %} {# Receipt confirmation (phase47) — assignee confirms, or shows confirmed. #} {% if s.is_acknowledged %} Confirmed {% else %}
{% endif %} {% set open_id = sched_open_inspections.get(s.id) %} {% if open_id %} Continue {% else %} Start {% endif %} {% endif %}
{% else %}
No inspections due in the next 7 days.
{% endif %}
{% endif %} {# ══════════════════════════════════════════════════════════════════════════ B. QUICK REVIEW (green) ══════════════════════════════════════════════════════════════════════════ #} {% set G = '#4e8a2f' %}
Quick Review
{{ stat_tile('Submitted Today', completed_today, G, url_for('inspections.index', status='completed', date_from=today_str, date_to=today_str), 'Completed & submitted today') }} {{ stat_tile('Submitted This Week', submitted_this_week, G, url_for('inspections.index', status='completed', date_from=week_start_str, date_to=today_str), 'Completed & submitted this week') }} {% if current_user.role != 'customer' %} {{ stat_tile('In Progress', in_progress_total, G, url_for('inspections.index', status='in_progress'), (stale_in_progress ~ ' stale >24h') if stale_in_progress else 'Started, not yet submitted') }} {{ stat_tile('Pending Follow-ups', pending_followups, G, url_for('inspections.index', status='follow_up'), 'Flagged for re-inspection') }} {{ stat_tile('On Schedules', sched_total, G, url_for('scheduled_inspections.index'), 'Active scheduled plans') }} {% endif %}
{# ══════════════════════════════════════════════════════════════════════════ C. REVIEW ISSUES (orange) ══════════════════════════════════════════════════════════════════════════ #} {% set O = '#d5761a' %}
Review Issues
{{ stat_tile('Open · Janitorial', handler_breakdown.internal, O, url_for('issues.index', status='open', handler_type='internal'), 'Handled by our crew') }} {{ stat_tile('Open · Facility Staff', handler_breakdown.facility, O, url_for('issues.index', status='open', handler_type='facility'), 'Handled by facility staff') }} {{ stat_tile('Open · Vendors', handler_breakdown.vendor, O, url_for('issues.index', status='open', handler_type='vendor'), 'Handled by outside vendor') }} {% if current_user.role != 'customer' %} {{ stat_tile('Open · Unassigned', unassigned_open, O, url_for('issues.index', status='open', unassigned='1'), 'No one assigned yet', chips_bd=unassigned_handler, chips_base={'status': 'open', 'unassigned': '1'}) }} {{ stat_tile('Pending · Verification', pending_verification, O, url_for('issues.index', status='pending_verification'), 'Awaiting sign-off') }} {% endif %} {# All the original Issues cards are kept here in the same colored group. #} {{ stat_tile('Issues Opened Today', issues_opened_today, O, url_for('issues.index', date_from=today_str, date_to=today_str), 'New issues reported today', chips_bd=opened_today_handler, chips_base={'date_from': today_str, 'date_to': today_str}) }} {{ stat_tile('Resolved Today', resolved_today, O, url_for('issues.index', status='resolved', date_from=today_str, date_to=today_str), 'Issues closed today') }}
{# ══════════════════════════════════════════════════════════════════════════ D. SLA ALERT (grey) ══════════════════════════════════════════════════════════════════════════ #} {# Section D shows only when there is at least one at-risk or breached issue. #} {% if sla_breached > 0 or sla_at_risk > 0 %} {% set R = '#cc0000' %}
SLA Alert
{{ stat_tile('SLA At Risk', sla_at_risk, R, url_for('issues.index', sla='at_risk'), 'Approaching their SLA deadline') }} {{ stat_tile('SLA Alert', sla_breached, R, url_for('issues.index', sla='breached'), 'Past their SLA deadline') }}
{% endif %} {# ── Recent activity ─────────────────────────────────────────────────────── #}
Recent Activity
{% if recent_inspections %}
{% if current_user.role != 'inspector' %}{% endif %} {% for insp in recent_inspections %} {% if current_user.role != 'inspector' %}{% endif %} {% endfor %}
Date Facility AreaInspectorScore Status
{{ insp.inspection_date.strftime('%Y-%m-%d %H:%M') }} {{ insp.facility.name }} {{ insp.area.name if insp.area else '—' }}{{ insp.inspector.display_name }} {% if insp.overall_score %} {{ insp.overall_score }}% {% else %} {% endif %} {{ 'Submitted' if insp.status == 'completed' else insp.status|title }}
{% else %}
No recent inspections.
{% endif %}
{# ── Inspector activity today (admin / director / PM) ───────────────────── #} {% if inspector_activity %}
Inspector Activity Today View all
{% for row in inspector_activity %} {% endfor %}
Inspector Submitted Today
{{ row.name }} {% if row.count > 0 %} {{ row.count }} {% else %} {% endif %}
{% set max_count = inspector_activity | map(attribute='count') | max %} {% set pct = (row.count / max_count * 100) | int if max_count > 0 else 0 %}
{% endif %} {# ── My open issues (inspector widget) ──────────────────────────────────── #} {% if my_issues %}
My Open Issues View all
{% for issue in my_issues %} {% set sla = sla_status(issue) %} {% endfor %}
ID Severity Facility / Description Status SLA
#{{ issue.id }} {{ issue.severity|title }}
{{ issue.resolved_facility.name if issue.resolved_facility else '—' }}
{{ issue.description[:60] }}{% if issue.description|length > 60 %}…{% endif %}
{{ issue.status|replace('_',' ')|title }} {% if sla == 'breached' %} Breached {% elif sla == 'at_risk' %} {{ sla_hours_remaining(issue)|abs|round(1) }}h left {% else %} OK {% endif %}
{% endif %} {# ── Customer portal: scoped facilities panel ───────────────────────────── #} {% if current_user.role == 'customer' %}
Your Facilities {% if customer_facilities %} {{ customer_facilities|length }} {% endif %}
{% if customer_facilities %}
{% if customer_facilities|length > 6 %}
{% endif %}
{% for f in customer_facilities %}
{{ f.name }}
{{ f.address or '—' }}
{{ f.project.name if f.project else '—' }}
{% endfor %}
{% if customer_facilities|length > 9 %}
{% endif %}
{% else %}
No facilities have been assigned to your account yet. Please contact your administrator.
{% endif %}
{% endif %} {% endblock %}