Reset Password

Enter your account email. You will receive a password reset token via email.

Need an account? Register

(function(){ const $ = s => document.querySelector(s); const pt=$('#platformTrigger'), pm=$('#platformMenu'), lt=$('#loginToggle'), lp=$('#loginPanel'), lo=$('#logoutLink'); const hide = el => el && el.classList.add('hidden'); const show = el => el && el.classList.remove('hidden'); const outside = (el, trigger, e) => el && !el.contains(e.target) && !trigger.contains(e.target); pt?.addEventListener('click', e => { e.preventDefault(); e.stopPropagation(); pm?.classList.toggle('hidden'); lp && hide(lp); pt.setAttribute('aria-expanded', String(!pm?.classList.contains('hidden'))); }); lt?.addEventListener('click', e => { e.preventDefault(); e.stopPropagation(); lp?.classList.toggle('hidden'); pm && hide(pm); lt.setAttribute('aria-expanded', String(!lp?.classList.contains('hidden'))); }); document.addEventListener('click', e => { if (pm && pt && outside(pm, pt, e)) { hide(pm); pt.setAttribute('aria-expanded','false'); } if (lp && lt && outside(lp, lt, e)) { hide(lp); lt.setAttribute('aria-expanded','false'); } }); document.addEventListener('keydown', e => { if (e.key === 'Escape'){ hide(pm); hide(lp); pt?.setAttribute('aria-expanded','false'); lt?.setAttribute('aria-expanded','false'); } }); // Auth visibility + logout if (localStorage.getItem('auth_token')) { if (lo) lo.style.display='inline-block'; if (lt) lt.style.display='none'; lo?.addEventListener('click', e => { e.preventDefault(); localStorage.removeItem('auth_token'); localStorage.removeItem('must_change_pw'); window.location.href = '/auth/login.html'; }); } else { if (lo) lo.style.display='none'; } // Inline login submit const loginForm=document.querySelector('form[data-login-form]'); loginForm?.addEventListener('submit', async e=>{ e.preventDefault(); const fd=new FormData(loginForm); const identifier=(fd.get('email')||fd.get('username')||'').toString().trim(); const password=(fd.get('password')||'').toString(); if(!identifier||!password) return alert('Enter email and password.'); try{ const res=await fetch('/api/auth/login',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({identifier,password})}); const text=await res.text(); let data={}; try{ data=JSON.parse(text);}catch{} if(!res.ok) throw new Error(data.error||data.message||'Login failed'); localStorage.setItem('auth_token', data.token); localStorage.setItem('must_change_pw', String(!!data.mustChangePassword)); window.location.href = data.mustChangePassword ? '/auth/change-password.html' : '/student/dashboard.html'; }catch(err){ alert(err.message||'Login failed'); } }); })(); // Password reset flow (API version) (function(){ const reqForm=document.getElementById('resetRequestForm'); const applyForm=document.getElementById('resetApplyForm'); const reqMsg=document.getElementById('reqMsg'); const cancelBtn=document.getElementById('cancelReset'); const tokenInput=document.getElementById('resetToken'); const pass1=document.getElementById('newPass'); const pass2=document.getElementById('newPass2'); const errorsBox=document.getElementById('resetErrors'); const successBox=document.getElementById('resetSuccess'); function show(el){ el.classList.remove('hidden'); } function hide(el){ el.classList.add('hidden'); } // Step 1: Request token from backend reqForm.addEventListener('submit', async e=>{ e.preventDefault(); const email=document.getElementById('resetEmail').value.trim(); hide(reqMsg); hide(errorsBox); hide(successBox); try { const res = await fetch('/api/auth/request-reset', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ email }) }); const data = await res.json(); if (!res.ok) throw new Error(data.error || 'Request failed'); reqMsg.textContent = 'A reset token has been sent to your email.'; reqMsg.className = 'md:col-span-2 text-[12px] text-pg-gold'; show(reqMsg); hide(reqForm); show(applyForm); } catch (err) { reqMsg.textContent = err.message; reqMsg.className = 'md:col-span-2 text-[12px] text-red-300'; show(reqMsg); } }); cancelBtn.addEventListener('click', ()=>{ hide(applyForm); show(reqForm); hide(errorsBox); hide(successBox); reqMsg.classList.add('hidden'); }); // Step 2: Apply token and new password via backend, then auto-login and redirect applyForm.addEventListener('submit', async e=>{ e.preventDefault(); hide(errorsBox); hide(successBox); const email=document.getElementById('resetEmail').value.trim(); const token=tokenInput.value.trim(); const newPassword=pass1.value.trim(); const confirmPassword=pass2.value.trim(); const errs=[]; if(newPassword.length < 6) errs.push('Password must be at least 6 characters.'); if(newPassword !== confirmPassword) errs.push('Passwords do not match.'); if(!token) errs.push('Token required.'); if(errs.length){ errorsBox.innerHTML=errs.map(e=>'• '+e).join('
'); show(errorsBox); return; } try { const res = await fetch('/api/auth/apply-reset', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ email, token, newPassword }) }); const data = await res.json(); if (!res.ok) throw new Error(data.error || 'Password update failed'); successBox.textContent = 'Password updated. Logging you in...'; show(successBox); // Auto-login with new password const loginRes = await fetch('/api/auth/login', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ identifier: email, password: newPassword }) }); const loginData = await loginRes.json(); if (!loginRes.ok) throw new Error(loginData.error || 'Login failed'); localStorage.setItem('auth_token', loginData.token); setTimeout(()=>window.location.href='/student/dashboard.html', 800); } catch (err) { errorsBox.innerHTML = '• ' + (err.message || 'Password update or login failed'); show(errorsBox); } }); })();