Files
Autoparts-DB/dashboard/login.js
consultoria-as 565f11aca6 feat: add login/register page with JWT auth flow
Login form with role-based redirect (ADMIN→demo, BODEGA→bodega, TALLER→demo).
Register form for TALLER/BODEGA with admin approval required.
Includes authFetch() wrapper with automatic token refresh.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 22:24:51 +00:00

228 lines
7.6 KiB
JavaScript

/* ============================================================
login.js -- Login / Register logic for Nexus Autoparts
============================================================ */
(function () {
'use strict';
// ---- DOM refs ----
const loginPanel = document.getElementById('loginPanel');
const registerPanel = document.getElementById('registerPanel');
const loginForm = document.getElementById('loginForm');
const registerForm = document.getElementById('registerForm');
const alertBox = document.getElementById('alert');
// ---- Role-based redirect map ----
const ROLE_REDIRECTS = {
ADMIN: '/demo',
OWNER: '/demo',
BODEGA: '/bodega',
TALLER: '/demo',
};
// ---- Check existing session on load ----
(function checkSession() {
const token = localStorage.getItem('access_token');
const role = localStorage.getItem('user_role');
if (token && role) {
const dest = ROLE_REDIRECTS[role] || '/index.html';
window.location.replace(dest);
}
})();
// ---- Panel toggling ----
window.showPanel = function (panel) {
hideAlert();
if (panel === 'register') {
loginPanel.classList.remove('active');
registerPanel.classList.add('active');
} else {
registerPanel.classList.remove('active');
loginPanel.classList.add('active');
}
};
// ---- Alert helpers ----
function showAlert(msg, type) {
alertBox.textContent = msg;
alertBox.className = 'login-alert show ' + type;
}
function hideAlert() {
alertBox.className = 'login-alert';
alertBox.textContent = '';
}
function setLoading(btn, loading) {
btn.classList.toggle('loading', loading);
}
// ---- Login ----
loginForm.addEventListener('submit', async function (e) {
e.preventDefault();
hideAlert();
const email = document.getElementById('loginEmail').value.trim();
const password = document.getElementById('loginPassword').value;
const btn = loginForm.querySelector('.btn-submit');
if (!email || !password) {
showAlert('Completa todos los campos.', 'error');
return;
}
setLoading(btn, true);
try {
const res = await fetch('/api/auth/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ email, password }),
});
const data = await res.json();
if (!res.ok) {
showAlert(data.error || data.message || 'Credenciales incorrectas.', 'error');
return;
}
// Persist tokens & user info
localStorage.setItem('access_token', data.access_token);
localStorage.setItem('refresh_token', data.refresh_token || '');
localStorage.setItem('user_role', data.role || data.user?.role || '');
localStorage.setItem('user_name', data.name || data.user?.name || '');
const role = (data.role || data.user?.role || '').toUpperCase();
const dest = ROLE_REDIRECTS[role] || '/index.html';
window.location.replace(dest);
} catch (err) {
showAlert('Error de conexion. Intenta de nuevo.', 'error');
} finally {
setLoading(btn, false);
}
});
// ---- Register ----
registerForm.addEventListener('submit', async function (e) {
e.preventDefault();
hideAlert();
const name = document.getElementById('regName').value.trim();
const email = document.getElementById('regEmail').value.trim();
const password = document.getElementById('regPassword').value;
const confirm = document.getElementById('regConfirm').value;
const business_name = document.getElementById('regBusiness').value.trim();
const phone = document.getElementById('regPhone').value.trim();
const role = document.getElementById('regRole').value;
const btn = registerForm.querySelector('.btn-submit');
// Validations
if (!name || !email || !password || !confirm || !business_name || !phone) {
showAlert('Completa todos los campos.', 'error');
return;
}
if (password.length < 8) {
showAlert('La contrasena debe tener al menos 8 caracteres.', 'error');
return;
}
if (password !== confirm) {
showAlert('Las contrasenas no coinciden.', 'error');
return;
}
setLoading(btn, true);
try {
const res = await fetch('/api/auth/register', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ name, email, password, role, business_name, phone }),
});
const data = await res.json();
if (!res.ok) {
showAlert(data.error || data.message || 'Error al crear la cuenta.', 'error');
return;
}
showAlert('Cuenta creada. Pendiente de aprobacion por administrador.', 'success');
registerForm.reset();
} catch (err) {
showAlert('Error de conexion. Intenta de nuevo.', 'error');
} finally {
setLoading(btn, false);
}
});
// ================================================================
// authFetch -- Authenticated fetch wrapper (exported globally)
// ================================================================
window.authFetch = async function authFetch(url, options = {}) {
const token = localStorage.getItem('access_token');
if (!token) {
window.location.replace('/login.html');
return;
}
const headers = Object.assign({}, options.headers || {}, {
'Authorization': 'Bearer ' + token,
});
let res = await fetch(url, Object.assign({}, options, { headers }));
// If 401, try refreshing the token once
if (res.status === 401) {
const refreshed = await tryRefreshToken();
if (refreshed) {
headers['Authorization'] = 'Bearer ' + localStorage.getItem('access_token');
res = await fetch(url, Object.assign({}, options, { headers }));
} else {
// Refresh failed — log out
logout();
return;
}
}
return res;
};
async function tryRefreshToken() {
const refreshToken = localStorage.getItem('refresh_token');
if (!refreshToken) return false;
try {
const res = await fetch('/api/auth/refresh', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ refresh_token: refreshToken }),
});
if (!res.ok) return false;
const data = await res.json();
localStorage.setItem('access_token', data.access_token);
if (data.refresh_token) {
localStorage.setItem('refresh_token', data.refresh_token);
}
return true;
} catch (e) {
return false;
}
}
window.logout = function logout() {
localStorage.removeItem('access_token');
localStorage.removeItem('refresh_token');
localStorage.removeItem('user_role');
localStorage.removeItem('user_name');
window.location.replace('/login.html');
};
})();