feat(dashboard): add pending as separate stat card and progress bar segment
This commit is contained in:
+6
-4
@@ -593,7 +593,8 @@ def dashboard(request: Request, user: User = Depends(get_current_user_web), db:
|
|||||||
all_cards.extend(cards)
|
all_cards.extend(cards)
|
||||||
|
|
||||||
total = len(all_cards)
|
total = len(all_cards)
|
||||||
sent = sum(1 for c in all_cards if c.status in ("pending", "sent"))
|
pending = sum(1 for c in all_cards if c.status == "pending")
|
||||||
|
sent = sum(1 for c in all_cards if c.status == "sent")
|
||||||
delivered = sum(1 for c in all_cards if c.status == "delivered")
|
delivered = sum(1 for c in all_cards if c.status == "delivered")
|
||||||
received = sum(1 for c in all_cards if c.status == "received")
|
received = sum(1 for c in all_cards if c.status == "received")
|
||||||
countries = len({c.country_to for c in all_cards if c.country_to})
|
countries = len({c.country_to for c in all_cards if c.country_to})
|
||||||
@@ -604,11 +605,12 @@ def dashboard(request: Request, user: User = Depends(get_current_user_web), db:
|
|||||||
|
|
||||||
# status distribution for progress bar
|
# status distribution for progress bar
|
||||||
if total > 0:
|
if total > 0:
|
||||||
|
pending_pct = round(pending / total * 100)
|
||||||
sent_pct = round(sent / total * 100)
|
sent_pct = round(sent / total * 100)
|
||||||
delivered_pct = round(delivered / total * 100)
|
delivered_pct = round(delivered / total * 100)
|
||||||
received_pct = round(received / total * 100)
|
received_pct = round(received / total * 100)
|
||||||
else:
|
else:
|
||||||
sent_pct = delivered_pct = received_pct = 0
|
pending_pct = sent_pct = delivered_pct = received_pct = 0
|
||||||
|
|
||||||
# country stats split by sent/received
|
# country stats split by sent/received
|
||||||
sent_country_counts: dict[str, int] = {}
|
sent_country_counts: dict[str, int] = {}
|
||||||
@@ -626,9 +628,9 @@ def dashboard(request: Request, user: User = Depends(get_current_user_web), db:
|
|||||||
from datetime import datetime, timezone as _tz
|
from datetime import datetime, timezone as _tz
|
||||||
|
|
||||||
return _render(request, "dashboard.html", {"user": user, "profiles": profiles,
|
return _render(request, "dashboard.html", {"user": user, "profiles": profiles,
|
||||||
"total": total, "sent": sent, "delivered": delivered, "received": received,
|
"total": total, "pending": pending, "sent": sent, "delivered": delivered, "received": received,
|
||||||
"countries": countries, "recent": recent,
|
"countries": countries, "recent": recent,
|
||||||
"sent_pct": sent_pct, "delivered_pct": delivered_pct, "received_pct": received_pct,
|
"pending_pct": pending_pct, "sent_pct": sent_pct, "delivered_pct": delivered_pct, "received_pct": received_pct,
|
||||||
"sent_country_stats": sent_country_stats, "received_country_stats": received_country_stats,
|
"sent_country_stats": sent_country_stats, "received_country_stats": received_country_stats,
|
||||||
"now": datetime.now(_tz.utc) + timedelta(hours=8),
|
"now": datetime.now(_tz.utc) + timedelta(hours=8),
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -186,17 +186,20 @@ code { background: var(--bg); padding: .15rem .4rem; border-radius: 4px; font-si
|
|||||||
.dash-stat-body { display: flex; flex-direction: column; }
|
.dash-stat-body { display: flex; flex-direction: column; }
|
||||||
.dash-stat-value { font-size: 1.15rem; font-weight: 700; line-height: 1.2; }
|
.dash-stat-value { font-size: 1.15rem; font-weight: 700; line-height: 1.2; }
|
||||||
.dash-stat-label { font-size: .68rem; color: var(--text-muted); }
|
.dash-stat-label { font-size: .68rem; color: var(--text-muted); }
|
||||||
|
.dash-pending { color: var(--primary); }
|
||||||
.dash-sent { color: var(--sent); }
|
.dash-sent { color: var(--sent); }
|
||||||
.dash-delivered { color: var(--delivered); }
|
.dash-delivered { color: var(--delivered); }
|
||||||
.dash-received { color: var(--received); }
|
.dash-received { color: var(--received); }
|
||||||
.dash-progress { margin-bottom: 2rem; }
|
.dash-progress { margin-bottom: 2rem; }
|
||||||
.progress-bar { display: flex; height: 8px; border-radius: 4px; overflow: hidden; background: var(--border); }
|
.progress-bar { display: flex; height: 8px; border-radius: 4px; overflow: hidden; background: var(--border); }
|
||||||
.progress-seg { height: 100%; }
|
.progress-seg { height: 100%; }
|
||||||
|
.progress-pending { background: var(--primary); }
|
||||||
.progress-sent { background: var(--sent); }
|
.progress-sent { background: var(--sent); }
|
||||||
.progress-delivered { background: var(--delivered); }
|
.progress-delivered { background: var(--delivered); }
|
||||||
.progress-received { background: var(--received); }
|
.progress-received { background: var(--received); }
|
||||||
.progress-legend { display: flex; gap: 1.25rem; margin-top: .5rem; font-size: .8rem; color: var(--text-muted); }
|
.progress-legend { display: flex; gap: 1.25rem; margin-top: .5rem; font-size: .8rem; color: var(--text-muted); }
|
||||||
.dot { display: inline-block; width: 8px; height: 8px; border-radius: 50%; margin-right: .25rem; vertical-align: middle; }
|
.dot { display: inline-block; width: 8px; height: 8px; border-radius: 50%; margin-right: .25rem; vertical-align: middle; }
|
||||||
|
.dot-pending { background: var(--primary); }
|
||||||
.dot-sent { background: var(--sent); }
|
.dot-sent { background: var(--sent); }
|
||||||
.dot-delivered { background: var(--delivered); }
|
.dot-delivered { background: var(--delivered); }
|
||||||
.dot-received { background: var(--received); }
|
.dot-received { background: var(--received); }
|
||||||
|
|||||||
@@ -14,6 +14,13 @@
|
|||||||
<span class="dash-stat-label">{{ 'dash.total_cards'|t(user.language) }}</span>
|
<span class="dash-stat-label">{{ 'dash.total_cards'|t(user.language) }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="dash-stat-card">
|
||||||
|
<div class="dash-stat-icon">📋</div>
|
||||||
|
<div class="dash-stat-body">
|
||||||
|
<span class="dash-stat-value dash-pending">{{ pending }}</span>
|
||||||
|
<span class="dash-stat-label">{{ 'status.pending'|t(user.language) }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="dash-stat-card">
|
<div class="dash-stat-card">
|
||||||
<div class="dash-stat-icon">📤</div>
|
<div class="dash-stat-icon">📤</div>
|
||||||
<div class="dash-stat-body">
|
<div class="dash-stat-body">
|
||||||
@@ -47,11 +54,13 @@
|
|||||||
{% if total > 0 %}
|
{% if total > 0 %}
|
||||||
<div class="dash-progress">
|
<div class="dash-progress">
|
||||||
<div class="progress-bar">
|
<div class="progress-bar">
|
||||||
|
<div class="progress-seg progress-pending" style="width:{{ pending_pct }}%"></div>
|
||||||
<div class="progress-seg progress-sent" style="width:{{ sent_pct }}%"></div>
|
<div class="progress-seg progress-sent" style="width:{{ sent_pct }}%"></div>
|
||||||
<div class="progress-seg progress-delivered" style="width:{{ delivered_pct }}%"></div>
|
<div class="progress-seg progress-delivered" style="width:{{ delivered_pct }}%"></div>
|
||||||
<div class="progress-seg progress-received" style="width:{{ received_pct }}%"></div>
|
<div class="progress-seg progress-received" style="width:{{ received_pct }}%"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="progress-legend">
|
<div class="progress-legend">
|
||||||
|
<span><i class="dot dot-pending"></i>{{ 'status.pending'|t(user.language) }} {{ pending_pct }}%</span>
|
||||||
<span><i class="dot dot-sent"></i>{{ 'dash.sent'|t(user.language) }} {{ sent_pct }}%</span>
|
<span><i class="dot dot-sent"></i>{{ 'dash.sent'|t(user.language) }} {{ sent_pct }}%</span>
|
||||||
<span><i class="dot dot-delivered"></i>{{ 'dash.delivered'|t(user.language) }} {{ delivered_pct }}%</span>
|
<span><i class="dot dot-delivered"></i>{{ 'dash.delivered'|t(user.language) }} {{ delivered_pct }}%</span>
|
||||||
<span><i class="dot dot-received"></i>{{ 'dash.received'|t(user.language) }} {{ received_pct }}%</span>
|
<span><i class="dot dot-received"></i>{{ 'dash.received'|t(user.language) }} {{ received_pct }}%</span>
|
||||||
|
|||||||
Reference in New Issue
Block a user