fix password resets
This commit is contained in:
parent
4497863667
commit
d462542bbd
4 changed files with 194 additions and 6 deletions
105
index.html
105
index.html
|
|
@ -5930,6 +5930,111 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="page-reset-password" class="page">
|
||||
<div
|
||||
class="reset-password-container"
|
||||
style="text-align: center; padding: var(--space-8); max-width: 400px; margin: 0 auto"
|
||||
>
|
||||
<h2 class="section-title" style="margin-bottom: var(--space-10)">Reset your Password</h2>
|
||||
|
||||
<div
|
||||
id="reset-password-error"
|
||||
class="message error-msg"
|
||||
style="
|
||||
display: none;
|
||||
padding: var(--space-3) 0;
|
||||
border-radius: var(--radius-md);
|
||||
font-size: var(--text-sm);
|
||||
margin-bottom: var(--space-4);
|
||||
background: transparent;
|
||||
color: #ff6b6b;
|
||||
text-align: left;
|
||||
"
|
||||
></div>
|
||||
<div
|
||||
id="reset-password-success"
|
||||
class="message success-msg"
|
||||
style="
|
||||
display: none;
|
||||
padding: var(--space-3) 0;
|
||||
border-radius: var(--radius-md);
|
||||
font-size: var(--text-sm);
|
||||
margin-bottom: var(--space-4);
|
||||
background: transparent;
|
||||
color: var(--foreground);
|
||||
text-align: left;
|
||||
"
|
||||
></div>
|
||||
|
||||
<form id="reset-password-form">
|
||||
<div style="margin-bottom: var(--space-4)">
|
||||
<input
|
||||
type="password"
|
||||
id="reset-password-input"
|
||||
placeholder="New Password"
|
||||
required
|
||||
minlength="8"
|
||||
style="
|
||||
width: 100%;
|
||||
padding: var(--space-3) var(--space-4);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius-md);
|
||||
background: var(--card);
|
||||
color: var(--foreground);
|
||||
font-size: 0.925rem;
|
||||
outline: none;
|
||||
transition: border-color 0.15s;
|
||||
"
|
||||
/>
|
||||
</div>
|
||||
<div style="margin-bottom: var(--space-6)">
|
||||
<input
|
||||
type="password"
|
||||
id="reset-password-confirm"
|
||||
placeholder="Confirm New Password"
|
||||
required
|
||||
minlength="8"
|
||||
style="
|
||||
width: 100%;
|
||||
padding: var(--space-3) var(--space-4);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius-md);
|
||||
background: var(--card);
|
||||
color: var(--foreground);
|
||||
font-size: 0.925rem;
|
||||
outline: none;
|
||||
transition: border-color 0.15s;
|
||||
"
|
||||
/>
|
||||
</div>
|
||||
<button
|
||||
type="submit"
|
||||
id="reset-password-submit-btn"
|
||||
class="btn-primary"
|
||||
style="width: 100%; justify-content: center"
|
||||
>
|
||||
<span id="reset-password-btn-text">Reset Password</span>
|
||||
<div
|
||||
id="reset-password-btn-spinner"
|
||||
class="animate-spin"
|
||||
style="display: none; width: 18px; height: 18px"
|
||||
>
|
||||
<svg
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
style="width: 100%; height: 100%"
|
||||
>
|
||||
<path d="M21 12a9 9 0 1 1-6.219-8.56" />
|
||||
</svg>
|
||||
</div>
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<footer class="now-playing-bar">
|
||||
|
|
|
|||
|
|
@ -15,12 +15,14 @@ export class AuthManager {
|
|||
const isOAuthRedirect = params.get('oauth') === '1';
|
||||
|
||||
if (userId && secret && userId !== 'null' && secret !== 'null') {
|
||||
try {
|
||||
await auth.createSession(userId, secret);
|
||||
window.history.replaceState({}, '', window.location.pathname);
|
||||
} catch (error) {
|
||||
console.warn('OAuth session handoff failed:', error.message);
|
||||
window.history.replaceState({}, '', window.location.pathname);
|
||||
if (window.location.pathname !== '/reset-password') {
|
||||
try {
|
||||
await auth.createSession(userId, secret);
|
||||
window.history.replaceState({}, '', window.location.pathname);
|
||||
} catch (error) {
|
||||
console.warn('OAuth session handoff failed:', error.message);
|
||||
window.history.replaceState({}, '', window.location.pathname);
|
||||
}
|
||||
}
|
||||
} else if (isOAuthRedirect) {
|
||||
await new Promise((resolve) => setTimeout(resolve, 500));
|
||||
|
|
@ -137,6 +139,18 @@ export class AuthManager {
|
|||
}
|
||||
}
|
||||
|
||||
async resetPassword(userId, secret, password, confirmPassword) {
|
||||
if (password !== confirmPassword) {
|
||||
throw new Error('Passwords do not match');
|
||||
}
|
||||
try {
|
||||
await auth.updateRecovery(userId, secret, password, password);
|
||||
} catch (error) {
|
||||
console.error('Password reset failed:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
async signOut() {
|
||||
try {
|
||||
await auth.deleteSession('current');
|
||||
|
|
|
|||
|
|
@ -114,6 +114,9 @@ export function createRouter(ui) {
|
|||
case 'home':
|
||||
await ui.renderHomePage();
|
||||
break;
|
||||
case 'reset-password':
|
||||
await ui.renderResetPasswordPage();
|
||||
break;
|
||||
case 'donate':
|
||||
ui.showPage('donate');
|
||||
break;
|
||||
|
|
|
|||
66
js/ui.js
66
js/ui.js
|
|
@ -2392,6 +2392,72 @@ export class UIRenderer {
|
|||
}
|
||||
}
|
||||
|
||||
async renderResetPasswordPage() {
|
||||
await this.showPage('reset-password');
|
||||
const form = document.getElementById('reset-password-form');
|
||||
const errorEl = document.getElementById('reset-password-error');
|
||||
const successEl = document.getElementById('reset-password-success');
|
||||
const btn = document.getElementById('reset-password-submit-btn');
|
||||
const btnText = document.getElementById('reset-password-btn-text');
|
||||
const spinner = document.getElementById('reset-password-btn-spinner');
|
||||
const passwordInput = document.getElementById('reset-password-input');
|
||||
const confirmInput = document.getElementById('reset-password-confirm');
|
||||
|
||||
if (!form) return;
|
||||
|
||||
const params = new URLSearchParams(window.location.search);
|
||||
const userId = params.get('userId');
|
||||
const secret = params.get('secret');
|
||||
|
||||
if (!userId || !secret) {
|
||||
errorEl.textContent = 'Invalid or missing password reset link.';
|
||||
errorEl.style.display = 'block';
|
||||
form.style.display = 'none';
|
||||
return;
|
||||
}
|
||||
|
||||
form.onsubmit = async (e) => {
|
||||
e.preventDefault();
|
||||
errorEl.style.display = 'none';
|
||||
successEl.style.display = 'none';
|
||||
|
||||
const password = passwordInput.value;
|
||||
const confirm = confirmInput.value;
|
||||
|
||||
if (password !== confirm) {
|
||||
errorEl.textContent = 'Passwords do not match.';
|
||||
errorEl.style.display = 'block';
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
btn.disabled = true;
|
||||
btnText.style.display = 'none';
|
||||
spinner.style.display = 'block';
|
||||
|
||||
await authManager.resetPassword(userId, secret, password, confirm);
|
||||
|
||||
successEl.textContent = 'Password reset successfully. Opening login...';
|
||||
successEl.style.display = 'block';
|
||||
form.style.display = 'none';
|
||||
|
||||
setTimeout(() => {
|
||||
const authModal = document.getElementById('email-auth-modal');
|
||||
if (authModal) {
|
||||
authModal.classList.add('active');
|
||||
}
|
||||
}, 2000);
|
||||
} catch (error) {
|
||||
errorEl.textContent = error.message || 'Failed to reset password. Please try again.';
|
||||
errorEl.style.display = 'block';
|
||||
} finally {
|
||||
btn.disabled = false;
|
||||
btnText.style.display = 'inline';
|
||||
spinner.style.display = 'none';
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
async renderPartyDetailPage(id) {
|
||||
await this.showPage('party-detail');
|
||||
await partyManager.joinParty(id);
|
||||
|
|
|
|||
Loading…
Reference in a new issue