Compare commits

...

2 Commits

Author SHA1 Message Date
spouliot 45441c1d07 Fix 'Customize your workflow' done signal not detecting deletions
The previous AnyAsync check used global query filters which hide
soft-deleted records. Deleting a lookup sets UpdatedAt on the record
(EF interceptor stamps Modified entities) but the IsDeleted filter
made it invisible to the query. Added ignoreQueryFilters: true with
an explicit CompanyId predicate so soft-deleted lookups are included —
any deletion or edit now correctly marks the step complete.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-28 21:25:30 -04:00
spouliot 64e9abceac Hide team invite step on progress widget for single-user plans
Injects ISubscriptionService into DashboardController and calls
GetUserCountAsync to check the plan's MaxUsers limit. When MaxUsers == 1
the "Bring your crew in" step is omitted from the progress widget entirely,
so solo-plan users aren't prompted to do something their subscription
doesn't allow. Plans with MaxUsers > 1 or unlimited (-1) show the step
as before.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-28 21:22:41 -04:00
@@ -24,6 +24,7 @@ public class DashboardController : Controller
private readonly ITenantContext _tenantContext; private readonly ITenantContext _tenantContext;
private readonly ICompanyConfigHealthService _configHealth; private readonly ICompanyConfigHealthService _configHealth;
private readonly UserManager<ApplicationUser> _userManager; private readonly UserManager<ApplicationUser> _userManager;
private readonly ISubscriptionService _subscriptionService;
private static readonly string[] CompletedStatusCodes = private static readonly string[] CompletedStatusCodes =
[ [
@@ -51,7 +52,8 @@ public class DashboardController : Controller
IDashboardReadService dashboardRead, IDashboardReadService dashboardRead,
ITenantContext tenantContext, ITenantContext tenantContext,
ICompanyConfigHealthService configHealth, ICompanyConfigHealthService configHealth,
UserManager<ApplicationUser> userManager) UserManager<ApplicationUser> userManager,
ISubscriptionService subscriptionService)
{ {
_unitOfWork = unitOfWork; _unitOfWork = unitOfWork;
_logger = logger; _logger = logger;
@@ -59,6 +61,7 @@ public class DashboardController : Controller
_tenantContext = tenantContext; _tenantContext = tenantContext;
_configHealth = configHealth; _configHealth = configHealth;
_userManager = userManager; _userManager = userManager;
_subscriptionService = subscriptionService;
} }
/// <summary> /// <summary>
@@ -692,11 +695,16 @@ public class DashboardController : Controller
// These share the same scoped DbContext so must run sequentially // These share the same scoped DbContext so must run sequentially
var hasStatusHistory = await _unitOfWork.JobStatusHistory.AnyAsync(_ => true); var hasStatusHistory = await _unitOfWork.JobStatusHistory.AnyAsync(_ => true);
var hasCustomizedLookups = await _unitOfWork.JobStatusLookups.AnyAsync(j => j.UpdatedAt != null); // ignoreQueryFilters so soft-deleted lookups (UpdatedAt set on delete) are also visible
var hasCustomizedLookups = await _unitOfWork.JobStatusLookups.AnyAsync(
j => j.CompanyId == companyId && j.UpdatedAt != null,
ignoreQueryFilters: true);
var teamCount = await _userManager.Users var teamCount = await _userManager.Users
.CountAsync(u => u.CompanyId == companyId && u.IsActive && !u.IsBanned); .CountAsync(u => u.CompanyId == companyId && u.IsActive && !u.IsBanned);
var (_, maxUsers) = await _subscriptionService.GetUserCountAsync(companyId);
var planAllowsMultipleUsers = maxUsers != 1;
var items = new List<ShopProgressItem> var items = new List<ShopProgressItem?>
{ {
new() new()
{ {
@@ -728,7 +736,7 @@ public class DashboardController : Controller
CtaText = "Create invoice", CtaText = "Create invoice",
CtaUrl = Url.Action("Create", "Invoices")! CtaUrl = Url.Action("Create", "Invoices")!
}, },
new() planAllowsMultipleUsers ? new()
{ {
Done = teamCount > 1, Done = teamCount > 1,
Label = "Bring your crew in", Label = "Bring your crew in",
@@ -737,7 +745,7 @@ public class DashboardController : Controller
Icon = "bi-people", Icon = "bi-people",
CtaText = "Invite team", CtaText = "Invite team",
CtaUrl = Url.Action("Index", "CompanyUsers")! CtaUrl = Url.Action("Index", "CompanyUsers")!
}, } : null!,
new() new()
{ {
Done = hasCustomizedLookups, Done = hasCustomizedLookups,
@@ -763,7 +771,7 @@ public class DashboardController : Controller
} }
}; };
return new ShopProgressWidgetViewModel { Items = items }; return new ShopProgressWidgetViewModel { Items = items.Where(i => i != null).Select(i => i!).ToList() };
} }
/// <summary> /// <summary>