Jobs list defaults to On Floor; add Completed filter pill; fix encoding bugs

- /Jobs now redirects to ?statusGroup=active so completed jobs don't clutter the default view
- Add Completed pill (filters Completed + ReadyForPickup + Delivered)
- Pill badge counts are now global DB counts, not page-local item counts
- Ready pill badge now shows ReadyForPickup-only count
- All pill links to ?statusGroup=all to bypass the redirect
- Fix double-encoded & in Completed filter alert label
- Fix corrupted em dash (â€") in Customers/Details billing email fallback text

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-19 20:11:33 -04:00
parent 551116d7e5
commit 24f3df1bbc
3 changed files with 55 additions and 16 deletions
+21 -15
View File
@@ -8,10 +8,12 @@
}
@{
var _wip = Model.Items.Count(j => j.StatusIsWIP);
var _done = Model.Items.Count(j => j.StatusCode == "COMPLETED" || j.StatusCode == "READYFORPICKUP" || j.StatusCode == "DELIVERED");
var _overdue = Model.Items.Count(j => j.DueDate.HasValue && j.DueDate.Value < DateTime.Now && j.StatusCode != "COMPLETED" && j.StatusCode != "READYFORPICKUP" && j.StatusCode != "DELIVERED" && j.StatusCode != "CANCELLED");
var _value = Model.Items.Sum(j => j.FinalPrice);
var _allCount = (int)(ViewBag.AllJobCount ?? 0);
var _wip = (int)(ViewBag.ActiveCount ?? 0);
var _done = (int)(ViewBag.CompletedCount ?? 0);
var _ready = (int)(ViewBag.ReadyCount ?? 0);
var _overdue = (int)(ViewBag.OverdueCount ?? 0);
var _value = Model.Items.Sum(j => j.FinalPrice);
}
<div class="pcl-metric-strip">
<div class="pcl-metric-strip-cell">
@@ -39,23 +41,23 @@
Showing <strong>@Model.TotalCount</strong> job(s) matching "<strong>@ViewBag.SearchTerm</strong>"
<small class="text-muted ms-2">(searches job number, description, customer, PO, instructions, status, priority)</small>
</div>
<a href="@Url.Action("Index")" class="btn btn-sm btn-outline-secondary">
<a href="@Url.Action("Index", new { statusGroup = "active" })" class="btn btn-sm btn-outline-secondary">
<i class="bi bi-x me-1"></i>Clear Filter
</a>
</div>
}
@if (!string.IsNullOrEmpty(ViewBag.StatusGroup as string))
@if (!string.IsNullOrEmpty(ViewBag.StatusGroup as string) && ViewBag.StatusGroup != "active" && ViewBag.StatusGroup != "all")
{
var groupLabel = ViewBag.StatusGroup == "active" ? "Active Jobs (excluding completed & cancelled)"
: ViewBag.StatusGroup == "overdue" ? "Overdue Jobs (past due date)"
: ViewBag.StatusGroup;
var groupLabel = ViewBag.StatusGroup == "overdue" ? "Overdue Jobs (past due date)"
: ViewBag.StatusGroup == "completed" ? "Completed Jobs (completed, ready for pickup & delivered)"
: (string)ViewBag.StatusGroup;
<div class="alert alert-warning alert-permanent d-flex justify-content-between align-items-center">
<div>
<i class="bi bi-funnel-fill me-2"></i>
Showing: <strong>@groupLabel</strong> &mdash; @Model.TotalCount result@(Model.TotalCount == 1 ? "" : "s")
</div>
<a href="@Url.Action("Index")" class="btn btn-sm btn-outline-secondary">
<i class="bi bi-x me-1"></i>Show All
<a href="@Url.Action("Index", new { statusGroup = "active" })" class="btn btn-sm btn-outline-secondary">
<i class="bi bi-x me-1"></i>Back to On Floor
</a>
</div>
}
@@ -63,7 +65,8 @@
@{
var _activeGroup = ViewBag.StatusGroup as string;
var _activeSearch = ViewBag.SearchTerm as string;
var _noFilter = string.IsNullOrEmpty(_activeGroup) && string.IsNullOrEmpty(_activeSearch) && string.IsNullOrEmpty(ViewBag.TagFilter as string);
// "all" is the explicit show-everything group (bare URL now redirects to "active")
var _noFilter = _activeGroup == "all" && string.IsNullOrEmpty(_activeSearch) && string.IsNullOrEmpty(ViewBag.TagFilter as string);
}
<!-- Jobs Table Card -->
<div class="card border-0 shadow-sm">
@@ -135,8 +138,8 @@
</div>
<!-- Row 2: quick-view pills -->
<div class="pcl-pill-group">
<a href="@Url.Action("Index")" class="pcl-pill @(_noFilter ? "active" : "")">
All <span class="pcl-pill-count">@Model.TotalCount</span>
<a href="@Url.Action("Index", new { statusGroup = "all" })" class="pcl-pill @(_noFilter ? "active" : "")">
All <span class="pcl-pill-count">@_allCount</span>
</a>
<a href="@Url.Action("Index", new { statusGroup = "active" })" class="pcl-pill @(_activeGroup == "active" ? "active" : "")">
On floor <span class="pcl-pill-count">@_wip</span>
@@ -145,7 +148,10 @@
Overdue <span class="pcl-pill-count">@_overdue</span>
</a>
<a href="@Url.Action("Index", new { searchTerm = "ReadyForPickup" })" class="pcl-pill @(_activeSearch == "ReadyForPickup" ? "active" : "")">
Ready <span class="pcl-pill-count">@_done</span>
Ready <span class="pcl-pill-count">@_ready</span>
</a>
<a href="@Url.Action("Index", new { statusGroup = "completed" })" class="pcl-pill @(_activeGroup == "completed" ? "active" : "")">
Completed <span class="pcl-pill-count">@_done</span>
</a>
</div>
</div>