diff --git a/pos/static/js/app-init.js b/pos/static/js/app-init.js
new file mode 100644
index 0000000..39a7f70
--- /dev/null
+++ b/pos/static/js/app-init.js
@@ -0,0 +1,143 @@
+/**
+ * app-init.js — Shared initialization for all POS pages
+ *
+ * Handles:
+ * 1. Auth check (redirect to login if no valid token)
+ * 2. Set real employee name/role in sidebar and header
+ * 3. Set navigation links as active based on current page
+ * 4. Sidebar toggle for mobile
+ */
+(function() {
+ 'use strict';
+
+ // ─── Auth Check ───
+ var token = localStorage.getItem('pos_token');
+ if (!token) {
+ window.location.href = '/pos/login';
+ return;
+ }
+
+ // Validate token not expired
+ try {
+ var payload = JSON.parse(atob(token.split('.')[1]));
+ if (payload.exp * 1000 < Date.now()) {
+ localStorage.removeItem('pos_token');
+ localStorage.removeItem('pos_employee');
+ window.location.href = '/pos/login';
+ return;
+ }
+ } catch(e) {
+ localStorage.removeItem('pos_token');
+ window.location.href = '/pos/login';
+ return;
+ }
+
+ // ─── Get employee info ───
+ var employee = {};
+ try {
+ employee = JSON.parse(localStorage.getItem('pos_employee') || '{}');
+ } catch(e) {}
+
+ var name = employee.name || payload.name || 'Usuario';
+ var role = employee.role || payload.role || '';
+ var roleLabels = {
+ 'owner': 'Dueño', 'admin': 'Administrador', 'cashier': 'Cajero',
+ 'warehouse': 'Almacén', 'accountant': 'Contador'
+ };
+ var roleLabel = roleLabels[role] || role;
+ var initials = name.split(' ').map(function(p) { return p[0]; }).join('').toUpperCase().substring(0, 2);
+
+ // ─── Replace hardcoded names in sidebar ───
+ // Sidebar user name
+ document.querySelectorAll('.sidebar__user-name').forEach(function(el) {
+ el.textContent = name;
+ });
+ // Sidebar user role
+ document.querySelectorAll('.sidebar__user-role').forEach(function(el) {
+ el.textContent = roleLabel;
+ });
+ // Sidebar user initials/avatar
+ document.querySelectorAll('.sidebar__user-avatar, .sidebar__avatar').forEach(function(el) {
+ el.textContent = initials;
+ });
+
+ // Profile info in headers (catalog uses this pattern)
+ document.querySelectorAll('.profile-info__name').forEach(function(el) {
+ el.textContent = name;
+ });
+ document.querySelectorAll('.profile-info__role').forEach(function(el) {
+ el.textContent = roleLabel;
+ });
+
+ // Theme bar user labels
+ document.querySelectorAll('.theme-bar__label').forEach(function(el) {
+ if (el.textContent.indexOf('Usuario:') !== -1 || el.textContent.indexOf('Sucursal') !== -1) {
+ el.textContent = 'Sucursal Principal — ' + name;
+ }
+ });
+
+ // Status bar user names
+ document.querySelectorAll('.status-bar .user-name, .status-info span').forEach(function(el) {
+ var text = el.textContent;
+ // Replace common demo names
+ ['Hugo M.', 'Hugo García', 'J. Ramírez', 'José Ramírez', 'Carlos M.', 'Admin'].forEach(function(demo) {
+ if (text.indexOf(demo) !== -1) {
+ el.textContent = text.replace(demo, name);
+ }
+ });
+ });
+
+ // ─── Set active nav link ───
+ var path = window.location.pathname;
+ var navMap = {
+ '/pos/dashboard': 'dashboard',
+ '/pos/sale': 'pos',
+ '/pos/catalog': 'catalogo',
+ '/pos/inventory': 'inventario',
+ '/pos/customers': 'clientes',
+ '/pos/invoicing': 'facturacion',
+ '/pos/accounting': 'contabilidad',
+ '/pos/reports': 'reportes',
+ '/pos/config': 'configuracion'
+ };
+
+ document.querySelectorAll('.nav-item, .nav-link').forEach(function(link) {
+ link.classList.remove('is-active', 'active');
+ var href = link.getAttribute('href') || '';
+ if (href === path) {
+ link.classList.add('is-active');
+ link.classList.add('active');
+ }
+ });
+
+ // ─── Logout ───
+ window.posLogout = function() {
+ localStorage.removeItem('pos_token');
+ localStorage.removeItem('pos_employee');
+ localStorage.removeItem('pos_tenant_id');
+ localStorage.removeItem('pos_cart');
+ window.location.href = '/pos/login';
+ };
+
+ // Wire any logout buttons
+ document.querySelectorAll('[data-action="logout"], .btn-logout, .logout-btn').forEach(function(btn) {
+ btn.addEventListener('click', function(e) {
+ e.preventDefault();
+ posLogout();
+ });
+ });
+
+ // ─── Expose globally ───
+ window.POS_USER = {
+ name: name,
+ role: role,
+ roleLabel: roleLabel,
+ initials: initials,
+ token: token,
+ tenantId: payload.tenant_id,
+ employeeId: payload.employee_id,
+ branchId: payload.branch_id,
+ permissions: payload.permissions || []
+ };
+
+})();
diff --git a/pos/templates/accounting.html b/pos/templates/accounting.html
index b15fbec..65e4577 100644
--- a/pos/templates/accounting.html
+++ b/pos/templates/accounting.html
@@ -2249,6 +2249,7 @@
+