Files
2026-06-29 17:27:36 -04:00

143 lines
4.7 KiB
HTML

{% extends "base.html" %}
{% block title %}Dashboard — Bid Checker{% endblock %}
{% block content %}
<div class="page-header">
<h1 class="page-title">Dashboard</h1>
<span class="text-muted" id="today-date"></span>
</div>
<!-- KPI Cards -->
<div class="kpi-grid">
<div class="kpi-card">
<div class="kpi-value">{{ stats.total_users }}</div>
<div class="kpi-label">Total Users</div>
</div>
<div class="kpi-card kpi-accent">
<div class="kpi-value">{{ stats.active_today }}</div>
<div class="kpi-label">Active Today</div>
</div>
<div class="kpi-card">
<div class="kpi-value">{{ stats.total_sites }}</div>
<div class="kpi-label">Total Sites</div>
</div>
<div class="kpi-card {{ 'kpi-warning' if stats.open_bids else '' }}">
<div class="kpi-value">{{ stats.open_bids }}</div>
<div class="kpi-label">Open Bids</div>
</div>
<div class="kpi-card {{ 'kpi-danger' if stats.bids_due_soon else '' }}">
<div class="kpi-value">{{ stats.bids_due_soon }}</div>
<div class="kpi-label">Due This Week</div>
</div>
<div class="kpi-card">
<div class="kpi-value">{{ stats.ai_analyses_30d }}</div>
<div class="kpi-label">AI Analyses (30d)</div>
</div>
</div>
<!-- Missed shifts alert -->
{% if missed %}
<div class="card mt-3" style="border-color:var(--warning-border)">
<div class="card-header" style="background:var(--warning-bg)">
<span class="card-title" style="color:var(--warning)">⚠ Missed Shifts Today</span>
<span class="text-muted text-sm">Users with 0 sites checked so far</span>
</div>
<table class="table table-sm">
<thead><tr><th>Shift</th><th>User</th><th>Sites Checked</th></tr></thead>
<tbody>
{% for m in missed %}
<tr>
<td>{{ m.shift_name }}</td>
<td>{{ m.full_name }}</td>
<td class="text-muted">{{ m.checked_sites }} / {{ m.total_sites }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% endif %}
<!-- Per-user completion table -->
<div class="card mt-4">
<div class="card-header">
<h2 class="card-title">Today's Completion</h2>
<div class="flex gap-1">
<button class="btn btn-ghost btn-sm" onclick="location.reload()">↻ Refresh</button>
<form method="post" action="{{ url_for('admin_shifts.send_incomplete_reminders') }}" style="display:inline"
onsubmit="return confirm('Send reminder emails to all staff with incomplete checks in shifts ending within 45 minutes?')">
<button class="btn btn-secondary btn-sm" type="submit">📧 Remind Incomplete</button>
</form>
</div>
</div>
<table class="table">
<thead>
<tr>
<th>User</th>
<th>Checked</th>
<th>Total</th>
<th style="width:200px">Progress</th>
<th>%</th>
</tr>
</thead>
<tbody>
{% for u in stats.user_stats %}
<tr>
<td>{{ u.full_name }}</td>
<td>{{ u.checked_count }}</td>
<td>{{ u.total_sites }}</td>
<td>
<div class="progress">
<div class="progress-bar {% if (u.pct_complete or 0) == 100 %}progress-success{% elif (u.pct_complete or 0) >= 50 %}progress-warn{% else %}progress-danger{% endif %}"
style="width: {{ u.pct_complete or 0 }}%"></div>
</div>
</td>
<td><strong>{{ u.pct_complete or 0 }}%</strong></td>
</tr>
{% else %}
<tr><td colspan="5" class="text-center text-muted">No user data for today.</td></tr>
{% endfor %}
</tbody>
</table>
</div>
<!-- Today's Check Notes -->
{% if check_notes %}
<div class="card mt-4">
<div class="card-header">
<h2 class="card-title">Today's Check Notes</h2>
<span class="text-muted text-sm">{{ check_notes|length }} note{{ 's' if check_notes|length != 1 }}</span>
</div>
<table class="table">
<thead>
<tr>
<th>Time</th>
<th>User</th>
<th>Website</th>
<th>Note</th>
</tr>
</thead>
<tbody>
{% for n in check_notes %}
<tr>
<td class="text-muted text-sm" style="white-space:nowrap">
{{ n.checked_at.strftime('%H:%M') if n.checked_at else '' }}
</td>
<td style="white-space:nowrap">{{ n.full_name }}</td>
<td>
<a href="{{ n.website_url }}" target="_blank" rel="noopener" class="link">{{ n.website_name }}</a>
</td>
<td style="white-space:pre-wrap; word-break:break-word">{{ n.user_note }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% endif %}
<script>
document.getElementById('today-date').textContent =
new Date().toLocaleDateString('en-US', {weekday:'long', year:'numeric', month:'long', day:'numeric'});
// Auto-refresh every 60 seconds
setTimeout(() => location.reload(), 60000);
</script>
{% endblock %}