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>
228 lines
7.6 KiB
JavaScript
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');
|
|
};
|
|
|
|
})();
|