feat: module toggles in POS config and Instance Manager
- Add GET/PUT /pos/api/config/modules endpoints in POS config_bp.py - Update sidebar.js to filter nav items based on enabled modules - Add Modules section to POS config.html with toggles for WhatsApp, Marketplace, MercadoLibre - Add module load/save logic to POS config.js - Preload modules in app-init.js for sidebar caching - Add tenant module management to Instance Manager - get_tenant_modules / update_tenant_modules in tenant_service.py - GET/PUT /api/tenants/<id>/modules endpoints in tenants_bp.py - Add modules modal to manager index.html - Add module editing UI and logic to manager.js - Add toggle-switch CSS to manager.css
This commit is contained in:
@@ -121,6 +121,9 @@ function showSection(sectionId) {
|
||||
case 'users':
|
||||
loadUsers();
|
||||
break;
|
||||
case 'tenants':
|
||||
loadTenants();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2074,3 +2077,99 @@ async function toggleUserActive(userId, currentActive) {
|
||||
showAlert(e.message, 'error');
|
||||
}
|
||||
}
|
||||
|
||||
// ─── Tenants / Modules ─────────────────────────────────────────────────────
|
||||
|
||||
async function loadTenants() {
|
||||
var token = localStorage.getItem('access_token');
|
||||
var tbody = document.getElementById('tenantsTable');
|
||||
tbody.innerHTML = '<tr><td colspan="6" class="loading"><div class="spinner"></div></td></tr>';
|
||||
|
||||
try {
|
||||
var res = await fetch('/api/admin/tenants', {
|
||||
headers: { 'Authorization': 'Bearer ' + token }
|
||||
});
|
||||
if (!res.ok) throw new Error('Error al cargar tenants (' + res.status + ')');
|
||||
var data = await res.json();
|
||||
var tenants = data.tenants || [];
|
||||
|
||||
if (tenants.length === 0) {
|
||||
tbody.innerHTML = '<tr><td colspan="6" style="text-align:center; color:var(--text-secondary); padding:2rem;">No hay tenants activos</td></tr>';
|
||||
return;
|
||||
}
|
||||
|
||||
// Load modules for each tenant
|
||||
var modulesMap = {};
|
||||
await Promise.all(tenants.map(async function(t) {
|
||||
try {
|
||||
var mres = await fetch('/api/admin/tenants/' + t.id + '/modules', {
|
||||
headers: { 'Authorization': 'Bearer ' + token }
|
||||
});
|
||||
if (mres.ok) {
|
||||
modulesMap[t.id] = await mres.json();
|
||||
} else {
|
||||
modulesMap[t.id] = {};
|
||||
}
|
||||
} catch (e) {
|
||||
modulesMap[t.id] = {};
|
||||
}
|
||||
}));
|
||||
|
||||
renderTenantsTable(tenants, modulesMap);
|
||||
} catch (e) {
|
||||
tbody.innerHTML = '<tr><td colspan="6" style="text-align:center; color:#ef4444; padding:2rem;">' + e.message + '</td></tr>';
|
||||
}
|
||||
}
|
||||
|
||||
function renderTenantsTable(tenants, modulesMap) {
|
||||
var tbody = document.getElementById('tenantsTable');
|
||||
tbody.innerHTML = tenants.map(function(t) {
|
||||
var mods = modulesMap[t.id] || {};
|
||||
function toggleBtn(tenantId, key, enabled) {
|
||||
var label = enabled ? 'Activado' : 'Desactivado';
|
||||
var cls = enabled ? 'btn-primary' : 'btn-secondary';
|
||||
return '<button class="btn ' + cls + '" style="font-size:0.75rem; padding:3px 10px;" ' +
|
||||
'onclick="toggleTenantModule(' + tenantId + ', \'' + key + '\', ' + enabled + ')">' + label + '</button>';
|
||||
}
|
||||
return '<tr>' +
|
||||
'<td>' + t.id + '</td>' +
|
||||
'<td>' + (t.name || '-') + '</td>' +
|
||||
'<td>' + toggleBtn(t.id, 'whatsapp_enabled', !!mods.whatsapp_enabled) + '</td>' +
|
||||
'<td>' + toggleBtn(t.id, 'marketplace_enabled', !!mods.marketplace_enabled) + '</td>' +
|
||||
'<td>' + toggleBtn(t.id, 'meli_enabled', !!mods.meli_enabled) + '</td>' +
|
||||
'<td><button class="btn btn-primary" style="font-size:0.75rem; padding:3px 10px;" onclick="loadTenants()">🔄 Recargar</button></td>' +
|
||||
'</tr>';
|
||||
}).join('');
|
||||
}
|
||||
|
||||
async function toggleTenantModule(tenantId, key, currentValue) {
|
||||
var token = localStorage.getItem('access_token');
|
||||
var moduleNames = {
|
||||
'whatsapp_enabled': 'WhatsApp',
|
||||
'marketplace_enabled': 'Marketplace',
|
||||
'meli_enabled': 'MercadoLibre'
|
||||
};
|
||||
var action = currentValue ? 'desactivar' : 'activar';
|
||||
if (!confirm('¿Seguro que deseas ' + action + ' ' + moduleNames[key] + ' para el tenant #' + tenantId + '?')) return;
|
||||
|
||||
try {
|
||||
var payload = {};
|
||||
payload[key] = !currentValue;
|
||||
var res = await fetch('/api/admin/tenants/' + tenantId + '/modules', {
|
||||
method: 'PUT',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': 'Bearer ' + token
|
||||
},
|
||||
body: JSON.stringify(payload)
|
||||
});
|
||||
if (!res.ok) {
|
||||
var err = await res.json();
|
||||
throw new Error(err.error || 'Error al actualizar módulo');
|
||||
}
|
||||
showAlert(moduleNames[key] + ' ' + (currentValue ? 'desactivado' : 'activado') + ' para tenant #' + tenantId);
|
||||
loadTenants();
|
||||
} catch (e) {
|
||||
showAlert(e.message, 'error');
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user