Move passkey enrollment prompt to post-login dedicated page

After password login, users are routed through /Passkey/EnrollPrompt
before reaching the dashboard. The page shows an Enable / Maybe later
choice using the auth layout for a clean full-screen experience.
Users who already have a passkey are skipped past instantly.

Removes the floating bottom-right card from _Layout — the dedicated
page is a better UX touchpoint (one moment, right after login, rather
than a floating card on every page).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-25 16:41:01 -04:00
parent 92f71f62d0
commit edce8e8c4a
6 changed files with 144 additions and 84 deletions
@@ -0,0 +1,63 @@
@{
ViewData["Title"] = "Enable Biometric Login";
Layout = "/Views/Shared/_AuthLayout.cshtml";
var returnUrl = ViewBag.ReturnUrl as string ?? "/";
}
<div class="d-flex" style="min-height:100vh;">
<!-- Left brand panel — hidden on mobile, same as login page -->
<div class="col-lg-5 d-none d-lg-flex auth-brand-panel">
<img src="/images/pcl-logo.png" alt="Powder Coating Logix" style="max-width:220px; margin-bottom:1.5rem;" />
<h1>Powder Coating Logix</h1>
<p class="tagline">The complete management platform for powder coating businesses</p>
<ul class="feature-list">
<li><i class="bi bi-fingerprint"></i> Fast biometric login</li>
<li><i class="bi bi-shield-check-fill"></i> Secure — your biometrics never leave your device</li>
<li><i class="bi bi-phone-fill"></i> Works with Face ID, Touch ID &amp; Windows Hello</li>
<li><i class="bi bi-trash3-fill"></i> Remove any device at any time</li>
</ul>
</div>
<!-- Right prompt panel -->
<div class="auth-form-panel col-lg-7">
<div class="auth-form-container text-center">
<div id="prompt-step">
<div class="mb-4" style="font-size:4rem; color:#0284c7; line-height:1;">
<i class="bi bi-fingerprint"></i>
</div>
<h2 class="mb-2">Speed up future logins</h2>
<p class="subtext mb-4">
Enable biometric login so next time you can sign in with a single tap —
no password needed.
</p>
<p id="pk-status" class="small mb-3" style="min-height:1.25em;"></p>
<div class="d-grid gap-2" style="max-width:320px; margin:0 auto;">
<button id="pk-enable-btn" type="button" class="btn btn-primary btn-lg">
<i class="bi bi-fingerprint me-2"></i><span id="pk-btn-label">Enable Biometric Login</span>
</button>
<a id="pk-skip-link" href="@returnUrl" class="btn btn-outline-secondary btn-lg">
Maybe later
</a>
</div>
</div>
<div id="success-step" class="d-none">
<div class="mb-4" style="font-size:4rem; color:#16a34a; line-height:1;">
<i class="bi bi-check-circle-fill"></i>
</div>
<h2 class="mb-2">All set!</h2>
<p class="subtext mb-4">Biometric login is enabled for this device.</p>
<a href="@returnUrl" class="btn btn-primary btn-lg px-5">Continue</a>
</div>
</div>
</div>
</div>
@section Scripts {
<script src="~/js/passkey.js"></script>
<script src="~/js/passkey-enroll.js"></script>
}
@@ -895,33 +895,6 @@
<div id="tempdata-info-message" style="display:none;">@TempData["Info"]</div>
}
@* Passkey setup prompt — shown once per session to authenticated users who have no passkeys yet *@
@if (User.Identity?.IsAuthenticated == true && !User.IsInRole("SuperAdmin"))
{
<div id="passkey-setup-prompt" class="d-none"
style="position:fixed;bottom:1.25rem;right:1.25rem;z-index:1090;max-width:320px;">
<div class="card shadow-lg border-0">
<div class="card-body p-3">
<div class="d-flex align-items-start gap-2 mb-2">
<i class="bi bi-fingerprint text-primary" style="font-size:1.4rem;flex-shrink:0;margin-top:2px;"></i>
<div>
<div class="fw-semibold" style="font-size:.9rem;">Enable Face ID / Biometric Login</div>
<div class="text-muted" style="font-size:.8rem;">Skip the password next time — use your fingerprint or Face ID.</div>
</div>
<button type="button" id="passkey-dismiss-btn" class="btn-close ms-auto" style="font-size:.75rem;" aria-label="Dismiss"></button>
</div>
<p id="passkey-setup-status" class="small mb-2"></p>
<div class="d-flex gap-2">
<button id="passkey-enable-btn" type="button" class="btn btn-primary btn-sm flex-grow-1">
<i class="bi bi-fingerprint me-1"></i>Enable
</button>
<a href="/Passkey/Manage" class="btn btn-outline-secondary btn-sm">Manage</a>
</div>
</div>
</div>
</div>
}
@* Hidden container for ModelState errors (read by toast-notifications.js) *@
@if (!ViewData.ModelState.IsValid && ViewData.ModelState.ErrorCount > 0)
{