Onboarding overhaul: slim wizard, progress widget, guided activation UX

Setup Wizard: reduced from 10 steps to 5 (Company Info → QB Migration →
Pricing Defaults → Named Ovens → Notifications). Removed Doc Numbering,
Job Settings, Payment Terms, Pricing Tiers, and Team Members steps — these
all have sensible defaults and are accessible any time in Company Settings.
Wizard now completes in ~5 minutes instead of 15–20.

Dashboard progress widget (new): "Get the most out of your shop" checklist
appears for Company Admins after wizard completion. Tracks six post-setup
activation tasks with dynamic progress badge, motivating subtitle copy,
collapsed-state persistence via localStorage, and a full completion state
("Your shop is fully set up 🎉") that replaces the checklist at 100%.
The next recommended step is highlighted with a solid CTA button and a
subtle blue row tint. Completed steps show encouraging green subtext instead
of just "Done". Widget disappears from controller when AllDone would have
caused a silent vanish — now renders the completion state instead.

Guided activation (Daily Board): rewrote the BoardIntroStep callout to lead
with "This is your shop in real time" and a plain-English description of the
board's purpose. Added a separate InstructionText field to
GuidedActivationCalloutViewModel so the "Move this job to the next stage"
action prompt renders as a distinct bold line with an arrow icon rather than
being buried in the body copy. After the stage change, the confirmation
callout now reads "Nice — your workflow just updated" to reinforce what just
happened before prompting the invoice step.

All copy passes the "shop owner, not SaaS" test: no technical jargon,
benefit-driven descriptions, natural language throughout.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-28 21:10:47 -04:00
parent 4d27a378ac
commit 8aae30765f
30 changed files with 10870 additions and 333 deletions
@@ -0,0 +1,43 @@
namespace PowderCoating.Web.ViewModels.Dashboard;
public class ShopProgressWidgetViewModel
{
public List<ShopProgressItem> Items { get; set; } = new();
public int TotalItems => Items.Count;
public int CompletedCount => Items.Count(i => i.Done);
public bool AllDone => CompletedCount == TotalItems;
public int ProgressPercent => TotalItems == 0 ? 0 : CompletedCount * 100 / TotalItems;
public string SubtitleText => CompletedCount switch
{
0 => "You're set up and ready to go — these steps will help you run a tighter shop.",
1 => "You're off to a great start — here's how to run your shop even smoother.",
2 => "Good momentum — keep going.",
3 => "Halfway there — great progress so far.",
4 => "Almost there — just a couple more steps.",
5 => "One step left — you're this close.",
_ => "You're all set."
};
public string BadgeText => CompletedCount switch
{
0 => $"0 of {TotalItems} complete",
1 => $"1 of {TotalItems} — you're on your way",
2 => $"2 of {TotalItems} — good momentum",
3 => $"3 of {TotalItems} — halfway there",
4 => $"4 of {TotalItems} — almost there",
5 => $"5 of {TotalItems} — one step left",
_ => $"{CompletedCount} of {TotalItems} complete"
};
}
public class ShopProgressItem
{
public bool Done { get; set; }
public string Label { get; set; } = string.Empty;
public string SubLabel { get; set; } = string.Empty;
public string DoneSubLabel { get; set; } = string.Empty;
public string Icon { get; set; } = string.Empty;
public string CtaText { get; set; } = string.Empty;
public string CtaUrl { get; set; } = string.Empty;
}
@@ -0,0 +1,35 @@
using System.ComponentModel.DataAnnotations;
namespace PowderCoating.Web.ViewModels.GuidedActivation;
public class GuidedActivationSelectionViewModel
{
[Required]
public string? OnboardingPath { get; set; }
}
public class GuidedActivationBannerViewModel
{
public bool Show { get; set; }
public bool IsDismissed { get; set; }
public string Title { get; set; } = string.Empty;
public string Message { get; set; } = string.Empty;
public string ActionText { get; set; } = "Start first workflow";
}
public class GuidedActivationCalloutViewModel
{
public bool Show { get; set; }
public string Title { get; set; } = string.Empty;
public string Message { get; set; } = string.Empty;
/// <summary>Optional action prompt rendered below the message (e.g. "Move this job to the next stage…").</summary>
public string? InstructionText { get; set; }
public string? ActionText { get; set; }
public string? ActionController { get; set; }
public string? ActionName { get; set; }
public object? ActionRouteValues { get; set; }
public string? SecondaryActionText { get; set; }
public string? SecondaryActionController { get; set; }
public string? SecondaryActionName { get; set; }
public object? SecondaryActionRouteValues { get; set; }
}