diff --git a/pos/blueprints/auth_bp.py b/pos/blueprints/auth_bp.py index 3dd1870..1b8befc 100644 --- a/pos/blueprints/auth_bp.py +++ b/pos/blueprints/auth_bp.py @@ -157,6 +157,38 @@ def login_pin(): }) +@auth_bp.route('/employees/', methods=['GET']) +def list_login_employees(tenant_id): + """Public endpoint: list employees for the login screen (names + roles only, no sensitive data).""" + try: + conn = get_tenant_conn(tenant_id) + except ValueError: + return jsonify({'error': 'Tenant not found'}), 404 + + cur = conn.cursor() + cur.execute(""" + SELECT id, name, role FROM employees + WHERE is_active = true AND pin IS NOT NULL + ORDER BY name + """) + employees = [] + for row in cur.fetchall(): + name = row[1] + parts = name.split() + initials = ''.join([p[0].upper() for p in parts[:2]]) if parts else '?' + role_labels = {'owner': 'Dueño', 'admin': 'Administrador', 'cashier': 'Cajero', 'warehouse': 'Almacén', 'accountant': 'Contador'} + employees.append({ + 'id': row[0], + 'name': name, + 'initials': initials, + 'role': row[2], + 'role_label': role_labels.get(row[2], row[2]) + }) + cur.close() + conn.close() + return jsonify({'data': employees}) + + @auth_bp.route('/me', methods=['GET']) def auth_me(): """Get current employee info from token.""" diff --git a/pos/templates/login.html b/pos/templates/login.html index 70ef065..7bdecee 100644 --- a/pos/templates/login.html +++ b/pos/templates/login.html @@ -890,92 +890,9 @@
-
- - - - - - - - - - - - - +
+ +
Cargando empleados...
@@ -1105,28 +1022,8 @@ }); /* ------------------------------------------------------------------ - USER SELECTION + USER SELECTION — handled dynamically in loadEmployees() ------------------------------------------------------------------ */ - userBtns.forEach(btn => { - btn.addEventListener('click', () => { - // Deselect all - userBtns.forEach(b => { - b.classList.remove('selected'); - b.setAttribute('aria-checked', 'false'); - }); - - // Select clicked - btn.classList.add('selected'); - btn.setAttribute('aria-checked', 'true'); - state.selectedUser = btn.dataset.user; - state.pin = []; - - // Enable PIN pad - enablePinPad(); - updatePinDisplay(); - updateLoginButton(); - }); - }); /* ------------------------------------------------------------------ PIN PAD LOGIC @@ -1373,6 +1270,64 @@ } }); + /* ------------------------------------------------------------------ + LOAD REAL EMPLOYEES FROM API + ------------------------------------------------------------------ */ + function loadEmployees() { + if (!tenantId) { + document.getElementById('usersGrid').innerHTML = '
No se especificó tenant. Agrega ?tenant=ID a la URL.
'; + return; + } + fetch('/pos/api/auth/employees/' + tenantId) + .then(function(r) { return r.json(); }) + .then(function(data) { + var grid = document.getElementById('usersGrid'); + var employees = data.data || []; + if (!employees.length) { + grid.innerHTML = '
No hay empleados registrados.
'; + return; + } + grid.innerHTML = ''; + employees.forEach(function(emp) { + var btn = document.createElement('button'); + btn.className = 'user-avatar-btn'; + btn.setAttribute('data-user', emp.initials); + btn.setAttribute('data-name', emp.name); + btn.setAttribute('data-role', emp.role_label); + btn.setAttribute('role', 'radio'); + btn.setAttribute('aria-checked', 'false'); + btn.setAttribute('aria-label', emp.name + ', ' + emp.role_label); + btn.innerHTML = '' + + '
' + emp.name + '
' + + '
' + emp.role_label + '
'; + btn.addEventListener('click', function() { + // Deselect all + grid.querySelectorAll('.user-avatar-btn').forEach(function(b) { + b.classList.remove('selected'); + b.setAttribute('aria-checked', 'false'); + }); + // Select this one + btn.classList.add('selected'); + btn.setAttribute('aria-checked', 'true'); + state.selectedUser = emp.initials; + state.pin = []; + enablePinPad(); + updatePinDisplay(); + updateLoginButton(); + }); + grid.appendChild(btn); + }); + + // If only 1 employee, auto-select + if (employees.length === 1) { + grid.querySelector('.user-avatar-btn').click(); + } + }) + .catch(function() { + document.getElementById('usersGrid').innerHTML = '
Error al cargar empleados.
'; + }); + } + /* ------------------------------------------------------------------ INIT ------------------------------------------------------------------ */ @@ -1380,6 +1335,8 @@ disablePinPad(); updatePinDisplay(); updateLoginButton(); + // Load real employees + loadEmployees();