feat: email field in settings — lets users set address for self-service password reset

This commit is contained in:
Davide Scaini
2026-06-03 21:56:35 +02:00
parent 5f916461ac
commit ac18b73c07
+57
View File
@@ -51,6 +51,25 @@ import Base from '../../layouts/Base.astro';
<p id="display-name-status" class="text-xs mt-2 hidden"></p>
</section>
<!-- Email card -->
<section class="mb-6 rounded-xl bg-zinc-900 border border-zinc-800 p-5">
<h2 class="text-sm font-semibold text-zinc-400 uppercase tracking-wider mb-1">Email</h2>
<p class="text-xs text-zinc-500 mb-4">Used to receive a reset link when you forget your password.</p>
<form id="email-form" class="flex gap-2 items-end">
<div class="flex-1">
<label class="block text-xs text-zinc-500 mb-1" for="email-input">Email address</label>
<input id="email-input" type="email" autocomplete="email"
class="w-full px-3 py-2 rounded-lg bg-zinc-800 border border-zinc-700 text-white placeholder-zinc-500 focus:outline-none focus:border-[--accent] text-sm"
placeholder="you@example.com" />
</div>
<button type="submit"
class="px-4 py-2 rounded-lg text-sm bg-zinc-700 hover:bg-zinc-600 text-white transition-colors shrink-0">
Save
</button>
</form>
<p id="email-status" class="text-xs mt-2 hidden"></p>
</section>
<!-- Password card -->
<section class="mb-6 rounded-xl bg-zinc-900 border border-zinc-800 p-5">
<h2 class="text-sm font-semibold text-zinc-400 uppercase tracking-wider mb-4">Password</h2>
@@ -602,10 +621,48 @@ import Base from '../../layouts/Base.astro';
}
});
// ── Email ─────────────────────────────────────────────────────────────────────
const emailForm = document.getElementById('email-form') as HTMLFormElement;
const emailInput = document.getElementById('email-input') as HTMLInputElement;
const emailStatus = document.getElementById('email-status') as HTMLElement;
async function loadEmail() {
const authUrl: string = (window as any).__bincioAuthUrl ?? '';
if (!authUrl) return; // single-user / no bincio-auth
try {
const r = await fetch(`${authUrl}/api/me/email`, { credentials: 'include' });
if (r.ok) {
const { email } = await r.json();
if (email) emailInput.value = email;
}
} catch { /* ignore */ }
}
emailForm.addEventListener('submit', async e => {
e.preventDefault();
const authUrl: string = (window as any).__bincioAuthUrl ?? '';
if (!authUrl) { setStatus(emailStatus, 'Not available on this instance.', false); return; }
const email = emailInput.value.trim();
try {
const r = await fetch(`${authUrl}/api/me/email`, {
method: 'POST',
credentials: 'include',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ email }),
});
const d = await r.json().catch(() => ({}));
setStatus(emailStatus, r.ok ? 'Saved.' : (d.detail ?? 'Failed.'), r.ok);
} catch {
setStatus(emailStatus, 'Could not reach server.', false);
}
});
// ── Init ─────────────────────────────────────────────────────────────────────
loadMe();
loadStorage();
loadEmail();
loadNavPrefs();
loadActivityDefaults();
loadStravaCreds();