diff --git a/public/js/auth.js b/public/js/auth.js new file mode 100644 index 0000000..9c7c797 --- /dev/null +++ b/public/js/auth.js @@ -0,0 +1,127 @@ +import { api, loadGoals } from './api.js'; +import { tr } from './i18n.js'; +import { state } from './state.js'; +import { tpl, showSheet, closeOv, showToast, updateHeader } from './ui.js'; +import { render } from './render.js'; + +export function showLogin(err) { + const c = tpl('tpl-login'); + if (err) { const e = c.querySelector('.login-err'); e.textContent = err; e.style.display = ''; } + showSheet(c, false); + const email = c.querySelector('.lf-email'), pass = c.querySelector('.lf-pass'), sub = c.querySelector('.lf-sub'); + setTimeout(() => email.focus(), 50); + email.onkeydown = e => { if (e.key === 'Enter') pass.focus(); }; + pass.onkeydown = e => { if (e.key === 'Enter') sub.click(); }; + c.querySelector('.lf-fgt').onclick = () => showForgotPassword(); + sub.onclick = () => { + const ev = email.value.trim(), pv = pass.value; + if (!ev || !pv) { + const errEl = c.querySelector('.login-err'); + errEl.textContent = tr('loginErrEmpty'); errEl.style.display = ''; + return; + } + sub.disabled = true; sub.textContent = '…'; + api('POST', 'login', { email: ev, password: pv }) + .then(() => loadGoals()) + .then(g => { state.goals = g; closeOv(); render(); }) + .catch(err => { + sub.disabled = false; sub.textContent = tr('loginBtn'); + showLogin(err.status === 401 ? tr('loginErrWrong') : err.status === 429 ? tr('loginErrRate') : tr('loginErrConn')); + }); + }; +} + +export function showForgotPassword() { + const c = tpl('tpl-forgot-pw'); + showSheet(c, false); + const email = c.querySelector('.fp-email'), errEl = c.querySelector('.login-err'), sub = c.querySelector('.fp-sub'); + setTimeout(() => email.focus(), 50); + c.querySelector('.fp-back').onclick = () => showLogin(); + sub.onclick = () => { + const ev = email.value.trim(); if (!ev) return; + sub.disabled = true; sub.textContent = '…'; + api('POST', 'reset-request', { email: ev }) + .then(() => { + const conf = tpl('tpl-email-sent'); + conf.querySelector('.es-ok').onclick = () => showLogin(); + showSheet(conf, false); + }) + .catch(err => { + sub.disabled = false; sub.textContent = tr('sendLink'); + errEl.textContent = err.message || 'Fehler'; errEl.style.display = ''; + }); + }; +} + +export function showResetPassword(selector, token) { + const c = tpl('tpl-reset-pw'); + showSheet(c, false); + const pass = c.querySelector('.rp-pass'), errEl = c.querySelector('.login-err'), sub = c.querySelector('.rp-sub'); + setTimeout(() => pass.focus(), 50); + sub.onclick = () => { + const pv = pass.value; if (!pv) return; + sub.disabled = true; sub.textContent = '…'; + api('POST', 'reset-password', { selector, token, password: pv }) + .then(() => { + const conf = tpl('tpl-pw-changed'); + conf.querySelector('.pc-ok').onclick = () => showLogin(); + showSheet(conf, false); + }) + .catch(err => { + sub.disabled = false; sub.textContent = tr('setPw'); + errEl.textContent = err.message || 'Fehler'; errEl.style.display = ''; + }); + }; +} + +export function showChangePassword() { + const c = tpl('tpl-change-pw'); + showSheet(c, true); + const oldP = c.querySelector('.cp-old'), newP = c.querySelector('.cp-new'), newP2 = c.querySelector('.cp-new2'); + const errEl = c.querySelector('.login-err'), sub = c.querySelector('.cp-sub'); + setTimeout(() => oldP.focus(), 50); + c.querySelector('.cp-can').onclick = closeOv; + sub.onclick = () => { + const o = oldP.value, n = newP.value, n2 = newP2.value; + if (!o || !n || !n2) return; + if (n !== n2) { errEl.textContent = tr('errPwMismatch'); errEl.style.display = ''; return; } + sub.disabled = true; sub.textContent = '…'; + api('POST', 'change-password', { old_password: o, new_password: n }) + .then(() => { showToast(tr('pwChanged')); closeOv(); }) + .catch(err => { + sub.disabled = false; sub.textContent = tr('changePwBtn'); + errEl.textContent = err.message || 'Fehler'; errEl.style.display = ''; + }); + }; +} + +export function showRegister(token) { + const c = tpl('tpl-register'); + showSheet(c, false); + const nameInp = c.querySelector('.rg-name'), email = c.querySelector('.rg-email'); + const pass = c.querySelector('.rg-pass'), pass2 = c.querySelector('.rg-pass2'); + const errEl = c.querySelector('.login-err'), sub = c.querySelector('.rg-sub'); + setTimeout(() => nameInp.focus(), 50); + nameInp.onkeydown = e => { if (e.key === 'Enter') email.focus(); }; + email.onkeydown = e => { if (e.key === 'Enter') pass.focus(); }; + pass.onkeydown = e => { if (e.key === 'Enter') pass2.focus(); }; + pass2.onkeydown = e => { if (e.key === 'Enter') sub.click(); }; + const checkMatch = () => { + if (pass2.value && pass.value !== pass2.value) { errEl.textContent = tr('errPwMismatch2'); errEl.style.display = ''; } + else errEl.style.display = 'none'; + }; + pass.oninput = checkMatch; pass2.oninput = checkMatch; + sub.onclick = () => { + const nv = nameInp.value.trim(), ev = email.value.trim(), pv = pass.value; + if (!nv || !ev || !pv) { errEl.textContent = tr('errFillAll'); errEl.style.display = ''; return; } + if (pv !== pass2.value) { errEl.textContent = tr('errPwMismatch2'); errEl.style.display = ''; return; } + sub.disabled = true; sub.textContent = '…'; + api('POST', 'register', { name: nv, email: ev, password: pv, token }) + .then(r => { state.userName = r.name || ''; return loadGoals(); }) + .then(g => { state.goals = g; closeOv(); updateHeader(); render(); }) + .catch(err => { + sub.disabled = false; sub.textContent = tr('registerBtn'); + errEl.textContent = err.message || 'Fehler'; errEl.style.display = ''; + }); + }; +}