diff --git a/configuracion.html b/configuracion.html
index b15a2dc..9f7a825 100644
--- a/configuracion.html
+++ b/configuracion.html
@@ -497,7 +497,6 @@
@@ -514,73 +513,102 @@
let cachedTemplates = {};
let currentTemplateType = null;
let localGuilds = [];
- let currentCompanyConfig = {}; // <--- ALMACENA TODA LA CONFIG GLOBAL
+ let globalConfig = null; // Para guardar la configuración de la base de datos
document.addEventListener("DOMContentLoaded", () => {
if (!localStorage.getItem("token")) window.location.href = "index.html";
showTab('templates');
loadTemplates();
loadWaSettings();
- loadGlobalCompanyConfig(); // <--- CARGA GLOBAL PARA EVITAR ERRORES
+ loadGlobalConfig(); // Cargar portal y app al iniciar
});
// ==========================================
- // CARGA GLOBAL DE DATOS (ANTI-ERROR 500)
+ // Carga y Guardado Unificado (Evita Error 500)
// ==========================================
- async function loadGlobalCompanyConfig() {
+ async function loadGlobalConfig() {
try {
const res = await fetch(`${API_URL}/config/company`, { headers: { "Authorization": `Bearer ${localStorage.getItem("token")}` } });
const data = await res.json();
+
if (data.ok && data.config) {
- currentCompanyConfig = data.config;
+ globalConfig = data.config;
- // Llenar datos Pestaña Portal
- document.getElementById('confCompanyName').value = data.config.full_name || "";
- if (data.config.company_logo) {
- document.getElementById('confLogoBase64').value = data.config.company_logo;
- document.getElementById('logoPreview').innerHTML = `
`;
+ // Rellenar Portal
+ document.getElementById('confCompanyName').value = globalConfig.full_name || "";
+ if (globalConfig.company_logo) {
+ document.getElementById('confLogoBase64').value = globalConfig.company_logo;
+ document.getElementById('logoPreview').innerHTML = `
`;
+ }
+ if (globalConfig.portal_settings) {
+ const s = globalConfig.portal_settings;
+ if(s.m_start) document.getElementById('mStart').value = s.m_start;
+ if(s.m_end) document.getElementById('mEnd').value = s.m_end;
+ if(s.a_start) document.getElementById('aStart').value = s.a_start;
+ if(s.a_end) document.getElementById('aEnd').value = s.a_end;
+ }
+
+ // Rellenar App Operario (si existe en la BD)
+ if (globalConfig.app_settings) {
+ const apps = globalConfig.app_settings;
+ document.getElementById('color-primary').value = apps.primary || "#2563EB";
+ document.getElementById('color-primary-hex').value = apps.primary || "#2563EB";
+ document.getElementById('color-secondary').value = apps.secondary || "#F59E0B";
+ document.getElementById('color-secondary-hex').value = apps.secondary || "#F59E0B";
+ document.getElementById('color-bg').value = apps.bg || "#F4F7F9";
+ document.getElementById('color-bg-hex').value = apps.bg || "#F4F7F9";
+ updateAppPreview();
}
- const ps = data.config.portal_settings || {};
- if(ps.m_start) document.getElementById('mStart').value = ps.m_start;
- if(ps.m_end) document.getElementById('mEnd').value = ps.m_end;
- if(ps.a_start) document.getElementById('aStart').value = ps.a_start;
- if(ps.a_end) document.getElementById('aEnd').value = ps.a_end;
-
- // Llenar datos Pestaña App
- const apps = ps.app_settings || {};
- document.getElementById('color-primary').value = apps.primary || "#2563EB";
- document.getElementById('color-primary-hex').value = apps.primary || "#2563EB";
- document.getElementById('color-secondary').value = apps.secondary || "#F59E0B";
- document.getElementById('color-secondary-hex').value = apps.secondary || "#F59E0B";
- document.getElementById('color-bg').value = apps.bg || "#F4F7F9";
- document.getElementById('color-bg-hex').value = apps.bg || "#F4F7F9";
- updateAppPreview();
}
- } catch(e) { console.error("Error config global"); }
+ } catch (e) { console.error("Error cargando configuración global"); }
}
- // UNIFICADOR DE PAYLOAD (Evita enviar datos vacíos a la BD y crashear PostgreSQL)
- function getCompanyPayload() {
- const portalSettings = currentCompanyConfig.portal_settings || {};
-
- portalSettings.m_start = document.getElementById('mStart').value || "09:00";
- portalSettings.m_end = document.getElementById('mEnd').value || "14:00";
- portalSettings.a_start = document.getElementById('aStart').value || "16:00";
- portalSettings.a_end = document.getElementById('aEnd').value || "19:00";
+ async function saveConfigUnified(isPortal) {
+ let btnId = isPortal ? 'btnSavePortal' : 'btnSaveApp';
+ const btn = document.getElementById(btnId);
+ const original = btn.innerHTML;
+ btn.innerHTML = '
Guardando...';
+ lucide.createIcons();
- portalSettings.app_settings = {
- primary: document.getElementById('color-primary').value || "#2563EB",
- secondary: document.getElementById('color-secondary').value || "#F59E0B",
- bg: document.getElementById('color-bg').value || "#F4F7F9"
+ // Construir el objeto con TODO lo que espera el servidor
+ const payload = {
+ company_name: document.getElementById('confCompanyName').value || globalConfig?.full_name || "Mi Empresa",
+ company_logo: document.getElementById('confLogoBase64').value || globalConfig?.company_logo || "",
+ portal_settings: {
+ m_start: document.getElementById('mStart').value || "09:00",
+ m_end: document.getElementById('mEnd').value || "14:00",
+ a_start: document.getElementById('aStart').value || "16:00",
+ a_end: document.getElementById('aEnd').value || "19:00"
+ },
+ app_settings: {
+ primary: document.getElementById('color-primary').value || "#2563EB",
+ secondary: document.getElementById('color-secondary').value || "#F59E0B",
+ bg: document.getElementById('color-bg').value || "#F4F7F9"
+ }
};
- return {
- company_name: document.getElementById('confCompanyName').value || "",
- company_logo: document.getElementById('confLogoBase64').value || "",
- portal_settings: portalSettings
- };
+ try {
+ const res = await fetch(`${API_URL}/config/company`, {
+ method: 'POST',
+ headers: { "Content-Type": "application/json", "Authorization": `Bearer ${localStorage.getItem("token")}` },
+ body: JSON.stringify(payload)
+ });
+ const data = await res.json();
+
+ if (data.ok) {
+ showToast(isPortal ? "✅ Portal Guardado" : "✅ Colores de la App Actualizados");
+ if(document.getElementById("headerUserName")) document.getElementById("headerUserName").innerText = payload.company_name;
+ localStorage.setItem('app_theme', JSON.stringify(payload.app_settings)); // Guardar en caché para la app móvil
+ } else {
+ showToast("❌ Error del servidor", true);
+ }
+ } catch (e) { showToast("Error de conexión", true); }
+ finally { btn.innerHTML = original; lucide.createIcons(); }
}
+ function savePortalConfig() { saveConfigUnified(true); }
+ function saveAppConfig() { saveConfigUnified(false); }
+
function showTab(tabId) {
document.querySelectorAll('.tab-content').forEach(el => el.classList.add('hidden'));
document.getElementById(`view-${tabId}`).classList.remove('hidden');
@@ -601,21 +629,13 @@
}
// ==========================================
- // LÓGICA PORTAL OPERARIO (COLORES)
+ // LÓGICA PORTAL OPERARIO (PREVIEW COLORES)
// ==========================================
['primary', 'secondary', 'bg'].forEach(type => {
const picker = document.getElementById(`color-${type}`);
const text = document.getElementById(`color-${type}-hex`);
- picker.addEventListener('input', (e) => {
- text.value = e.target.value.toUpperCase();
- updateAppPreview();
- });
- text.addEventListener('input', (e) => {
- if(/^#[0-9A-F]{6}$/i.test(e.target.value)) {
- picker.value = e.target.value;
- updateAppPreview();
- }
- });
+ picker.addEventListener('input', (e) => { text.value = e.target.value.toUpperCase(); updateAppPreview(); });
+ text.addEventListener('input', (e) => { if(/^#[0-9A-F]{6}$/i.test(e.target.value)) { picker.value = e.target.value; updateAppPreview(); } });
});
function updateAppPreview() {
@@ -628,34 +648,6 @@
document.getElementById('app-preview').style.backgroundColor = b;
}
- async function saveAppConfig() {
- const btn = document.getElementById('btnSaveApp');
- const original = btn.innerHTML;
- btn.innerHTML = '
Aplicando...';
- lucide.createIcons();
-
- const payload = getCompanyPayload();
-
- try {
- const res = await fetch(`${API_URL}/config/company`, {
- method: 'POST',
- headers: { "Content-Type": "application/json", "Authorization": `Bearer ${localStorage.getItem("token")}` },
- body: JSON.stringify(payload)
- });
- const data = await res.json();
- if (data.ok) {
- showToast("✅ Colores de la App actualizados");
- localStorage.setItem('app_theme', JSON.stringify(payload.portal_settings.app_settings));
- } else {
- showToast("❌ Error al guardar", true);
- }
- } catch (e) { showToast("Error de conexión", true); }
- finally { btn.innerHTML = original; lucide.createIcons(); }
- }
-
- // ==========================================
- // LÓGICA PORTAL CLIENTE
- // ==========================================
function encodeLogo(input) {
const file = input.files[0];
if (!file || file.size > 1024 * 1024) { alert("Máximo 1MB"); return; }
@@ -667,30 +659,51 @@
reader.readAsDataURL(file);
}
- async function savePortalConfig() {
- const btn = document.getElementById('btnSavePortal');
- const original = btn.innerHTML;
- btn.innerHTML = '
Guardando...';
- lucide.createIcons();
-
- const payload = getCompanyPayload();
-
+ // ==========================================
+ // LÓGICA WHATSAPP
+ // ==========================================
+ async function loadWaSettings() {
try {
- const res = await fetch(`${API_URL}/config/company`, {
- method: 'POST',
- headers: { "Content-Type": "application/json", "Authorization": `Bearer ${localStorage.getItem("token")}` },
- body: JSON.stringify(payload)
- });
+ const res = await fetch(`${API_URL}/whatsapp/settings`, { headers: { "Authorization": `Bearer ${localStorage.getItem("token")}` } });
const data = await res.json();
- if (data.ok) {
- showToast("✅ Configuración del Portal guardada");
- const nameEl = document.getElementById("headerUserName");
- if (nameEl && payload.company_name) nameEl.innerText = payload.company_name;
- } else {
- showToast("❌ Error al guardar", true);
- }
- } catch (e) { showToast("Error de conexión", true); }
- finally { btn.innerHTML = original; lucide.createIcons(); }
+ const s = data.settings || {};
+ document.getElementById('cfg_delay').checked = s.wa_delay_enabled !== false;
+ document.getElementById('cfg_evt_welcome').checked = s.wa_evt_welcome || false;
+ document.getElementById('cfg_evt_assigned').checked = s.wa_evt_assigned || false;
+ document.getElementById('cfg_evt_date').checked = s.wa_evt_date || false;
+ document.getElementById('cfg_evt_onway').checked = s.wa_evt_onway || false;
+ document.getElementById('cfg_evt_finished').checked = s.wa_evt_finished || false;
+ document.getElementById('cfg_evt_survey').checked = s.wa_evt_survey || false;
+ } catch(e) {}
+ }
+
+ async function saveWaSettings() {
+ const settings = {
+ wa_delay_enabled: document.getElementById('cfg_delay').checked,
+ wa_evt_welcome: document.getElementById('cfg_evt_welcome').checked,
+ wa_evt_assigned: document.getElementById('cfg_evt_assigned').checked,
+ wa_evt_date: document.getElementById('cfg_evt_date').checked,
+ wa_evt_onway: document.getElementById('cfg_evt_onway').checked,
+ wa_evt_finished: document.getElementById('cfg_evt_finished').checked,
+ wa_evt_survey: document.getElementById('cfg_evt_survey').checked
+ };
+ try {
+ const res = await fetch(`${API_URL}/whatsapp/settings`, { method: 'POST', headers: { "Content-Type": "application/json", "Authorization": `Bearer ${localStorage.getItem("token")}` }, body: JSON.stringify(settings) });
+ if (res.ok) showToast("✅ Ajustes WhatsApp guardados");
+ } catch(e) {}
+ }
+
+ async function checkWhatsappStatus() {
+ const container = document.getElementById('waStatusContainer');
+ container.innerHTML = `
`;
+ try {
+ const res = await fetch(`${API_URL}/whatsapp/status`, { headers: { "Authorization": `Bearer ${localStorage.getItem("token")}` } });
+ const data = await res.json();
+ if (data.state === "open") container.innerHTML = `
Conectado
`;
+ else if (data.qr) container.innerHTML = `
`;
+ else container.innerHTML = `
Iniciando...
`;
+ lucide.createIcons();
+ } catch(e) { container.innerHTML = `
Error servidor
`; }
}
// ==========================================
@@ -736,7 +749,6 @@
});
lucide.createIcons();
} catch (e) {
- console.error("Error cargando reglas IA:", e);
list.innerHTML = '
Error al cargar las reglas de IA.
';
}
}
@@ -762,69 +774,39 @@
body: JSON.stringify({ keywords: keywordsArray })
});
if (res.ok) {
- showToast("✅ Reglas de IA guardadas correctamente.");
+ showToast("✅ Reglas de IA guardadas.");
closeIaModal();
loadIaRules();
- } else { showToast("❌ Error al guardar las reglas.", true); }
+ } else { showToast("❌ Error al guardar reglas.", true); }
} catch (e) { showToast("❌ Error de conexión.", true); }
}
- async function loadWaSettings() {
- try {
- const res = await fetch(`${API_URL}/whatsapp/settings`, { headers: { "Authorization": `Bearer ${localStorage.getItem("token")}` } });
- const data = await res.json();
- const s = data.settings || {};
- document.getElementById('cfg_delay').checked = s.wa_delay_enabled !== false;
- document.getElementById('cfg_evt_welcome').checked = s.wa_evt_welcome || false;
- document.getElementById('cfg_evt_assigned').checked = s.wa_evt_assigned || false;
- document.getElementById('cfg_evt_date').checked = s.wa_evt_date || false;
- document.getElementById('cfg_evt_onway').checked = s.wa_evt_onway || false;
- document.getElementById('cfg_evt_finished').checked = s.wa_evt_finished || false;
- document.getElementById('cfg_evt_survey').checked = s.wa_evt_survey || false;
- } catch(e) {}
- }
-
- async function saveWaSettings() {
- const settings = {
- wa_delay_enabled: document.getElementById('cfg_delay').checked,
- wa_evt_welcome: document.getElementById('cfg_evt_welcome').checked,
- wa_evt_assigned: document.getElementById('cfg_evt_assigned').checked,
- wa_evt_date: document.getElementById('cfg_evt_date').checked,
- wa_evt_onway: document.getElementById('cfg_evt_onway').checked,
- wa_evt_finished: document.getElementById('cfg_evt_finished').checked,
- wa_evt_survey: document.getElementById('cfg_evt_survey').checked
- };
- try {
- const res = await fetch(`${API_URL}/whatsapp/settings`, { method: 'POST', headers: { "Content-Type": "application/json", "Authorization": `Bearer ${localStorage.getItem("token")}` }, body: JSON.stringify(settings) });
- if (res.ok) showToast("✅ Ajustes WhatsApp guardados");
- } catch(e) {}
- }
-
- async function checkWhatsappStatus() {
- const container = document.getElementById('waStatusContainer');
- container.innerHTML = `
`;
- try {
- const res = await fetch(`${API_URL}/whatsapp/status`, { headers: { "Authorization": `Bearer ${localStorage.getItem("token")}` } });
- const data = await res.json();
- if (data.state === "open") container.innerHTML = `
Conectado
`;
- else if (data.qr) container.innerHTML = `
`;
- else container.innerHTML = `
Iniciando...
`;
- lucide.createIcons();
- } catch(e) { container.innerHTML = `
Error servidor
`; }
- }
-
+ // ==========================================
+ // LÓGICA PLANTILLAS
+ // ==========================================
async function loadTemplates() {
try {
const res = await fetch(`${API_URL}/templates`, { headers: { "Authorization": `Bearer ${localStorage.getItem("token")}` } });
const data = await res.json();
- if(data.ok) { data.templates.forEach(t => { cachedTemplates[t.type] = t.content; }); if (!currentTemplateType) document.querySelector('.tpl-btn').click(); }
+ if(data.ok) {
+ data.templates.forEach(t => { cachedTemplates[t.type] = t.content; });
+ if (!currentTemplateType) document.querySelector('.tpl-btn').click();
+ }
} catch(e) {}
}
function selectTemplate(type, btn) {
currentTemplateType = type;
- document.querySelectorAll('.tpl-btn').forEach(b => b.classList.remove('bg-blue-50', 'ring-1', 'ring-blue-200'));
+ document.querySelectorAll('.tpl-btn').forEach(b => {
+ b.classList.remove('bg-blue-50', 'ring-1', 'ring-blue-200');
+ const span = b.querySelector('span');
+ if (span.classList.contains('bg-blue-600')) span.classList.replace('bg-blue-600', 'bg-blue-100'), span.classList.replace('text-white', 'text-blue-600');
+ if (span.classList.contains('bg-orange-600')) span.classList.replace('bg-orange-600', 'bg-orange-100'), span.classList.replace('text-white', 'text-orange-600');
+ });
btn.classList.add('bg-blue-50', 'ring-1', 'ring-blue-200');
+ const activeSpan = btn.querySelector('span');
+ if (activeSpan.classList.contains('bg-blue-100')) activeSpan.classList.replace('bg-blue-100', 'bg-blue-600'), activeSpan.classList.replace('text-blue-600', 'text-white');
+ else if (activeSpan.classList.contains('bg-orange-100')) activeSpan.classList.replace('bg-orange-100', 'bg-orange-600'), activeSpan.classList.replace('text-orange-600', 'text-white');
document.getElementById('editorTitle').innerText = btn.innerText.trim();
document.getElementById('tplContent').value = cachedTemplates[type] || "";
}
@@ -843,6 +825,9 @@
showToast("Guardado");
}
+ // ==========================================
+ // LÓGICA OTROS Y PROVEEDORES
+ // ==========================================
async function loadCompanies() {
const res = await fetch(`${API_URL}/companies`, { headers: { "Authorization": `Bearer ${localStorage.getItem("token")}` } });
const data = await res.json();
@@ -850,13 +835,11 @@
data.companies.forEach(c => { list.innerHTML += `
${c.name}
`; });
lucide.createIcons();
}
-
async function addCompany() {
const name = document.getElementById('newCompanyInput').value;
await fetch(`${API_URL}/companies`, { method: 'POST', headers: { "Content-Type": "application/json", "Authorization": `Bearer ${localStorage.getItem("token")}` }, body: JSON.stringify({ name }) });
document.getElementById('newCompanyInput').value = ""; loadCompanies();
}
-
async function deleteCompany(id) { if(confirm("Borrar?")) { await fetch(`${API_URL}/companies/${id}`, { method: 'DELETE', headers: { "Authorization": `Bearer ${localStorage.getItem("token")}` } }); loadCompanies(); } }
async function loadStatusesConfig() {
@@ -866,23 +849,24 @@
data.statuses.forEach(s => { list.innerHTML += `
`; });
lucide.createIcons();
}
-
async function addStatus() {
- const name = document.getElementById('newStatusInput').value;
- const color = document.getElementById('newStatusColor').value;
+ const name = document.getElementById('newStatusInput').value, color = document.getElementById('newStatusColor').value;
await fetch(`${API_URL}/statuses`, { method: 'POST', headers: { "Content-Type": "application/json", "Authorization": `Bearer ${localStorage.getItem("token")}` }, body: JSON.stringify({ name, color }) });
document.getElementById('newStatusInput').value = ""; loadStatusesConfig();
}
-
async function deleteStatus(id) { if(confirm("Borrar?")) { await fetch(`${API_URL}/statuses/${id}`, { method: 'DELETE', headers: { "Authorization": `Bearer ${localStorage.getItem("token")}` } }); loadStatusesConfig(); } }
async function loadProviderCredentials() {
const res = await fetch(`${API_URL}/providers/credentials`, { headers: { "Authorization": `Bearer ${localStorage.getItem("token")}` } });
const data = await res.json();
- data.credentials.forEach(c => {
- const inp = document.getElementById(`user_${c.provider.toLowerCase()}`);
- if(inp) inp.value = c.username;
- });
+ data.credentials.forEach(c => { const inp = document.getElementById(`user_${c.provider.toLowerCase()}`); if(inp) inp.value = c.username; });
+ }
+ async function saveProviderCreds(event, provider) {
+ event.preventDefault();
+ const username = document.getElementById(`user_${provider}`).value, password = document.getElementById(`pass_${provider}`).value;
+ if(!username || !password) return showToast("Faltan datos", true);
+ await fetch(`${API_URL}/providers/credentials`, { method: 'POST', headers: { "Content-Type": "application/json", "Authorization": `Bearer ${localStorage.getItem("token")}` }, body: JSON.stringify({ provider, username, password }) });
+ showToast(`✅ Acceso a ${provider} guardado`);
}
function showToast(msg, isError = false) {
@@ -891,8 +875,6 @@
m.innerText = msg;
setTimeout(() => t.className += " opacity-0 translate-y-20", 3000);
}
-
- function logout() { localStorage.clear(); window.location.href = "index.html"; }