@model PowderCoating.Web.ViewModels.Reports.CustomerRetentionViewModel @{ ViewData["Title"] = "Customer Retention"; }
@Model.ActiveCount
Active
(≤ 30 days)
@Model.AtRiskCount
At Risk
(31–60 days)
@Model.LapsingCount
Lapsing
(61–90 days)
@Model.ChurnedCount
Churned
(> 90 days)
@Model.NeverOrderedCount
Never Ordered
 
@{ var statusOrder = new[] { "Churned", "Lapsing", "At Risk", "Active", "Never Ordered" }; var grouped = Model.Items.GroupBy(i => i.RetentionStatus).OrderBy(g => Array.IndexOf(statusOrder, g.Key)); } @foreach (var group in grouped) { var badgeClass = group.Key switch { "Active" => "bg-success", "At Risk" => "bg-warning text-dark", "Lapsing" => "bg-orange", "Churned" => "bg-danger", _ => "bg-secondary" }; var headerClass = group.Key switch { "Active" => "table-success", "At Risk" => "table-warning", "Lapsing" => "table-orange", "Churned" => "table-danger", _ => "table-secondary" };
@group.Key @group.Count()
@foreach (var item in group.OrderByDescending(i => i.LifetimeRevenue)) { }
Customer Email Phone Jobs Lifetime Revenue Last Job Days Since
@item.CustomerName @Html.Raw(item.Email ?? "—") @Html.Raw(item.Phone ?? "—") @item.TotalJobs @item.LifetimeRevenue.ToString("C") @Html.Raw(item.LastJobDate?.ToString("MMM d, yyyy") ?? "—") @if (item.DaysSinceLastJob < 0) { } else { @item.DaysSinceLastJob }
}