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:
@@ -0,0 +1,52 @@
|
||||
document.addEventListener('DOMContentLoaded', async () => {
|
||||
const enableBtn = document.getElementById('pk-enable-btn');
|
||||
const btnLabel = document.getElementById('pk-btn-label');
|
||||
const statusEl = document.getElementById('pk-status');
|
||||
const promptStep = document.getElementById('prompt-step');
|
||||
const successStep = document.getElementById('success-step');
|
||||
|
||||
if (!enableBtn) return;
|
||||
|
||||
// Set platform-specific label
|
||||
const label = passkeyLabel();
|
||||
if (btnLabel) btnLabel.textContent = `Enable ${label.replace('Use ', '')}`;
|
||||
|
||||
const supported = await passkeySupported();
|
||||
if (!supported) {
|
||||
enableBtn.disabled = true;
|
||||
enableBtn.textContent = 'Not supported on this browser';
|
||||
if (statusEl) {
|
||||
statusEl.textContent = 'Your browser does not support biometric login. You can enable it later from Settings → Passkeys & Biometrics on a supported device.';
|
||||
statusEl.className = 'small mb-3 text-muted';
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
enableBtn.addEventListener('click', async () => {
|
||||
enableBtn.disabled = true;
|
||||
enableBtn.innerHTML = '<span class="spinner-border spinner-border-sm me-2"></span>Follow the prompt on your device…';
|
||||
if (statusEl) { statusEl.textContent = ''; }
|
||||
|
||||
const ua = navigator.userAgent;
|
||||
const deviceName = /iphone/i.test(ua) ? 'iPhone'
|
||||
: /ipad/i.test(ua) ? 'iPad'
|
||||
: /android/i.test(ua) ? 'Android device'
|
||||
: /macintosh/i.test(ua) ? 'Mac'
|
||||
: /windows/i.test(ua) ? 'Windows PC'
|
||||
: 'This device';
|
||||
|
||||
const result = await registerPasskey(deviceName);
|
||||
|
||||
if (result.success) {
|
||||
promptStep.classList.add('d-none');
|
||||
successStep.classList.remove('d-none');
|
||||
} else {
|
||||
enableBtn.disabled = false;
|
||||
enableBtn.innerHTML = `<i class="bi bi-fingerprint me-2"></i>Enable ${label.replace('Use ', '')}`;
|
||||
if (statusEl) {
|
||||
statusEl.textContent = result.error || 'Setup failed. Please try again.';
|
||||
statusEl.className = 'small mb-3 text-danger';
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -272,60 +272,3 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||
});
|
||||
});
|
||||
|
||||
// ─── Post-login prompt wiring (layout) ───────────────────────────────────────
|
||||
|
||||
document.addEventListener('DOMContentLoaded', async () => {
|
||||
const prompt = document.getElementById('passkey-setup-prompt');
|
||||
if (!prompt) return;
|
||||
|
||||
const supported = await passkeySupported();
|
||||
if (!supported) { prompt.remove(); return; }
|
||||
|
||||
const label = passkeyLabel();
|
||||
const enableBtn = document.getElementById('passkey-enable-btn');
|
||||
if (enableBtn) enableBtn.innerHTML = `<i class="bi bi-fingerprint me-1"></i>Enable ${label.replace('Use ', '')}`;
|
||||
|
||||
prompt.classList.remove('d-none');
|
||||
|
||||
const dismissBtn = document.getElementById('passkey-dismiss-btn');
|
||||
const statusEl = document.getElementById('passkey-setup-status');
|
||||
|
||||
enableBtn?.addEventListener('click', async () => {
|
||||
enableBtn.disabled = true;
|
||||
if (statusEl) statusEl.textContent = 'Follow the prompt on your device…';
|
||||
|
||||
const ua = navigator.userAgent;
|
||||
const deviceName = /iphone/i.test(ua) ? 'iPhone'
|
||||
: /ipad/i.test(ua) ? 'iPad'
|
||||
: /android/i.test(ua) ? 'Android device'
|
||||
: /macintosh/i.test(ua) ? 'Mac'
|
||||
: /windows/i.test(ua) ? 'Windows PC'
|
||||
: 'This device';
|
||||
|
||||
const result = await registerPasskey(deviceName);
|
||||
|
||||
if (result.success) {
|
||||
if (statusEl) {
|
||||
statusEl.textContent = `✓ ${label.replace('Use ', '')} enabled for this device!`;
|
||||
statusEl.className = 'small mb-0 text-success';
|
||||
}
|
||||
enableBtn.classList.add('d-none');
|
||||
if (dismissBtn) dismissBtn.textContent = 'Close';
|
||||
setTimeout(() => prompt.classList.add('d-none'), 3000);
|
||||
} else {
|
||||
enableBtn.disabled = false;
|
||||
enableBtn.innerHTML = `<i class="bi bi-fingerprint me-1"></i>Enable ${label.replace('Use ', '')}`;
|
||||
if (statusEl) statusEl.textContent = result.error || 'Setup failed. Try again.';
|
||||
}
|
||||
});
|
||||
|
||||
dismissBtn?.addEventListener('click', () => {
|
||||
prompt.classList.add('d-none');
|
||||
// Remember dismissal for this session so it doesn't re-appear on every page load
|
||||
sessionStorage.setItem('passkey-prompt-dismissed', '1');
|
||||
});
|
||||
|
||||
if (sessionStorage.getItem('passkey-prompt-dismissed')) {
|
||||
prompt.classList.add('d-none');
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user