Download src/ui/AuthUI.js from mlmihjaz/Echo: direct link, hf CLI and curl.
- Browser
- Download file 5.2 kB
-
https://huggingface.co/spaces/mlmihjaz/Echo/resolve/main/src/ui/AuthUI.js
- Command line
-
hf download hf://spaces/mlmihjaz/Echo/src/ui/AuthUI.js
-
curl -L -o AuthUI.js https://huggingface.co/spaces/mlmihjaz/Echo/resolve/main/src/ui/AuthUI.js
5.2 kB
| /** | |
| * AuthUI — wires the login/register form. | |
| */ | |
| import { Auth } from '../auth/Auth.js'; | |
| export class AuthUI { | |
| constructor({ onEnter, adminOnly = false } = {}) { | |
| this.onEnter = onEnter; | |
| this.adminOnly = adminOnly; | |
| this.mode = 'login'; | |
| this._bind(); | |
| if (this.adminOnly) this._applyAdminMode(); | |
| this.setMode('login'); | |
| } | |
| /** Hide the Register tab, Guest button, and tighten the wording for /admin. */ | |
| _applyAdminMode() { | |
| const tabReg = this.$('tabRegister'); | |
| if (tabReg) tabReg.style.display = 'none'; | |
| const tabLogin = this.$('tabLogin'); | |
| if (tabLogin) tabLogin.textContent = 'Admin sign-in'; | |
| const guestRow = document.querySelector('.auth-card .guest'); | |
| if (guestRow) guestRow.style.display = 'none'; | |
| // Tighten the auth card heading. | |
| const h2 = document.querySelector('.auth-card h2'); | |
| if (h2) h2.textContent = 'ECHO · Admin'; | |
| const sub = this.$('authSub'); | |
| if (sub) sub.textContent = 'Restricted area. Admin credentials required.'; | |
| } | |
| $(id) { return document.getElementById(id); } | |
| _bind() { | |
| this.$('tabLogin').addEventListener('click', () => this.setMode('login')); | |
| this.$('tabRegister').addEventListener('click', () => this.setMode('register')); | |
| // Form submit (Enter key + button[type=submit]) | |
| this.$('authForm').addEventListener('submit', e => this._submit(e)); | |
| // Belt-and-braces: also handle direct button click in case the form's submit event is swallowed | |
| this.$('authBtn').addEventListener('click', e => { e.preventDefault(); this._submit(e); }); | |
| this.$('forgotBtn').addEventListener('click', () => this._forgot()); | |
| this.$('guestBtn').addEventListener('click', () => { Auth.logout().catch(()=>{});this.hide(); this.onEnter?.(true); }); | |
| this.$('signOutBtn').addEventListener('click', () => { Auth.logout().catch(()=>{});location.reload(); }); | |
| console.log('[Auth] UI bound successfully'); | |
| } | |
| setMode(m) { | |
| // In adminOnly mode, ignore register and force login. | |
| if (this.adminOnly) m = 'login'; | |
| this.mode = m; | |
| this.$('tabLogin').classList.toggle('active', m === 'login'); | |
| this.$('tabRegister').classList.toggle('active', m === 'register'); | |
| this.$('fNameRow').style.display = m === 'register' ? 'block' : 'none'; | |
| this.$('fPwd2Row').style.display = m === 'register' ? 'block' : 'none'; | |
| this.$('authBtn').textContent = m === 'login' ? 'Login' : 'Create account'; | |
| if (!this.adminOnly) { | |
| this.$('authSub').textContent = m === 'login' | |
| ? 'Welcome back — sign in to resume.' | |
| : 'Create an account — track stars, climb the leaderboard.'; | |
| } | |
| this.$('forgotBtn').style.display = (m === 'login' && !this.adminOnly) ? 'inline' : 'none'; | |
| this.$('fErr').textContent = ''; | |
| } | |
| async _submit(e) { | |
| if (e?.preventDefault) e.preventDefault(); | |
| const email = this.$('fEmail').value; | |
| const pwd = this.$('fPwd').value; | |
| const pwd2 = this.$('fPwd2').value; | |
| const name = this.$('fName').value; | |
| console.log(`[Auth] ${this.mode} submit: email="${email}" pwd.len=${pwd.length}`); | |
| if (!email) { | |
| this.$('fErr').style.color = 'var(--coral)'; | |
| this.$('fErr').textContent = 'Email is required.'; | |
| return; | |
| } | |
| if (!pwd) { | |
| this.$('fErr').style.color = 'var(--coral)'; | |
| this.$('fErr').textContent = 'Password is required.'; | |
| return; | |
| } | |
| try { | |
| let user; | |
| if (this.mode === 'register') { | |
| if (this.adminOnly) throw new Error('Registration is closed on /admin'); | |
| if (pwd !== pwd2) throw new Error('Passwords do not match'); | |
| user = await Auth.register(email, pwd, name); | |
| console.log('[Auth] registered:', user.email); | |
| } else { | |
| user = await Auth.login(email, pwd); | |
| console.log('[Auth] logged in:', user.email); | |
| } | |
| // /admin route: reject non-admin logins immediately. | |
| if (this.adminOnly && !user.isAdmin) { | |
| await Auth.logout().catch(() => {}); | |
| throw new Error('Admin access only.'); | |
| } | |
| this.$('fErr').style.color = 'var(--spring)'; | |
| this.$('fErr').textContent = `✓ Welcome, ${user.name}!`; | |
| setTimeout(() => { | |
| this.hide(); | |
| this.onEnter?.(false); | |
| }, 350); | |
| } catch (err) { | |
| console.warn('[Auth] error:', err.message); | |
| this.$('fErr').style.color = 'var(--coral)'; | |
| this.$('fErr').textContent = err.message; | |
| } | |
| } | |
| _forgot() { | |
| const email = this.$('fEmail').value.trim(); | |
| if (!email) { this.$('fErr').textContent = 'Type your email above, then click Forgot password.'; return; } | |
| const np = prompt(`Enter a new password (6+ chars) for ${email}:`); | |
| if (!np) return; | |
| try { | |
| Auth.resetPwd(email, np); | |
| this.$('fErr').style.color = 'var(--spring)'; | |
| this.$('fErr').textContent = 'Password reset — login with the new one.'; | |
| } catch (err) { | |
| this.$('fErr').style.color = 'var(--coral)'; | |
| this.$('fErr').textContent = err.message; | |
| } | |
| } | |
| show() { this.$('authScreen').classList.remove('hidden'); this.$('appWrap').style.display = 'none'; } | |
| hide() { this.$('authScreen').classList.add('hidden'); this.$('appWrap').style.display = ''; } | |
| } | |