Add server-side dismiss persistence and SuperAdmin onboarding progress page

Progress widget dismiss now POSTs to Dashboard/DismissProgressWidget, writing
GuidedActivationDismissedAt to the DB so the widget stays hidden across devices
and cache clears (localStorage alone wasn't enough). BuildShopProgressWidgetAsync
suppresses the widget server-side when AllDone + dismissed.

New SuperAdmin page at /OnboardingProgress shows the activation funnel across
all tenant companies: wizard status, chosen path, milestone progress bar, key
dates (first job/quote, first invoice, workflow completed, widget dismissed),
and a status badge (Not Started / In Progress / Complete / Dismissed). Nav link
added under Users & Activity in the Platform Management sidebar.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-29 09:23:20 -04:00
parent 73df72ab97
commit 8de9cd04b8
6 changed files with 311 additions and 1 deletions
@@ -0,0 +1,35 @@
namespace PowderCoating.Web.ViewModels.Platform;
public class OnboardingProgressIndexViewModel
{
public List<OnboardingProgressRowViewModel> Rows { get; set; } = new();
public int TotalCompanies => Rows.Count;
public int WizardCompleted => Rows.Count(r => r.WizardCompleted);
public int FullyActivated => Rows.Count(r => r.Status == OnboardingStatus.Complete);
public int InProgress => Rows.Count(r => r.Status == OnboardingStatus.InProgress);
public int NotStarted => Rows.Count(r => r.Status == OnboardingStatus.NotStarted);
}
public class OnboardingProgressRowViewModel
{
public int CompanyId { get; set; }
public string CompanyName { get; set; } = string.Empty;
public bool WizardCompleted { get; set; }
public string? OnboardingPath { get; set; }
public int StepsCompleted { get; set; }
public int TotalSteps { get; set; }
public DateTime? FirstJobCreatedAt { get; set; }
public DateTime? FirstQuoteCreatedAt { get; set; }
public DateTime? FirstInvoiceCreatedAt { get; set; }
public DateTime? FirstWorkflowCompletedAt { get; set; }
public DateTime? GuidedActivationDismissedAt { get; set; }
public OnboardingStatus Status { get; set; }
}
public enum OnboardingStatus
{
NotStarted,
InProgress,
Complete,
Dismissed
}