Actualizar configuracion.html

This commit is contained in:
2026-02-11 22:46:59 +00:00
parent aeed3b1336
commit 0723577f68

View File

@@ -50,40 +50,20 @@
<div id="view-templates" class="tab-content h-full fade-in flex flex-col md:flex-row gap-6">
<div class="w-full md:w-1/3 bg-white rounded-xl shadow border border-gray-100 overflow-hidden flex flex-col">
<div class="p-4 bg-gray-50 border-b border-gray-200 font-bold text-gray-700 text-sm uppercase tracking-wide">
Tipos de Mensaje
</div>
<div class="p-4 bg-gray-50 border-b border-gray-200 font-bold text-gray-700 text-sm uppercase tracking-wide">Tipos de Mensaje</div>
<div class="flex-1 overflow-y-auto p-2 space-y-1">
<button onclick="selectTemplate('welcome', this)" class="tpl-btn w-full text-left p-3 rounded-lg hover:bg-blue-50 text-sm font-medium text-gray-600 transition-colors flex items-center gap-3 group">
<span class="bg-blue-100 text-blue-600 p-1.5 rounded-md group-hover:bg-blue-200 transition"><i data-lucide="hand" class="w-4 h-4"></i></span> Bienvenida / Alta
</button>
<button onclick="selectTemplate('no_contact', this)" class="tpl-btn w-full text-left p-3 rounded-lg hover:bg-blue-50 text-sm font-medium text-gray-600 transition-colors flex items-center gap-3 group">
<span class="bg-orange-100 text-orange-600 p-1.5 rounded-md group-hover:bg-orange-200 transition"><i data-lucide="phone-off" class="w-4 h-4"></i></span> Cliente No Localizado
</button>
<button onclick="selectTemplate('appointment', this)" class="tpl-btn w-full text-left p-3 rounded-lg hover:bg-blue-50 text-sm font-medium text-gray-600 transition-colors flex items-center gap-3 group">
<span class="bg-green-100 text-green-600 p-1.5 rounded-md group-hover:bg-green-200 transition"><i data-lucide="calendar-check" class="w-4 h-4"></i></span> Cita Creada
</button>
<button onclick="selectTemplate('update', this)" class="tpl-btn w-full text-left p-3 rounded-lg hover:bg-blue-50 text-sm font-medium text-gray-600 transition-colors flex items-center gap-3 group">
<span class="bg-purple-100 text-purple-600 p-1.5 rounded-md group-hover:bg-purple-200 transition"><i data-lucide="refresh-cw" class="w-4 h-4"></i></span> Modificación de Servicio
</button>
<button onclick="selectTemplate('on_way', this)" class="tpl-btn w-full text-left p-3 rounded-lg hover:bg-blue-50 text-sm font-medium text-gray-600 transition-colors flex items-center gap-3 group">
<span class="bg-teal-100 text-teal-600 p-1.5 rounded-md group-hover:bg-teal-200 transition"><i data-lucide="truck" class="w-4 h-4"></i></span> Técnico de Camino
</button>
<button onclick="selectTemplate('survey', this)" class="tpl-btn w-full text-left p-3 rounded-lg hover:bg-blue-50 text-sm font-medium text-gray-600 transition-colors flex items-center gap-3 group">
<span class="bg-yellow-100 text-yellow-600 p-1.5 rounded-md group-hover:bg-yellow-200 transition"><i data-lucide="star" class="w-4 h-4"></i></span> Encuesta de Calidad
</button>
<button onclick="selectTemplate('welcome', this)" class="tpl-btn w-full text-left p-3 rounded-lg hover:bg-blue-50 text-sm font-medium text-gray-600 transition-colors flex items-center gap-3 group"><span class="bg-blue-100 text-blue-600 p-1.5 rounded-md group-hover:bg-blue-200 transition"><i data-lucide="hand" class="w-4 h-4"></i></span> Bienvenida / Alta</button>
<button onclick="selectTemplate('no_contact', this)" class="tpl-btn w-full text-left p-3 rounded-lg hover:bg-blue-50 text-sm font-medium text-gray-600 transition-colors flex items-center gap-3 group"><span class="bg-orange-100 text-orange-600 p-1.5 rounded-md group-hover:bg-orange-200 transition"><i data-lucide="phone-off" class="w-4 h-4"></i></span> Cliente No Localizado</button>
<button onclick="selectTemplate('appointment', this)" class="tpl-btn w-full text-left p-3 rounded-lg hover:bg-blue-50 text-sm font-medium text-gray-600 transition-colors flex items-center gap-3 group"><span class="bg-green-100 text-green-600 p-1.5 rounded-md group-hover:bg-green-200 transition"><i data-lucide="calendar-check" class="w-4 h-4"></i></span> Cita Creada</button>
<button onclick="selectTemplate('update', this)" class="tpl-btn w-full text-left p-3 rounded-lg hover:bg-blue-50 text-sm font-medium text-gray-600 transition-colors flex items-center gap-3 group"><span class="bg-purple-100 text-purple-600 p-1.5 rounded-md group-hover:bg-purple-200 transition"><i data-lucide="refresh-cw" class="w-4 h-4"></i></span> Modificación de Servicio</button>
<button onclick="selectTemplate('on_way', this)" class="tpl-btn w-full text-left p-3 rounded-lg hover:bg-blue-50 text-sm font-medium text-gray-600 transition-colors flex items-center gap-3 group"><span class="bg-teal-100 text-teal-600 p-1.5 rounded-md group-hover:bg-teal-200 transition"><i data-lucide="truck" class="w-4 h-4"></i></span> Técnico de Camino</button>
<button onclick="selectTemplate('survey', this)" class="tpl-btn w-full text-left p-3 rounded-lg hover:bg-blue-50 text-sm font-medium text-gray-600 transition-colors flex items-center gap-3 group"><span class="bg-yellow-100 text-yellow-600 p-1.5 rounded-md group-hover:bg-yellow-200 transition"><i data-lucide="star" class="w-4 h-4"></i></span> Encuesta de Calidad</button>
</div>
</div>
<div class="flex-1 bg-white rounded-xl shadow border border-gray-100 flex flex-col overflow-hidden">
<div class="p-4 border-b bg-gray-50 flex justify-between items-center shrink-0">
<div>
<span class="block font-bold text-gray-800" id="editorTitle">Selecciona una plantilla</span>
<span class="text-xs text-gray-500">Edita el mensaje que se enviará por WhatsApp/Email</span>
</div>
<button onclick="saveTemplate()" class="bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 rounded-lg text-sm font-bold shadow-lg transition-all transform active:scale-95 flex items-center gap-2">
<i data-lucide="save" class="w-4 h-4"></i> Guardar
</button>
<div><span class="block font-bold text-gray-800" id="editorTitle">Selecciona una plantilla</span><span class="text-xs text-gray-500">Edita el mensaje que se enviará por WhatsApp/Email</span></div>
<button onclick="saveTemplate()" class="bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 rounded-lg text-sm font-bold shadow-lg transition-all transform active:scale-95 flex items-center gap-2"><i data-lucide="save" class="w-4 h-4"></i> Guardar</button>
</div>
<div class="p-3 border-b bg-gray-50/50 flex flex-wrap gap-2 items-center">
<span class="text-[10px] font-bold text-gray-400 uppercase tracking-wide mr-1">Variables:</span>
@@ -94,55 +74,33 @@
<button onclick="insertVar('{{COMPANIA}}')" class="var-btn">{{COMPANIA}}</button>
<button onclick="insertVar('{{REFERENCIA}}')" class="var-btn">{{REFERENCIA}}</button>
</div>
<textarea id="tplContent" class="flex-1 p-6 outline-none resize-none text-sm leading-relaxed text-gray-700 font-sans" placeholder="Selecciona un tipo de mensaje..."></textarea>
<textarea id="tplContent" class="flex-1 p-6 outline-none resize-none text-sm leading-relaxed text-gray-700 font-sans" placeholder="Selecciona un tipo de mensaje a la izquierda..."></textarea>
</div>
</div>
<div id="view-whatsapp" class="tab-content hidden h-full fade-in">
<div class="max-w-4xl mx-auto grid grid-cols-1 md:grid-cols-2 gap-8">
<div class="max-w-2xl mx-auto mt-10">
<div class="bg-white rounded-xl shadow-lg border border-gray-100 p-8 flex flex-col items-center text-center">
<div class="w-16 h-16 bg-blue-50 rounded-full flex items-center justify-center mb-6">
<i data-lucide="smartphone" class="w-8 h-8 text-blue-600"></i>
</div>
<div class="bg-white rounded-xl shadow border border-gray-100 p-6">
<h3 class="text-lg font-bold text-gray-800 mb-4 flex items-center gap-2">
<i data-lucide="activity" class="text-blue-600"></i> Estado de Conexión
</h3>
<h2 class="text-2xl font-bold text-gray-800 mb-2">Conexión con WhatsApp</h2>
<p class="text-gray-500 mb-8 max-w-md">Escanea el código QR para vincular tu número de empresa. Esto permitirá enviar notificaciones automáticas.</p>
<div id="waStatusContainer" class="flex flex-col items-center justify-center p-6 bg-gray-50 rounded-lg border border-gray-200 min-h-[200px]">
<div id="waStatusContainer" class="w-full flex flex-col items-center justify-center min-h-[250px] bg-gray-50 rounded-xl border-2 border-dashed border-gray-200 p-6 mb-6">
<div class="animate-pulse flex flex-col items-center">
<div class="w-12 h-12 bg-gray-200 rounded-full mb-3"></div>
<span class="text-gray-400 text-sm">Comprobando estado...</span>
<div class="w-10 h-10 border-4 border-blue-200 border-t-blue-600 rounded-full animate-spin mb-4"></div>
<span class="text-sm font-bold text-gray-400">Iniciando instancia segura...</span>
</div>
</div>
<button onclick="checkWhatsappStatus()" class="mt-4 w-full bg-white border border-gray-300 text-gray-700 font-bold py-2 rounded-lg hover:bg-gray-50 transition shadow-sm flex items-center justify-center gap-2">
<button onclick="checkWhatsappStatus()" class="bg-slate-800 hover:bg-slate-700 text-white font-bold py-3 px-8 rounded-xl transition shadow-lg flex items-center gap-2">
<i data-lucide="refresh-cw" class="w-4 h-4"></i> Actualizar Estado
</button>
</div>
<div class="bg-white rounded-xl shadow border border-gray-100 p-6">
<h3 class="text-lg font-bold text-gray-800 mb-4 flex items-center gap-2">
<i data-lucide="settings-2" class="text-gray-600"></i> Configuración API
</h3>
<p class="text-xs text-gray-500 mb-4">Introduce los datos de tu instancia de Evolution API.</p>
<div class="space-y-4">
<div>
<label class="block text-xs font-bold text-gray-600 mb-1">URL Base (Evolution API)</label>
<input type="url" id="waUrl" class="w-full border rounded-lg px-3 py-2 text-sm focus:border-blue-500 outline-none" placeholder="https://api.midominio.com">
<p class="text-[10px] text-gray-400 mt-6">Instancia segura gestionada automáticamente por el servidor.</p>
</div>
<div>
<label class="block text-xs font-bold text-gray-600 mb-1">API Key (Global)</label>
<input type="password" id="waKey" class="w-full border rounded-lg px-3 py-2 text-sm focus:border-blue-500 outline-none" placeholder="sk-...">
</div>
<div>
<label class="block text-xs font-bold text-gray-600 mb-1">Nombre de Instancia</label>
<input type="text" id="waInstance" class="w-full border rounded-lg px-3 py-2 text-sm focus:border-blue-500 outline-none" placeholder="IntegraRepara">
</div>
<button onclick="saveWhatsappConfig()" class="w-full bg-slate-800 text-white font-bold py-2 rounded-lg hover:bg-slate-700 transition">
Guardar Configuración
</button>
</div>
</div>
</div>
</div>
@@ -193,7 +151,6 @@
if (!localStorage.getItem("token")) window.location.href = "index.html";
showTab('templates');
loadTemplates();
loadWhatsappConfig(); // Cargar config si existe
});
function showTab(tabId) {
@@ -212,105 +169,62 @@
if(tabId === 'whatsapp') { checkWhatsappStatus(); }
}
// --- WHATSAPP CONFIG & STATUS ---
function loadWhatsappConfig() {
// Por ahora usamos localStorage, idealmente vendría del backend
const conf = JSON.parse(localStorage.getItem('wa_config') || '{}');
if(conf.url) document.getElementById('waUrl').value = conf.url;
if(conf.key) document.getElementById('waKey').value = conf.key;
if(conf.instance) document.getElementById('waInstance').value = conf.instance;
}
function saveWhatsappConfig() {
const url = document.getElementById('waUrl').value.replace(/\/$/, ""); // Quitar slash final
const key = document.getElementById('waKey').value;
const instance = document.getElementById('waInstance').value;
if(!url || !key || !instance) { showToast("Rellena todos los campos", true); return; }
localStorage.setItem('wa_config', JSON.stringify({ url, key, instance }));
showToast("Configuración guardada");
checkWhatsappStatus();
}
// --- WHATSAPP STATUS (AUTOMÁTICO) ---
async function checkWhatsappStatus() {
const conf = JSON.parse(localStorage.getItem('wa_config') || '{}');
const container = document.getElementById('waStatusContainer');
if(!conf.url || !conf.key || !conf.instance) {
container.innerHTML = `
<div class="text-center text-gray-400">
<i data-lucide="settings" class="w-10 h-10 mx-auto mb-2 text-gray-300"></i>
<p class="text-sm">Configura la API primero</p>
</div>`;
lucide.createIcons();
return;
}
container.innerHTML = `
<div class="flex flex-col items-center animate-pulse">
<i data-lucide="loader-2" class="w-8 h-8 text-blue-500 animate-spin mb-2"></i>
<span class="text-sm text-blue-600 font-medium">Conectando con Evolution API...</span>
<i data-lucide="loader-2" class="w-8 h-8 text-blue-500 animate-spin mb-3"></i>
<span class="text-sm text-blue-600 font-medium">Verificando instancia...</span>
</div>`;
lucide.createIcons();
try {
// 1. Verificar estado de la instancia
const res = await fetch(`${conf.url}/instance/connectionState/${conf.instance}`, {
headers: { "apikey": conf.key }
// Llamamos a NUESTRO backend, que gestiona todo con Evolution
const res = await fetch(`${API_URL}/whatsapp/status`, {
headers: { "Authorization": `Bearer ${localStorage.getItem("token")}` }
});
if(!res.ok) throw new Error("Error al conectar");
const data = await res.json();
const state = data.instance?.state || "close";
if (state === "open") {
if (!data.ok) throw new Error(data.error || "Error desconocido");
if (data.state === "open") {
container.innerHTML = `
<div class="flex flex-col items-center">
<div class="w-16 h-16 bg-green-100 rounded-full flex items-center justify-center mb-3">
<i data-lucide="check" class="w-8 h-8 text-green-600"></i>
<div class="w-20 h-20 bg-green-100 rounded-full flex items-center justify-center mb-4 shadow-sm border border-green-200">
<i data-lucide="check" class="w-10 h-10 text-green-600"></i>
</div>
<h4 class="text-lg font-bold text-green-700">Conectado</h4>
<p class="text-xs text-green-600 mt-1">Listo para enviar mensajes</p>
<h4 class="text-xl font-bold text-green-700">Conectado</h4>
<p class="text-sm text-green-600 mt-1 font-medium">Instancia: ${data.instanceName}</p>
</div>`;
} else {
// Si no está conectado, intentamos obtener el QR
// Nota: En Evolution v2 el endpoint de QR puede variar, aquí asumo el estándar
} else if (data.qr) {
container.innerHTML = `
<div class="flex flex-col items-center text-center">
<div class="w-16 h-16 bg-orange-100 rounded-full flex items-center justify-center mb-3">
<i data-lucide="qr-code" class="w-8 h-8 text-orange-600"></i>
</div>
<h4 class="text-lg font-bold text-orange-700">Desconectado</h4>
<p class="text-xs text-orange-600 mt-1 mb-3">Escanea el QR para vincular</p>
<div id="qrcode" class="bg-white p-2 border rounded"></div>
<div class="flex flex-col items-center w-full">
<div id="qrcode" class="bg-white p-3 border rounded-lg shadow-sm"></div>
<p class="text-xs text-orange-500 mt-4 font-bold animate-pulse">Esperando escaneo...</p>
</div>`;
// Fetch QR (esto depende de la versión exacta de Evolution API)
const resQr = await fetch(`${conf.url}/instance/connect/${conf.instance}`, { headers: { "apikey": conf.key } });
const dataQr = await resQr.json();
if(dataQr.code || dataQr.base64) {
// Si recibimos base64, lo mostramos como imagen
// Si recibimos string, usamos qrcode.js (si está cargado)
const qrCode = dataQr.code || dataQr.base64;
if(qrCode.startsWith('data:image')) {
document.getElementById('qrcode').innerHTML = `<img src="${qrCode}" class="w-40 h-40">`;
}
if(data.qr.startsWith('data:image')) {
document.getElementById('qrcode').innerHTML = `<img src="${data.qr}" class="w-48 h-48">`;
} else {
new QRCode(document.getElementById("qrcode"), { text: data.qr, width: 180, height: 180 });
}
} else {
container.innerHTML = `<p class="text-orange-500 font-bold">Iniciando... intenta de nuevo en unos segundos.</p>`;
}
} catch(e) {
container.innerHTML = `
<div class="text-center text-red-500">
<i data-lucide="alert-triangle" class="w-10 h-10 mx-auto mb-2"></i>
<p class="text-sm font-bold">Error de conexión</p>
<p class="text-xs mt-1 opacity-75">Revisa la URL y la API Key</p>
<div class="text-center text-red-500 p-4">
<i data-lucide="alert-triangle" class="w-10 h-10 mx-auto mb-2 opacity-80"></i>
<p class="font-bold">Error de conexión</p>
<p class="text-xs mt-1 bg-red-50 p-2 rounded">${e.message}</p>
</div>`;
}
lucide.createIcons();
}
// --- GESTIÓN DE PLANTILLAS (IGUAL QUE ANTES) ---
// --- GESTIÓN DE PLANTILLAS ---
async function loadTemplates() {
try {
const res = await fetch(`${API_URL}/templates`, { headers: { "Authorization": `Bearer ${localStorage.getItem("token")}` } });