74 lines
2.2 KiB
Cheetah
74 lines
2.2 KiB
Cheetah
{{define "page"}}
|
|
<div class="login-wrapper">
|
|
<div class="login-card glass fade-in">
|
|
<div class="login-header">
|
|
<div class="brand">clavitor</div>
|
|
<p>Enter the code sent to your email</p>
|
|
</div>
|
|
|
|
<form id="verify-form" onsubmit="return verifyCode(event)">
|
|
<input type="hidden" id="verify-email" value="{{.Data}}">
|
|
<div class="field">
|
|
<label for="code">Verification code</label>
|
|
<input type="text" id="code" class="input input-mono" placeholder="123456"
|
|
required autocomplete="one-time-code" autofocus
|
|
maxlength="6" pattern="[0-9]{6}" inputmode="numeric"
|
|
style="text-align:center;font-size:1.5rem;letter-spacing:0.3em">
|
|
</div>
|
|
<button type="submit" class="btn btn-primary btn-block btn-lg" id="verify-btn">
|
|
Verify
|
|
</button>
|
|
</form>
|
|
|
|
<div class="login-footer">
|
|
<a href="{{.Base}}/login">Back to sign in</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{{end}}
|
|
|
|
{{define "scripts"}}
|
|
<script>
|
|
async function verifyCode(e) {
|
|
e.preventDefault();
|
|
const email = document.getElementById('verify-email').value;
|
|
const code = document.getElementById('code').value;
|
|
const btn = document.getElementById('verify-btn');
|
|
btn.disabled = true;
|
|
btn.textContent = 'Verifying…';
|
|
|
|
try {
|
|
const resp = await fetch('{{.Base}}/api/auth/verify', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({ email, code })
|
|
});
|
|
if (!resp.ok) {
|
|
const data = await resp.json();
|
|
throw new Error(data.error || 'Invalid code');
|
|
}
|
|
window.location.href = '{{.Base}}/dashboard';
|
|
} catch (err) {
|
|
showToast(err.message, 'error');
|
|
btn.disabled = false;
|
|
btn.textContent = 'Verify';
|
|
document.getElementById('code').value = '';
|
|
document.getElementById('code').focus();
|
|
}
|
|
}
|
|
|
|
function showToast(msg, type) {
|
|
let t = document.querySelector('.toast');
|
|
if (!t) {
|
|
t = document.createElement('div');
|
|
t.className = 'toast';
|
|
document.body.appendChild(t);
|
|
}
|
|
t.textContent = msg;
|
|
t.className = 'toast ' + type;
|
|
requestAnimationFrame(() => t.classList.add('show'));
|
|
setTimeout(() => t.classList.remove('show'), type === 'error' ? 6000 : 3000);
|
|
}
|
|
</script>
|
|
{{end}}
|