Add passkey prompt dismissal and consolidate company admin navigation

- Add "Don't ask me again" to passkey enrollment prompt (PasskeyPromptDismissed
  field on ApplicationUser; DismissPrompt POST action; migration applied)
- Add Subscription & Features button to Companies/Index btn-group and
  Companies/Edit header for direct navigation to SubscriptionManagement/Manage
- Add Edit Company back-link on SubscriptionManagement/Manage
- Remove duplicate AI Features section from Companies/Edit (managed exclusively
  via Subscription & Features page)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-26 10:34:50 -04:00
parent 3899860c1f
commit a4b8ae611a
9 changed files with 9426 additions and 39 deletions
@@ -258,8 +258,8 @@ public class PasskeyController : Controller
// ─── Post-login enrollment prompt ─────────────────────────────────────────
/// <summary>
/// Shown immediately after password login. If the user already has a passkey,
/// redirects straight to returnUrl. Otherwise presents the "Enable Face ID" page.
/// Shown immediately after password login. Skips to returnUrl if the user already
/// has a passkey or has previously dismissed the prompt.
/// </summary>
[Authorize]
[HttpGet("/Passkey/EnrollPrompt")]
@@ -268,15 +268,32 @@ public class PasskeyController : Controller
var user = await _userManager.GetUserAsync(User);
if (user == null) return Unauthorized();
// Skip prompt for users who already have at least one passkey
var hasPasskey = await _db.UserPasskeys.AnyAsync(p => p.UserId == user.Id);
if (hasPasskey)
if (hasPasskey || user.PasskeyPromptDismissed)
return Redirect(returnUrl ?? "/");
ViewBag.ReturnUrl = returnUrl ?? "/";
return View();
}
/// <summary>
/// Permanently dismisses the passkey enrollment prompt for this user. They can
/// re-enable it from Profile → Security at any time.
/// </summary>
[Authorize]
[HttpPost("/Passkey/DismissPrompt")]
[ValidateAntiForgeryToken]
public async Task<IActionResult> DismissPrompt(string? returnUrl)
{
var user = await _userManager.GetUserAsync(User);
if (user == null) return Unauthorized();
user.PasskeyPromptDismissed = true;
await _userManager.UpdateAsync(user);
return Redirect(returnUrl ?? "/");
}
/// <summary>Shows all passkeys registered by the current user.</summary>
[Authorize]
[HttpGet("/Passkey/Manage")]